From 588569a154bab91efbef1d445ad40ec9c6ac1857 Mon Sep 17 00:00:00 2001 From: matthewpeterkort Date: Mon, 10 Aug 2026 16:56:10 -0700 Subject: [PATCH 01/15] add support for versioned recipes, more robust dataframing --- docs/DATAFRAMER_RECIPES.md | 7 + docs/DATAFRAMER_RECIPE_REFERENCE.md | 26 + .../graphql/graph/executor/root_.generated.go | 174 ++++ .../graph/executor/schema.generated.go | 821 +++++++++++++++++- generated/graphql/graph/model/models.go | 21 + internal/api/bulk/load/generation_route.go | 28 +- .../api/bulk/load/generation_route_test.go | 33 + internal/api/bulk/load/handler.go | 2 + internal/api/bulk/load/service.go | 114 ++- internal/api/bulk/load/service_test.go | 254 ++++++ .../graphql/graph/materialization/output.go | 26 +- .../graphql/graph/materialization/service.go | 40 + .../graphql/graph/query/recipe_discovery.go | 7 + .../graph/resolver/recipe_control_graphql.go | 5 + .../graph/resolver/recipe_execution_reader.go | 2 +- .../graph/resolver/recipe_revision_model.go | 17 + .../api/graphql/graph/resolver/resolver.go | 7 +- .../graph/resolver/schema.resolvers.go | 63 ++ .../api/graphql/graph/schema/schema.graphqls | 25 + internal/api/http/recipe_execution.go | 86 ++ internal/catalog/arango/store.go | 34 + internal/catalog/arango/store_test.go | 3 +- internal/catalog/cache.go | 6 + internal/catalog/cache_test.go | 20 + internal/catalog/types.go | 93 +- internal/catalog/write_profiler.go | 135 ++- internal/catalog/write_profiler_test.go | 26 + .../compiler/ir/physical_validation_expr.go | 3 +- .../compiler/lower/recipe_compile.go | 31 +- .../compiler/lower/recipe_dynamic_columns.go | 28 +- .../compiler/lower/recipe_output_test.go | 93 +- .../dataframe/compiler/lower/recipe_schema.go | 79 +- .../lower/recipe_semantic_path_test.go | 20 + .../dataframe/compiler/render/aql/calls.go | 6 + .../expression/expression_checking.go | 6 + internal/dataframe/publication/bundle.go | 8 +- .../publication/clickhouse/bundle_store.go | 163 ++++ .../clickhouse/clickhouse_bundle_test.go | 146 ++++ .../publication/clickhouse/target.go | 10 + internal/dataframe/publication/types.go | 13 +- internal/dataframe/published/federation.go | 31 + internal/dataframe/published/read.go | 9 +- internal/dataframe/published/read_test.go | 2 +- internal/dataframe/published/types.go | 10 +- internal/dataframe/recipe/canonical.go | 3 + internal/dataframe/recipe/document_types.go | 38 +- .../dataframe/recipe/document_validation.go | 9 +- .../dataframe/recipe/dynamic_validation.go | 40 + internal/dataframe/recipe/engine/engine.go | 30 +- internal/dataframe/recipe/engine/postquery.go | 40 +- .../dataframe/recipe/engine/postquery_test.go | 64 +- .../dataframe/recipe/exec/arango/revisions.go | 150 ++++ .../recipe/exec/arango/revisions_test.go | 83 ++ internal/dataframe/recipe/json_encoding.go | 1 + internal/dataframe/recipe/revisions.go | 101 +++ internal/dataframe/recipe/revisions_test.go | 28 + internal/dataframe/recipe/schema/discovery.go | 32 +- .../recipe/schema/extension_columns.go | 159 ++++ internal/dataframe/recipe/schema/resolve.go | 32 +- .../dataframe/recipe/schema/resolve_test.go | 58 ++ .../dataframe/semantic/recipe_plan_output.go | 88 +- .../dataframe/semantic/recipe_plan_types.go | 24 +- .../dataframe/semantic/recipe_projection.go | 8 +- .../dataframe/semantic/recipe_traversal.go | 5 + internal/dataframe/semantic/resolved_plan.go | 9 +- internal/dataset/arango/manifest_lifecycle.go | 8 +- internal/dataset/validation.go | 1 + internal/ingest/generation_orchestration.go | 2 +- internal/ingest/load_options.go | 3 + internal/server/config_test.go | 6 +- internal/server/options.go | 8 + internal/server/recipe_discovery.go | 7 + internal/server/recipe_discovery_test.go | 13 + internal/server/recipe_publication.go | 55 +- internal/server/routes.go | 17 +- internal/server/routes_test.go | 24 +- internal/server/server.go | 18 +- 77 files changed, 3695 insertions(+), 202 deletions(-) create mode 100644 internal/api/bulk/load/service_test.go create mode 100644 internal/api/graphql/graph/resolver/recipe_revision_model.go create mode 100644 internal/api/http/recipe_execution.go create mode 100644 internal/dataframe/compiler/lower/recipe_semantic_path_test.go create mode 100644 internal/dataframe/recipe/exec/arango/revisions.go create mode 100644 internal/dataframe/recipe/exec/arango/revisions_test.go create mode 100644 internal/dataframe/recipe/revisions.go create mode 100644 internal/dataframe/recipe/revisions_test.go create mode 100644 internal/dataframe/recipe/schema/extension_columns.go diff --git a/docs/DATAFRAMER_RECIPES.md b/docs/DATAFRAMER_RECIPES.md index 0afe1dc7..1c8b2f5e 100644 --- a/docs/DATAFRAMER_RECIPES.md +++ b/docs/DATAFRAMER_RECIPES.md @@ -456,6 +456,13 @@ each traversal that needs it. ### Key/value families +Use `dynamicColumns` for identifiers and general key/value arrays. For +schema-aware FHIR extensions, prefer `extensionColumns` on an output or +traversal: it recursively discovers nested `Extension` URLs, freezes +URL-to-value mappings and logical types, and emits canonical JSON strings for +mixed or complex values. `maxColumns` is required; an explicit empty +`columnPrefix` preserves bare names such as `source_path` and `sha256`. + Use `dynamicColumns` for identifiers, extensions, and similar arrays whose key becomes part of the column name: diff --git a/docs/DATAFRAMER_RECIPE_REFERENCE.md b/docs/DATAFRAMER_RECIPE_REFERENCE.md index b3b0d71c..7f527a93 100644 --- a/docs/DATAFRAMER_RECIPE_REFERENCE.md +++ b/docs/DATAFRAMER_RECIPE_REFERENCE.md @@ -331,6 +331,32 @@ traversals attach context without changing the root output identity. ## Dynamic columns: controlled key/value flattening +### `extensionColumns`: typed URL-keyed Extension values + +For recipes that need a stable, loss-aware mapping of FHIR `Extension` +values, use `extensionColumns` on either an output or a traversal. `source` +must be a schema-valid repeated `Extension` selector and `maxColumns` is +required. Discovery walks nested `extension[]` arrays and freezes each URL's +normalized final segment (for example `source_path` and `sha256`). An explicit +empty `columnPrefix` publishes those names without a family prefix. + +When discovery observes one primitive `value[x]` kind for a URL, the resulting +column retains that nullable logical type. URLs with mixed or complex values +are represented as canonical JSON strings. The frozen URL, source path, value +selector, and logical type are included in the resolved schema digest. + +```json +{ + "name": "attachment", + "columnPrefix": "", + "source": {"select": "root.content[].attachment.extension[]"}, + "maxColumns": 16 +} +``` + +`dynamicColumns` remains available for general key/value arrays and retains +its existing behavior. + Use a dynamic column family when FHIR represents repeated key/value metadata and each known key should become its own column. This is the correct tool for identifiers, category coding, and attachment extensions. It is **not** a diff --git a/generated/graphql/graph/executor/root_.generated.go b/generated/graphql/graph/executor/root_.generated.go index 6a3dac48..46da61b0 100644 --- a/generated/graphql/graph/executor/root_.generated.go +++ b/generated/graphql/graph/executor/root_.generated.go @@ -601,6 +601,7 @@ type ComplexityRoot struct { Name func(childComplexity int) int Nullable func(childComplexity int) int Repeated func(childComplexity int) int + SemanticPath func(childComplexity int) int Sortable func(childComplexity int) int } @@ -659,6 +660,7 @@ type ComplexityRoot struct { Columns func(childComplexity int) int Completeness func(childComplexity int) int CreatedAt func(childComplexity int) int + DatasetGeneration func(childComplexity int) int Error func(childComplexity int) int ErrorCode func(childComplexity int) int ErrorRetryable func(childComplexity int) int @@ -666,6 +668,7 @@ type ComplexityRoot struct { ID func(childComplexity int) int IncludedProjectCount func(childComplexity int) int Name func(childComplexity int) int + ProjectID func(childComplexity int) int ProjectStatuses func(childComplexity int) int ReadyAt func(childComplexity int) int Revision func(childComplexity int) int @@ -752,6 +755,7 @@ type ComplexityRoot struct { } DataframeRecipeExecutionOutput struct { + Columns func(childComplexity int) int Error func(childComplexity int) int ErrorCode func(childComplexity int) int ErrorRetryable func(childComplexity int) int @@ -916,6 +920,15 @@ type ComplexityRoot struct { Rows func(childComplexity int) int } + DataframeRecipeRevision struct { + CreatedAt func(childComplexity int) int + Digest func(childComplexity int) int + Name func(childComplexity int) int + ParentDigest func(childComplexity int) int + ProjectID func(childComplexity int) int + Recipe func(childComplexity int) int + } + DataframeRecipeValidation struct { Name func(childComplexity int) int Outputs func(childComplexity int) int @@ -1928,6 +1941,7 @@ type ComplexityRoot struct { MaterializeDataframeRecipeBundle func(childComplexity int, input model.MaterializeDataframeRecipeInput) int PreviewDataframeRecipe func(childComplexity int, input model.PreviewDataframeRecipeInput) int PromoteDataframeContract func(childComplexity int, input model.PromoteDataframeContractInput) int + RegisterDataframeRecipeRevision func(childComplexity int, input model.RegisterDataframeRecipeRevisionInput) int RunDataframeRecipe func(childComplexity int, input model.RunDataframeRecipeInput) int RunFhirDataframe func(childComplexity int, input model.FhirDataframeInput, limit *int) int StartDataframeMaterialization func(childComplexity int, input model.StartDataframeMaterializationInput) int @@ -2421,6 +2435,8 @@ type ComplexityRoot struct { DataframeDatasets func(childComplexity int) int DataframeMaterialization func(childComplexity int, id string) int DataframeRecipeExecution func(childComplexity int, id string) int + DataframeRecipeRevision func(childComplexity int, projectID string, name string, digest string) int + DataframeRecipeRevisions func(childComplexity int, projectID string, name string) int DataframeRows func(childComplexity int, input model.DataframeRowsInput) int DiagnosticReport func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int DocumentReference func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int @@ -2441,6 +2457,7 @@ type ComplexityRoot struct { PractitionerRole func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int PreflightDataframeRecipe func(childComplexity int, input model.PreflightDataframeRecipeInput) int Procedure func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + ProjectDataframeDatasets func(childComplexity int, projectID string) int ResearchStudy func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int ResearchSubject func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int Specimen func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int @@ -5585,6 +5602,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.ComplexityRoot.DataframeColumn.Repeated(childComplexity), true + case "DataframeColumn.semanticPath": + if e.ComplexityRoot.DataframeColumn.SemanticPath == nil { + break + } + + return e.ComplexityRoot.DataframeColumn.SemanticPath(childComplexity), true case "DataframeColumn.sortable": if e.ComplexityRoot.DataframeColumn.Sortable == nil { break @@ -5831,6 +5854,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.ComplexityRoot.DataframeMaterialization.CreatedAt(childComplexity), true + case "DataframeMaterialization.datasetGeneration": + if e.ComplexityRoot.DataframeMaterialization.DatasetGeneration == nil { + break + } + + return e.ComplexityRoot.DataframeMaterialization.DatasetGeneration(childComplexity), true case "DataframeMaterialization.error": if e.ComplexityRoot.DataframeMaterialization.Error == nil { break @@ -5873,6 +5902,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.ComplexityRoot.DataframeMaterialization.Name(childComplexity), true + case "DataframeMaterialization.projectId": + if e.ComplexityRoot.DataframeMaterialization.ProjectID == nil { + break + } + + return e.ComplexityRoot.DataframeMaterialization.ProjectID(childComplexity), true case "DataframeMaterialization.projectStatuses": if e.ComplexityRoot.DataframeMaterialization.ProjectStatuses == nil { break @@ -6236,6 +6271,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.ComplexityRoot.DataframeRecipeExecution.TranslationVersion(childComplexity), true + case "DataframeRecipeExecutionOutput.columns": + if e.ComplexityRoot.DataframeRecipeExecutionOutput.Columns == nil { + break + } + + return e.ComplexityRoot.DataframeRecipeExecutionOutput.Columns(childComplexity), true case "DataframeRecipeExecutionOutput.error": if e.ComplexityRoot.DataframeRecipeExecutionOutput.Error == nil { break @@ -6869,6 +6910,43 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.ComplexityRoot.DataframeRecipeResultOutput.Rows(childComplexity), true + case "DataframeRecipeRevision.createdAt": + if e.ComplexityRoot.DataframeRecipeRevision.CreatedAt == nil { + break + } + + return e.ComplexityRoot.DataframeRecipeRevision.CreatedAt(childComplexity), true + case "DataframeRecipeRevision.digest": + if e.ComplexityRoot.DataframeRecipeRevision.Digest == nil { + break + } + + return e.ComplexityRoot.DataframeRecipeRevision.Digest(childComplexity), true + case "DataframeRecipeRevision.name": + if e.ComplexityRoot.DataframeRecipeRevision.Name == nil { + break + } + + return e.ComplexityRoot.DataframeRecipeRevision.Name(childComplexity), true + case "DataframeRecipeRevision.parentDigest": + if e.ComplexityRoot.DataframeRecipeRevision.ParentDigest == nil { + break + } + + return e.ComplexityRoot.DataframeRecipeRevision.ParentDigest(childComplexity), true + case "DataframeRecipeRevision.projectId": + if e.ComplexityRoot.DataframeRecipeRevision.ProjectID == nil { + break + } + + return e.ComplexityRoot.DataframeRecipeRevision.ProjectID(childComplexity), true + case "DataframeRecipeRevision.recipe": + if e.ComplexityRoot.DataframeRecipeRevision.Recipe == nil { + break + } + + return e.ComplexityRoot.DataframeRecipeRevision.Recipe(childComplexity), true + case "DataframeRecipeValidation.name": if e.ComplexityRoot.DataframeRecipeValidation.Name == nil { break @@ -11969,6 +12047,17 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.ComplexityRoot.Mutation.PromoteDataframeContract(childComplexity, args["input"].(model.PromoteDataframeContractInput)), true + case "Mutation.registerDataframeRecipeRevision": + if e.ComplexityRoot.Mutation.RegisterDataframeRecipeRevision == nil { + break + } + + args, err := ec.field_Mutation_registerDataframeRecipeRevision_args(ctx, rawArgs) + if err != nil { + return 0, false + } + + return e.ComplexityRoot.Mutation.RegisterDataframeRecipeRevision(childComplexity, args["input"].(model.RegisterDataframeRecipeRevisionInput)), true case "Mutation.runDataframeRecipe": if e.ComplexityRoot.Mutation.RunDataframeRecipe == nil { break @@ -14596,6 +14685,28 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.ComplexityRoot.Query.DataframeRecipeExecution(childComplexity, args["id"].(string)), true + case "Query.dataframeRecipeRevision": + if e.ComplexityRoot.Query.DataframeRecipeRevision == nil { + break + } + + args, err := ec.field_Query_dataframeRecipeRevision_args(ctx, rawArgs) + if err != nil { + return 0, false + } + + return e.ComplexityRoot.Query.DataframeRecipeRevision(childComplexity, args["projectId"].(string), args["name"].(string), args["digest"].(string)), true + case "Query.dataframeRecipeRevisions": + if e.ComplexityRoot.Query.DataframeRecipeRevisions == nil { + break + } + + args, err := ec.field_Query_dataframeRecipeRevisions_args(ctx, rawArgs) + if err != nil { + return 0, false + } + + return e.ComplexityRoot.Query.DataframeRecipeRevisions(childComplexity, args["projectId"].(string), args["name"].(string)), true case "Query.dataframeRows": if e.ComplexityRoot.Query.DataframeRows == nil { break @@ -14817,6 +14928,17 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.ComplexityRoot.Query.Procedure(childComplexity, args["project"].(string), args["filters"].([]*model.FhirFilterInput), args["limit"].(*int)), true + case "Query.projectDataframeDatasets": + if e.ComplexityRoot.Query.ProjectDataframeDatasets == nil { + break + } + + args, err := ec.field_Query_projectDataframeDatasets_args(ctx, rawArgs) + if err != nil { + return 0, false + } + + return e.ComplexityRoot.Query.ProjectDataframeDatasets(childComplexity, args["projectId"].(string)), true case "Query.ResearchStudy": if e.ComplexityRoot.Query.ResearchStudy == nil { break @@ -20068,6 +20190,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputPreflightDataframeRecipeInput, ec.unmarshalInputPreviewDataframeRecipeInput, ec.unmarshalInputPromoteDataframeContractInput, + ec.unmarshalInputRegisterDataframeRecipeRevisionInput, ec.unmarshalInputRunDataframeRecipeInput, ec.unmarshalInputStartDataframeMaterializationInput, ec.unmarshalInputValidateDataframeRecipeInput, @@ -20153,11 +20276,14 @@ var sources = []*ast.Source{ dataframeMaterialization(id: ID!): DataframeMaterialization dataframeDatasets: [DataframeMaterialization!]! + projectDataframeDatasets(projectId: String!): [DataframeMaterialization!]! dataframeDataset(input: DataframeDatasetInput!): DataframeMaterialization dataframeRows(input: DataframeRowsInput!): DataframeRowConnection! dataframeAggregate(input: DataframeAggregateInput!): DataframeAggregateResult! dataframeAggregations(input: DataframeAggregationsInput!): DataframeAggregationsResult! dataframeRecipeExecution(id: ID!): DataframeRecipeExecution + dataframeRecipeRevision(projectId: String!, name: String!, digest: String!): DataframeRecipeRevision + dataframeRecipeRevisions(projectId: String!, name: String!): [DataframeRecipeRevision!]! explainDataframeRecipe(input: ExplainDataframeRecipeInput!): DataframeRecipeExplanation! preflightDataframeRecipe(input: PreflightDataframeRecipeInput!): DataframeRecipePreflight! fhirGraph(input: FhirGraphQueryInput!): FhirGraphQueryResult! @@ -20178,6 +20304,7 @@ type Mutation { startDataframeMaterialization(input: StartDataframeMaterializationInput!): DataframeRecipeExecution! activateProjectRelease(input: ActivateProjectReleaseInput!): ProjectRelease! promoteDataframeContract(input: PromoteDataframeContractInput!): DataframeContract! + registerDataframeRecipeRevision(input: RegisterDataframeRecipeRevisionInput!): DataframeRecipeRevision! } input StartDataframeMaterializationInput { @@ -20213,8 +20340,25 @@ type DataframeContract { promotedAt: String! } +input RegisterDataframeRecipeRevisionInput { + projectId: String! + name: String! + parentDigest: String + recipe: JSON! +} + +type DataframeRecipeRevision { + projectId: String! + name: String! + digest: String! + parentDigest: String + recipe: JSON! + createdAt: String! +} + input DataframeRecipeBindingsInput { project: String! + recipeDigest: String datasetGeneration: String authResourcePaths: [String!] previewLimit: Int = 25 @@ -20462,6 +20606,7 @@ type DataframeRecipeExecutionOutput { name: String! state: DataframeRecipeExecutionState! rowCount: Int + columns: [DataframeColumn!]! error: String errorCode: String errorRetryable: Boolean @@ -20477,6 +20622,7 @@ enum DataframeMaterializationState { } type DataframeColumn { + semanticPath: String! name: String! clickhouseType: String! logicalType: String! @@ -20491,6 +20637,8 @@ type DataframeMaterialization { id: ID! name: String! revision: String! + projectId: String! + datasetGeneration: String! state: DataframeMaterializationState! columns: [DataframeColumn!]! rowCount: Int @@ -24712,6 +24860,8 @@ func (ec *executionContext) childFields_DataframeBuilderIntrospection(ctx contex func (ec *executionContext) childFields_DataframeColumn(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { + case "semanticPath": + return ec.fieldContext_DataframeColumn_semanticPath(ctx, field) case "name": return ec.fieldContext_DataframeColumn_name(ctx, field) case "clickhouseType": @@ -24838,6 +24988,10 @@ func (ec *executionContext) childFields_DataframeMaterialization(ctx context.Con return ec.fieldContext_DataframeMaterialization_name(ctx, field) case "revision": return ec.fieldContext_DataframeMaterialization_revision(ctx, field) + case "projectId": + return ec.fieldContext_DataframeMaterialization_projectId(ctx, field) + case "datasetGeneration": + return ec.fieldContext_DataframeMaterialization_datasetGeneration(ctx, field) case "state": return ec.fieldContext_DataframeMaterialization_state(ctx, field) case "columns": @@ -25034,6 +25188,8 @@ func (ec *executionContext) childFields_DataframeRecipeExecutionOutput(ctx conte return ec.fieldContext_DataframeRecipeExecutionOutput_state(ctx, field) case "rowCount": return ec.fieldContext_DataframeRecipeExecutionOutput_rowCount(ctx, field) + case "columns": + return ec.fieldContext_DataframeRecipeExecutionOutput_columns(ctx, field) case "error": return ec.fieldContext_DataframeRecipeExecutionOutput_error(ctx, field) case "errorCode": @@ -25356,6 +25512,24 @@ func (ec *executionContext) childFields_DataframeRecipeResultOutput(ctx context. return nil, fmt.Errorf("no field named %q was found under type DataframeRecipeResultOutput", field.Name) } +func (ec *executionContext) childFields_DataframeRecipeRevision(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "projectId": + return ec.fieldContext_DataframeRecipeRevision_projectId(ctx, field) + case "name": + return ec.fieldContext_DataframeRecipeRevision_name(ctx, field) + case "digest": + return ec.fieldContext_DataframeRecipeRevision_digest(ctx, field) + case "parentDigest": + return ec.fieldContext_DataframeRecipeRevision_parentDigest(ctx, field) + case "recipe": + return ec.fieldContext_DataframeRecipeRevision_recipe(ctx, field) + case "createdAt": + return ec.fieldContext_DataframeRecipeRevision_createdAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type DataframeRecipeRevision", field.Name) +} + func (ec *executionContext) childFields_DataframeRecipeValidation(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "name": diff --git a/generated/graphql/graph/executor/schema.generated.go b/generated/graphql/graph/executor/schema.generated.go index cb1aca80..88f737cd 100644 --- a/generated/graphql/graph/executor/schema.generated.go +++ b/generated/graphql/graph/executor/schema.generated.go @@ -28,16 +28,20 @@ type MutationResolver interface { StartDataframeMaterialization(ctx context.Context, input model.StartDataframeMaterializationInput) (*model.DataframeRecipeExecution, error) ActivateProjectRelease(ctx context.Context, input model.ActivateProjectReleaseInput) (*model.ProjectRelease, error) PromoteDataframeContract(ctx context.Context, input model.PromoteDataframeContractInput) (*model.DataframeContract, error) + RegisterDataframeRecipeRevision(ctx context.Context, input model.RegisterDataframeRecipeRevisionInput) (*model.DataframeRecipeRevision, error) } type QueryResolver interface { DataframeBuilderIntrospection(ctx context.Context, input model.DataframeBuilderIntrospectionInput) (*model.DataframeBuilderIntrospection, error) DataframeMaterialization(ctx context.Context, id string) (*model.DataframeMaterialization, error) DataframeDatasets(ctx context.Context) ([]*model.DataframeMaterialization, error) + ProjectDataframeDatasets(ctx context.Context, projectID string) ([]*model.DataframeMaterialization, error) DataframeDataset(ctx context.Context, input model.DataframeDatasetInput) (*model.DataframeMaterialization, error) DataframeRows(ctx context.Context, input model.DataframeRowsInput) (*model.DataframeRowConnection, error) DataframeAggregate(ctx context.Context, input model.DataframeAggregateInput) (*model.DataframeAggregateResult, error) DataframeAggregations(ctx context.Context, input model.DataframeAggregationsInput) (*model.DataframeAggregationsResult, error) DataframeRecipeExecution(ctx context.Context, id string) (*model.DataframeRecipeExecution, error) + DataframeRecipeRevision(ctx context.Context, projectID string, name string, digest string) (*model.DataframeRecipeRevision, error) + DataframeRecipeRevisions(ctx context.Context, projectID string, name string) ([]*model.DataframeRecipeRevision, error) ExplainDataframeRecipe(ctx context.Context, input model.ExplainDataframeRecipeInput) (*model.DataframeRecipeExplanation, error) PreflightDataframeRecipe(ctx context.Context, input model.PreflightDataframeRecipeInput) (*model.DataframeRecipePreflight, error) FhirGraph(ctx context.Context, input model.FhirGraphQueryInput) (*model.FhirGraphQueryResult, error) @@ -127,6 +131,20 @@ func (ec *executionContext) field_Mutation_promoteDataframeContract_args(ctx con return args, nil } +func (ec *executionContext) field_Mutation_registerDataframeRecipeRevision_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", + func(ctx context.Context, v any) (model.RegisterDataframeRecipeRevisionInput, error) { + return ec.unmarshalNRegisterDataframeRecipeRevisionInput2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐRegisterDataframeRecipeRevisionInput(ctx, v) + }) + if err != nil { + return nil, err + } + args["input"] = arg0 + return args, nil +} + func (ec *executionContext) field_Mutation_runDataframeRecipe_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -979,6 +997,58 @@ func (ec *executionContext) field_Query_dataframeRecipeExecution_args(ctx contex return args, nil } +func (ec *executionContext) field_Query_dataframeRecipeRevision_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := graphql.ProcessArgField(ctx, rawArgs, "projectId", + func(ctx context.Context, v any) (string, error) { + return ec.unmarshalNString2string(ctx, v) + }) + if err != nil { + return nil, err + } + args["projectId"] = arg0 + arg1, err := graphql.ProcessArgField(ctx, rawArgs, "name", + func(ctx context.Context, v any) (string, error) { + return ec.unmarshalNString2string(ctx, v) + }) + if err != nil { + return nil, err + } + args["name"] = arg1 + arg2, err := graphql.ProcessArgField(ctx, rawArgs, "digest", + func(ctx context.Context, v any) (string, error) { + return ec.unmarshalNString2string(ctx, v) + }) + if err != nil { + return nil, err + } + args["digest"] = arg2 + return args, nil +} + +func (ec *executionContext) field_Query_dataframeRecipeRevisions_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := graphql.ProcessArgField(ctx, rawArgs, "projectId", + func(ctx context.Context, v any) (string, error) { + return ec.unmarshalNString2string(ctx, v) + }) + if err != nil { + return nil, err + } + args["projectId"] = arg0 + arg1, err := graphql.ProcessArgField(ctx, rawArgs, "name", + func(ctx context.Context, v any) (string, error) { + return ec.unmarshalNString2string(ctx, v) + }) + if err != nil { + return nil, err + } + args["name"] = arg1 + return args, nil +} + func (ec *executionContext) field_Query_dataframeRows_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -1057,6 +1127,20 @@ func (ec *executionContext) field_Query_preflightDataframeRecipe_args(ctx contex return args, nil } +func (ec *executionContext) field_Query_projectDataframeDatasets_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := graphql.ProcessArgField(ctx, rawArgs, "projectId", + func(ctx context.Context, v any) (string, error) { + return ec.unmarshalNString2string(ctx, v) + }) + if err != nil { + return nil, err + } + args["projectId"] = arg0 + return args, nil +} + // endregion ***************************** args.gotpl ***************************** // region **************************** field.gotpl ***************************** @@ -1423,6 +1507,29 @@ func (ec *executionContext) fieldContext_DataframeBuilderIntrospection_pivotFiel return fc, nil } +func (ec *executionContext) _DataframeColumn_semanticPath(ctx context.Context, field graphql.CollectedField, obj *model.DataframeColumn) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.fieldContext_DataframeColumn_semanticPath(ctx, field) + }, + func(ctx context.Context) (any, error) { + return obj.SemanticPath, nil + }, + nil, + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) + }, + true, + true, + ) +} +func (ec *executionContext) fieldContext_DataframeColumn_semanticPath(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeColumn", field, false, false, errors.New("field of type String does not have child fields")) +} + func (ec *executionContext) _DataframeColumn_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeColumn) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -2512,6 +2619,52 @@ func (ec *executionContext) fieldContext_DataframeMaterialization_revision(_ con return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) } +func (ec *executionContext) _DataframeMaterialization_projectId(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.fieldContext_DataframeMaterialization_projectId(ctx, field) + }, + func(ctx context.Context) (any, error) { + return obj.ProjectID, nil + }, + nil, + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) + }, + true, + true, + ) +} +func (ec *executionContext) fieldContext_DataframeMaterialization_projectId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) +} + +func (ec *executionContext) _DataframeMaterialization_datasetGeneration(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.fieldContext_DataframeMaterialization_datasetGeneration(ctx, field) + }, + func(ctx context.Context) (any, error) { + return obj.DatasetGeneration, nil + }, + nil, + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) + }, + true, + true, + ) +} +func (ec *executionContext) fieldContext_DataframeMaterialization_datasetGeneration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) +} + func (ec *executionContext) _DataframeMaterialization_state(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -4235,6 +4388,38 @@ func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_rowCount return graphql.NewScalarFieldContext("DataframeRecipeExecutionOutput", field, false, false, errors.New("field of type Int does not have child fields")) } +func (ec *executionContext) _DataframeRecipeExecutionOutput_columns(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.fieldContext_DataframeRecipeExecutionOutput_columns(ctx, field) + }, + func(ctx context.Context) (any, error) { + return obj.Columns, nil + }, + nil, + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeColumn) graphql.Marshaler { + return ec.marshalNDataframeColumn2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeColumnᚄ(ctx, selections, v) + }, + true, + true, + ) +} +func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_columns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DataframeRecipeExecutionOutput", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeColumn(ctx, field) + }, + } + return fc, nil +} + func (ec *executionContext) _DataframeRecipeExecutionOutput_error(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -6647,6 +6832,144 @@ func (ec *executionContext) fieldContext_DataframeRecipeResultOutput_rowCount(_ return graphql.NewScalarFieldContext("DataframeRecipeResultOutput", field, false, false, errors.New("field of type Int does not have child fields")) } +func (ec *executionContext) _DataframeRecipeRevision_projectId(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeRevision) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.fieldContext_DataframeRecipeRevision_projectId(ctx, field) + }, + func(ctx context.Context) (any, error) { + return obj.ProjectID, nil + }, + nil, + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) + }, + true, + true, + ) +} +func (ec *executionContext) fieldContext_DataframeRecipeRevision_projectId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeRevision", field, false, false, errors.New("field of type String does not have child fields")) +} + +func (ec *executionContext) _DataframeRecipeRevision_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeRevision) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.fieldContext_DataframeRecipeRevision_name(ctx, field) + }, + func(ctx context.Context) (any, error) { + return obj.Name, nil + }, + nil, + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) + }, + true, + true, + ) +} +func (ec *executionContext) fieldContext_DataframeRecipeRevision_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeRevision", field, false, false, errors.New("field of type String does not have child fields")) +} + +func (ec *executionContext) _DataframeRecipeRevision_digest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeRevision) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.fieldContext_DataframeRecipeRevision_digest(ctx, field) + }, + func(ctx context.Context) (any, error) { + return obj.Digest, nil + }, + nil, + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) + }, + true, + true, + ) +} +func (ec *executionContext) fieldContext_DataframeRecipeRevision_digest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeRevision", field, false, false, errors.New("field of type String does not have child fields")) +} + +func (ec *executionContext) _DataframeRecipeRevision_parentDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeRevision) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.fieldContext_DataframeRecipeRevision_parentDigest(ctx, field) + }, + func(ctx context.Context) (any, error) { + return obj.ParentDigest, nil + }, + nil, + func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { + return ec.marshalOString2ᚖstring(ctx, selections, v) + }, + true, + false, + ) +} +func (ec *executionContext) fieldContext_DataframeRecipeRevision_parentDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeRevision", field, false, false, errors.New("field of type String does not have child fields")) +} + +func (ec *executionContext) _DataframeRecipeRevision_recipe(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeRevision) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.fieldContext_DataframeRecipeRevision_recipe(ctx, field) + }, + func(ctx context.Context) (any, error) { + return obj.Recipe, nil + }, + nil, + func(ctx context.Context, selections ast.SelectionSet, v json.RawMessage) graphql.Marshaler { + return ec.marshalNJSON2encodingᚋjsonᚐRawMessage(ctx, selections, v) + }, + true, + true, + ) +} +func (ec *executionContext) fieldContext_DataframeRecipeRevision_recipe(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeRevision", field, false, false, errors.New("field of type JSON does not have child fields")) +} + +func (ec *executionContext) _DataframeRecipeRevision_createdAt(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeRevision) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.fieldContext_DataframeRecipeRevision_createdAt(ctx, field) + }, + func(ctx context.Context) (any, error) { + return obj.CreatedAt, nil + }, + nil, + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) + }, + true, + true, + ) +} +func (ec *executionContext) fieldContext_DataframeRecipeRevision_createdAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeRevision", field, false, false, errors.New("field of type String does not have child fields")) +} + func (ec *executionContext) _DataframeRecipeValidation_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeValidation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -8413,6 +8736,50 @@ func (ec *executionContext) fieldContext_Mutation_promoteDataframeContract(ctx c return fc, nil } +func (ec *executionContext) _Mutation_registerDataframeRecipeRevision(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.fieldContext_Mutation_registerDataframeRecipeRevision(ctx, field) + }, + func(ctx context.Context) (any, error) { + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Mutation().RegisterDataframeRecipeRevision(ctx, fc.Args["input"].(model.RegisterDataframeRecipeRevisionInput)) + }, + nil, + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeRevision) graphql.Marshaler { + return ec.marshalNDataframeRecipeRevision2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeRevision(ctx, selections, v) + }, + true, + true, + ) +} +func (ec *executionContext) fieldContext_Mutation_registerDataframeRecipeRevision(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipeRevision(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_registerDataframeRecipeRevision_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _ProjectRelease_id(ctx context.Context, field graphql.CollectedField, obj *model.ProjectRelease) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -8648,6 +9015,50 @@ func (ec *executionContext) fieldContext_Query_dataframeDatasets(_ context.Conte return fc, nil } +func (ec *executionContext) _Query_projectDataframeDatasets(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.fieldContext_Query_projectDataframeDatasets(ctx, field) + }, + func(ctx context.Context) (any, error) { + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().ProjectDataframeDatasets(ctx, fc.Args["projectId"].(string)) + }, + nil, + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeMaterialization) graphql.Marshaler { + return ec.marshalNDataframeMaterialization2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeMaterializationᚄ(ctx, selections, v) + }, + true, + true, + ) +} +func (ec *executionContext) fieldContext_Query_projectDataframeDatasets(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeMaterialization(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_projectDataframeDatasets_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Query_dataframeDataset(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -8705,21 +9116,109 @@ func (ec *executionContext) _Query_dataframeRows(ctx context.Context, field grap return ec.Resolvers.Query().DataframeRows(ctx, fc.Args["input"].(model.DataframeRowsInput)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRowConnection) graphql.Marshaler { - return ec.marshalNDataframeRowConnection2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRowConnection(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRowConnection) graphql.Marshaler { + return ec.marshalNDataframeRowConnection2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRowConnection(ctx, selections, v) + }, + true, + true, + ) +} +func (ec *executionContext) fieldContext_Query_dataframeRows(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRowConnection(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_dataframeRows_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_dataframeAggregate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.fieldContext_Query_dataframeAggregate(ctx, field) + }, + func(ctx context.Context) (any, error) { + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().DataframeAggregate(ctx, fc.Args["input"].(model.DataframeAggregateInput)) + }, + nil, + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeAggregateResult) graphql.Marshaler { + return ec.marshalNDataframeAggregateResult2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeAggregateResult(ctx, selections, v) + }, + true, + true, + ) +} +func (ec *executionContext) fieldContext_Query_dataframeAggregate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeAggregateResult(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_dataframeAggregate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_dataframeAggregations(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.fieldContext_Query_dataframeAggregations(ctx, field) + }, + func(ctx context.Context) (any, error) { + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().DataframeAggregations(ctx, fc.Args["input"].(model.DataframeAggregationsInput)) + }, + nil, + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeAggregationsResult) graphql.Marshaler { + return ec.marshalNDataframeAggregationsResult2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeAggregationsResult(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_Query_dataframeRows(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_dataframeAggregations(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRowConnection(ctx, field) + return ec.childFields_DataframeAggregationsResult(ctx, field) }, } defer func() { @@ -8729,41 +9228,41 @@ func (ec *executionContext) fieldContext_Query_dataframeRows(ctx context.Context } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_dataframeRows_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_dataframeAggregations_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Query_dataframeAggregate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_dataframeRecipeExecution(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_dataframeAggregate(ctx, field) + return ec.fieldContext_Query_dataframeRecipeExecution(ctx, field) }, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().DataframeAggregate(ctx, fc.Args["input"].(model.DataframeAggregateInput)) + return ec.Resolvers.Query().DataframeRecipeExecution(ctx, fc.Args["id"].(string)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeAggregateResult) graphql.Marshaler { - return ec.marshalNDataframeAggregateResult2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeAggregateResult(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeExecution) graphql.Marshaler { + return ec.marshalODataframeRecipeExecution2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExecution(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_Query_dataframeAggregate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_dataframeRecipeExecution(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeAggregateResult(ctx, field) + return ec.childFields_DataframeRecipeExecution(ctx, field) }, } defer func() { @@ -8773,41 +9272,41 @@ func (ec *executionContext) fieldContext_Query_dataframeAggregate(ctx context.Co } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_dataframeAggregate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_dataframeRecipeExecution_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Query_dataframeAggregations(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_dataframeRecipeRevision(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_dataframeAggregations(ctx, field) + return ec.fieldContext_Query_dataframeRecipeRevision(ctx, field) }, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().DataframeAggregations(ctx, fc.Args["input"].(model.DataframeAggregationsInput)) + return ec.Resolvers.Query().DataframeRecipeRevision(ctx, fc.Args["projectId"].(string), fc.Args["name"].(string), fc.Args["digest"].(string)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeAggregationsResult) graphql.Marshaler { - return ec.marshalNDataframeAggregationsResult2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeAggregationsResult(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeRevision) graphql.Marshaler { + return ec.marshalODataframeRecipeRevision2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeRevision(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_Query_dataframeAggregations(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_dataframeRecipeRevision(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeAggregationsResult(ctx, field) + return ec.childFields_DataframeRecipeRevision(ctx, field) }, } defer func() { @@ -8817,41 +9316,41 @@ func (ec *executionContext) fieldContext_Query_dataframeAggregations(ctx context } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_dataframeAggregations_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_dataframeRecipeRevision_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Query_dataframeRecipeExecution(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_dataframeRecipeRevisions(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_dataframeRecipeExecution(ctx, field) + return ec.fieldContext_Query_dataframeRecipeRevisions(ctx, field) }, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().DataframeRecipeExecution(ctx, fc.Args["id"].(string)) + return ec.Resolvers.Query().DataframeRecipeRevisions(ctx, fc.Args["projectId"].(string), fc.Args["name"].(string)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeExecution) graphql.Marshaler { - return ec.marshalODataframeRecipeExecution2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExecution(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeRevision) graphql.Marshaler { + return ec.marshalNDataframeRecipeRevision2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeRevisionᚄ(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_Query_dataframeRecipeExecution(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_dataframeRecipeRevisions(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeExecution(ctx, field) + return ec.childFields_DataframeRecipeRevision(ctx, field) }, } defer func() { @@ -8861,7 +9360,7 @@ func (ec *executionContext) fieldContext_Query_dataframeRecipeExecution(ctx cont } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_dataframeRecipeExecution_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_dataframeRecipeRevisions_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } @@ -10530,7 +11029,7 @@ func (ec *executionContext) unmarshalInputDataframeRecipeBindingsInput(ctx conte asMap["previewLimit"] = 25 } - fieldsInOrder := [...]string{"project", "datasetGeneration", "authResourcePaths", "previewLimit"} + fieldsInOrder := [...]string{"project", "recipeDigest", "datasetGeneration", "authResourcePaths", "previewLimit"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -10544,6 +11043,13 @@ func (ec *executionContext) unmarshalInputDataframeRecipeBindingsInput(ctx conte return it, err } it.Project = data + case "recipeDigest": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("recipeDigest")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.RecipeDigest = data case "datasetGeneration": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("datasetGeneration")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) @@ -12060,6 +12566,57 @@ func (ec *executionContext) unmarshalInputPromoteDataframeContractInput(ctx cont return it, nil } +func (ec *executionContext) unmarshalInputRegisterDataframeRecipeRevisionInput(ctx context.Context, obj any) (model.RegisterDataframeRecipeRevisionInput, error) { + var it model.RegisterDataframeRecipeRevisionInput + if obj == nil { + return it, nil + } + + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"projectId", "name", "parentDigest", "recipe"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "projectId": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("projectId")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.ProjectID = data + case "name": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.Name = data + case "parentDigest": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("parentDigest")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.ParentDigest = data + case "recipe": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("recipe")) + data, err := ec.unmarshalNJSON2encodingᚋjsonᚐRawMessage(ctx, v) + if err != nil { + return it, err + } + it.Recipe = data + } + } + return it, nil +} + func (ec *executionContext) unmarshalInputRunDataframeRecipeInput(ctx context.Context, obj any) (model.RunDataframeRecipeInput, error) { var it model.RunDataframeRecipeInput if obj == nil { @@ -12369,6 +12926,11 @@ func (ec *executionContext) _DataframeColumn(ctx context.Context, sel ast.Select switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("DataframeColumn") + case "semanticPath": + out.Values[i] = ec._DataframeColumn_semanticPath(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "name": out.Values[i] = ec._DataframeColumn_name(ctx, field, obj) if out.Values[i] == graphql.Null { @@ -12792,6 +13354,16 @@ func (ec *executionContext) _DataframeMaterialization(ctx context.Context, sel a if out.Values[i] == graphql.Null { out.Invalids++ } + case "projectId": + out.Values[i] = ec._DataframeMaterialization_projectId(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "datasetGeneration": + out.Values[i] = ec._DataframeMaterialization_datasetGeneration(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "state": out.Values[i] = ec._DataframeMaterialization_state(ctx, field, obj) if out.Values[i] == graphql.Null { @@ -13444,6 +14016,11 @@ func (ec *executionContext) _DataframeRecipeExecutionOutput(ctx context.Context, if out.Values[i] == graphql.RequiredNull { out.Invalids++ } + case "columns": + out.Values[i] = ec._DataframeRecipeExecutionOutput_columns(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "error": out.Values[i] = ec._DataframeRecipeExecutionOutput_error(ctx, field, obj) if out.Values[i] == graphql.RequiredNull { @@ -14620,6 +15197,69 @@ func (ec *executionContext) _DataframeRecipeResultOutput(ctx context.Context, se return out } +var dataframeRecipeRevisionImplementors = []string{"DataframeRecipeRevision"} + +func (ec *executionContext) _DataframeRecipeRevision(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeRecipeRevision) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, dataframeRecipeRevisionImplementors) + + out := graphql.NewFieldSet(fields) + deferredFieldSet := graphql.NewFieldSet(nil) + deferLabelToView := make(map[string]*graphql.FieldSetView) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("DataframeRecipeRevision") + case "projectId": + out.Values[i] = ec._DataframeRecipeRevision_projectId(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec._DataframeRecipeRevision_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "digest": + out.Values[i] = ec._DataframeRecipeRevision_digest(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "parentDigest": + out.Values[i] = ec._DataframeRecipeRevision_parentDigest(ctx, field, obj) + if out.Values[i] == graphql.RequiredNull { + out.Invalids++ + } + case "recipe": + out.Values[i] = ec._DataframeRecipeRevision_recipe(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "createdAt": + out.Values[i] = ec._DataframeRecipeRevision_createdAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.Deferred, int32(min(len(deferLabelToView), math.MaxInt32))) + + ec.ProcessDeferredGroup(graphql.DeferredGroup{ + Defers: deferLabelToView, + Path: graphql.GetPath(ctx), + FieldSet: deferredFieldSet, + Context: ctx, + }) + + return out +} + var dataframeRecipeValidationImplementors = []string{"DataframeRecipeValidation"} func (ec *executionContext) _DataframeRecipeValidation(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeRecipeValidation) graphql.Marshaler { @@ -15438,6 +16078,13 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { out.Invalids++ } + case "registerDataframeRecipeRevision": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_registerDataframeRecipeRevision(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -15602,6 +16249,28 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "projectDataframeDatasets": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_projectDataframeDatasets(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "dataframeDataset": field := field @@ -15712,6 +16381,50 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "dataframeRecipeRevision": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_dataframeRecipeRevision(ctx, field) + if res == graphql.RequiredNull { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "dataframeRecipeRevisions": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_dataframeRecipeRevisions(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "explainDataframeRecipe": field := field @@ -17136,6 +17849,36 @@ func (ec *executionContext) marshalNDataframeRecipeResultOutput2ᚖgithubᚗcom return ec._DataframeRecipeResultOutput(ctx, sel, v) } +func (ec *executionContext) marshalNDataframeRecipeRevision2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeRevision(ctx context.Context, sel ast.SelectionSet, v model.DataframeRecipeRevision) graphql.Marshaler { + return ec._DataframeRecipeRevision(ctx, sel, &v) +} + +func (ec *executionContext) marshalNDataframeRecipeRevision2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeRevisionᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.DataframeRecipeRevision) graphql.Marshaler { + ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { + fc := graphql.GetFieldContext(ctx) + fc.Result = &v[i] + return ec.marshalNDataframeRecipeRevision2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeRevision(ctx, sel, v[i]) + }) + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalNDataframeRecipeRevision2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeRevision(ctx context.Context, sel ast.SelectionSet, v *model.DataframeRecipeRevision) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._DataframeRecipeRevision(ctx, sel, v) +} + func (ec *executionContext) marshalNDataframeRecipeValidation2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeValidation(ctx context.Context, sel ast.SelectionSet, v model.DataframeRecipeValidation) graphql.Marshaler { return ec._DataframeRecipeValidation(ctx, sel, &v) } @@ -17656,6 +18399,11 @@ func (ec *executionContext) unmarshalNPromoteDataframeContractInput2githubᚗcom return res, graphql.ErrorOnPath(ctx, err) } +func (ec *executionContext) unmarshalNRegisterDataframeRecipeRevisionInput2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐRegisterDataframeRecipeRevisionInput(ctx context.Context, v any) (model.RegisterDataframeRecipeRevisionInput, error) { + res, err := ec.unmarshalInputRegisterDataframeRecipeRevisionInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) unmarshalNRunDataframeRecipeInput2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐRunDataframeRecipeInput(ctx context.Context, v any) (model.RunDataframeRecipeInput, error) { res, err := ec.unmarshalInputRunDataframeRecipeInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -17767,6 +18515,13 @@ func (ec *executionContext) marshalODataframeRecipePhysicalExplanation2ᚖgithub return ec._DataframeRecipePhysicalExplanation(ctx, sel, v) } +func (ec *executionContext) marshalODataframeRecipeRevision2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeRevision(ctx context.Context, sel ast.SelectionSet, v *model.DataframeRecipeRevision) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._DataframeRecipeRevision(ctx, sel, v) +} + func (ec *executionContext) marshalODataframeSelector2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeSelector(ctx context.Context, sel ast.SelectionSet, v *model.DataframeSelector) graphql.Marshaler { if v == nil { return graphql.Null diff --git a/generated/graphql/graph/model/models.go b/generated/graphql/graph/model/models.go index ea8c799d..c8705b24 100644 --- a/generated/graphql/graph/model/models.go +++ b/generated/graphql/graph/model/models.go @@ -79,6 +79,7 @@ type DataframeBuilderIntrospectionInput struct { } type DataframeColumn struct { + SemanticPath string `json:"semanticPath"` Name string `json:"name"` ClickhouseType string `json:"clickhouseType"` LogicalType string `json:"logicalType"` @@ -153,6 +154,8 @@ type DataframeMaterialization struct { ID string `json:"id"` Name string `json:"name"` Revision string `json:"revision"` + ProjectID string `json:"projectId"` + DatasetGeneration string `json:"datasetGeneration"` State DataframeMaterializationState `json:"state"` Columns []*DataframeColumn `json:"columns"` RowCount *int `json:"rowCount,omitempty"` @@ -224,6 +227,7 @@ type DataframeRecipeArangoAssessment struct { type DataframeRecipeBindingsInput struct { Project string `json:"project"` + RecipeDigest *string `json:"recipeDigest,omitempty"` DatasetGeneration *string `json:"datasetGeneration,omitempty"` AuthResourcePaths []string `json:"authResourcePaths,omitempty"` PreviewLimit *int `json:"previewLimit,omitempty"` @@ -258,6 +262,7 @@ type DataframeRecipeExecutionOutput struct { Name string `json:"name"` State DataframeRecipeExecutionState `json:"state"` RowCount *int `json:"rowCount,omitempty"` + Columns []*DataframeColumn `json:"columns"` Error *string `json:"error,omitempty"` ErrorCode *string `json:"errorCode,omitempty"` ErrorRetryable *bool `json:"errorRetryable,omitempty"` @@ -419,6 +424,15 @@ type DataframeRecipeResultOutput struct { RowCount int `json:"rowCount"` } +type DataframeRecipeRevision struct { + ProjectID string `json:"projectId"` + Name string `json:"name"` + Digest string `json:"digest"` + ParentDigest *string `json:"parentDigest,omitempty"` + Recipe json.RawMessage `json:"recipe"` + CreatedAt string `json:"createdAt"` +} + type DataframeRecipeValidation struct { Name string `json:"name"` RecipeDigest string `json:"recipeDigest"` @@ -722,6 +736,13 @@ type PromoteDataframeContractInput struct { type Query struct { } +type RegisterDataframeRecipeRevisionInput struct { + ProjectID string `json:"projectId"` + Name string `json:"name"` + ParentDigest *string `json:"parentDigest,omitempty"` + Recipe json.RawMessage `json:"recipe"` +} + type RunDataframeRecipeInput struct { Name string `json:"name"` Bindings *DataframeRecipeBindingsInput `json:"bindings"` diff --git a/internal/api/bulk/load/generation_route.go b/internal/api/bulk/load/generation_route.go index 2e212314..ba56c692 100644 --- a/internal/api/bulk/load/generation_route.go +++ b/internal/api/bulk/load/generation_route.go @@ -6,6 +6,7 @@ import ( "mime/multipart" "os" "path/filepath" + "strconv" "strings" "github.com/calypr/loom/internal/authscope" @@ -31,6 +32,13 @@ func (s *Handler) createGeneration(c fiber.Ctx) error { return dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") } authResourcePath := strings.TrimSpace(c.Req().FormValue("auth_resource_path")) + deferActivation := false + if raw := strings.TrimSpace(c.Req().FormValue("defer_activation")); raw != "" { + deferActivation, err = strconv.ParseBool(raw) + if err != nil { + return dataframeerrors.Wrap(err, dataframeerrors.CodeInvalidRequest, "") + } + } principal, _ := c.Locals("principal").(*authscope.Principal) if err := s.authz.AuthorizeWrite(c.Context(), principal, project, authResourcePath); err != nil { return dataframeerrors.Wrap(err, dataframeerrors.CodeForbidden, "") @@ -47,7 +55,7 @@ func (s *Handler) createGeneration(c fiber.Ctx) error { return dataframeerrors.Wrap(err, dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) } defer os.RemoveAll(stagedDir) - req := GenerationLoadRequest{Project: project, Generation: generation, AuthResourcePath: authResourcePath, StagedDir: stagedDir} + req := GenerationLoadRequest{Project: project, Generation: generation, AuthResourcePath: authResourcePath, StagedDir: stagedDir, DeferActivation: deferActivation} if principal != nil { req.SubmittedBy = principal.Subject } @@ -58,6 +66,24 @@ func (s *Handler) createGeneration(c fiber.Ctx) error { return c.Status(fiber.StatusOK).JSON(result) } +func (s *Handler) activateGeneration(c fiber.Ctx) error { + project := strings.TrimSpace(c.Params("project")) + generation := strings.TrimSpace(c.Params("generation")) + executionID := strings.TrimSpace(c.Query("dataframe_execution_id")) + if project == "" || generation == "" || executionID == "" { + return dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") + } + authResourcePath := strings.TrimSpace(c.Query("auth_resource_path")) + principal, _ := c.Locals("principal").(*authscope.Principal) + if err := s.authz.AuthorizeWrite(c.Context(), principal, project, authResourcePath); err != nil { + return dataframeerrors.Wrap(err, dataframeerrors.CodeForbidden, "") + } + if err := s.service.ActivateGeneration(c.Context(), project, generation, executionID); err != nil { + return dataframeerrors.Wrap(err, dataframeerrors.CodePublicationConflict, "") + } + return c.Status(fiber.StatusOK).JSON(map[string]any{"project": project, "generation": generation, "dataframeExecutionId": executionID, "activated": true}) +} + func stageGenerationFiles(headers []*multipart.FileHeader) (string, error) { dir, err := os.MkdirTemp("", "loom-generation-") if err != nil { diff --git a/internal/api/bulk/load/generation_route_test.go b/internal/api/bulk/load/generation_route_test.go index 089893b5..94caef31 100644 --- a/internal/api/bulk/load/generation_route_test.go +++ b/internal/api/bulk/load/generation_route_test.go @@ -49,12 +49,45 @@ func TestCreateGenerationStagesCompleteBundle(t *testing.T) { } } +func TestCreateGenerationPropagatesDeferredActivation(t *testing.T) { + runner := &fakeGenerationRunner{} + svc, err := NewService(ServiceConfig{GenerationRunner: runner}) + if err != nil { + t.Fatal(err) + } + server, err := NewHTTPServer(HTTPConfig{Service: svc, Authorizer: authscope.AllowAllAuthorizer{}}) + if err != nil { + t.Fatal(err) + } + req := newGenerationMultipartRequestWithDefer(t, "P1", "generation-1", true, map[string][]byte{ + "Patient.ndjson": []byte(`{"resourceType":"Patient","id":"1"}` + "\n"), + }) + resp, err := server.App().Test(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + t.Fatalf("status = %d, want %d", resp.StatusCode, http.StatusOK) + } + if !runner.req.DeferActivation { + t.Fatalf("generation request = %#v, want deferred activation", runner.req) + } +} + func newGenerationMultipartRequest(t *testing.T, project, generation string, files map[string][]byte) *http.Request { + return newGenerationMultipartRequestWithDefer(t, project, generation, false, files) +} + +func newGenerationMultipartRequestWithDefer(t *testing.T, project, generation string, deferActivation bool, files map[string][]byte) *http.Request { t.Helper() var body bytes.Buffer writer := multipart.NewWriter(&body) _ = writer.WriteField("project", project) _ = writer.WriteField("generation", generation) + if deferActivation { + _ = writer.WriteField("defer_activation", "true") + } for name, content := range files { part, err := writer.CreateFormFile("file", name) if err != nil { diff --git a/internal/api/bulk/load/handler.go b/internal/api/bulk/load/handler.go index c0a198a0..9fe6bc96 100644 --- a/internal/api/bulk/load/handler.go +++ b/internal/api/bulk/load/handler.go @@ -32,7 +32,9 @@ func NewHandler(cfg Config) (*Handler, error) { } func (h *Handler) RegisterRoutes(router fiber.Router) { + h.RegisterResourceRoute(router) router.Post("/api/v1/datasets/:project/generations/:generation", h.createGeneration) + router.Post("/api/v1/datasets/:project/generations/:generation/activate", h.activateGeneration) router.Put("/api/v1/raw", h.loadRaw) h.RegisterSnapshotRoutes(router) } diff --git a/internal/api/bulk/load/service.go b/internal/api/bulk/load/service.go index ccdaa26b..c7cc2ff1 100644 --- a/internal/api/bulk/load/service.go +++ b/internal/api/bulk/load/service.go @@ -3,8 +3,10 @@ package load import ( "context" "errors" + "fmt" "log/slog" + dataframepublication "github.com/calypr/loom/internal/dataframe/publication" publication "github.com/calypr/loom/internal/dataset" "github.com/calypr/loom/internal/ingest" ) @@ -16,6 +18,7 @@ type GenerationLoadRequest struct { StagedDir string SubmittedBy string StageOnly bool + DeferActivation bool } type ImportRequest struct { @@ -44,6 +47,18 @@ type GenerationLoadResult struct { AuthResourcePath string `json:"auth_resource_path,omitempty"` SubmittedBy string `json:"submitted_by,omitempty"` Summary *ingest.LoadSummary `json:"summary,omitempty"` + Activated bool `json:"activated"` + Reused bool `json:"reused,omitempty"` +} + +type GenerationActivator interface { + ReadManifest(context.Context, publication.Ref) (publication.Manifest, error) + Activate(context.Context, publication.Manifest) error +} + +type DataframeReleaseStore interface { + GetExecution(context.Context, string) (dataframepublication.BundleExecution, error) + GetPointer(context.Context, string) (dataframepublication.BundlePointer, error) } type GenerationRunner interface { @@ -78,6 +93,7 @@ func (r IngestRunner) RunGeneration(ctx context.Context, req GenerationLoadReque opts.AuthResourcePath = req.AuthResourcePath opts.MetaDir = req.StagedDir opts.Dataset = &ref + opts.DeferActivation = req.DeferActivation opts.Truncate = false opts.EventSink = sink opts.StageOnly = req.StageOnly @@ -85,17 +101,21 @@ func (r IngestRunner) RunGeneration(ctx context.Context, req GenerationLoadReque } type ServiceConfig struct { - Runner Runner - GenerationRunner GenerationRunner - Logger *slog.Logger - OnSuccess func(project string) + Runner Runner + GenerationRunner GenerationRunner + Logger *slog.Logger + OnSuccess func(project string) + GenerationActivator GenerationActivator + DataframeReleases DataframeReleaseStore } type Service struct { - runner Runner - generationRunner GenerationRunner - logger *slog.Logger - onSuccess func(project string) + runner Runner + generationRunner GenerationRunner + logger *slog.Logger + onSuccess func(project string) + generationActivator GenerationActivator + dataframeReleases DataframeReleaseStore } func NewService(cfg ServiceConfig) (*Service, error) { @@ -106,10 +126,12 @@ func NewService(cfg ServiceConfig) (*Service, error) { cfg.Logger = slog.Default() } return &Service{ - runner: cfg.Runner, - generationRunner: cfg.GenerationRunner, - logger: cfg.Logger, - onSuccess: cfg.OnSuccess, + runner: cfg.Runner, + generationRunner: cfg.GenerationRunner, + logger: cfg.Logger, + onSuccess: cfg.OnSuccess, + generationActivator: cfg.GenerationActivator, + dataframeReleases: cfg.DataframeReleases, }, nil } @@ -154,6 +176,26 @@ func (s *Service) RunGeneration(ctx context.Context, req GenerationLoadRequest) if req.Project == "" || req.Generation == "" || req.StagedDir == "" { return nil, errors.New("project, generation, and staged directory are required") } + if s.generationActivator != nil { + ref, err := publication.NewRef(req.Project, req.Generation) + if err != nil { + return nil, err + } + manifest, err := s.generationActivator.ReadManifest(ctx, ref) + switch { + case err == nil && manifest.IsReady(): + s.logger.Info("reusing ready generation", "project", req.Project, "generation", req.Generation) + return &GenerationLoadResult{ + Project: req.Project, Generation: req.Generation, + AuthResourcePath: req.AuthResourcePath, SubmittedBy: req.SubmittedBy, + Activated: false, Reused: true, + }, nil + case err == nil: + return nil, fmt.Errorf("generation %s/%s already exists in state %s", req.Project, req.Generation, manifest.State) + case !errors.Is(err, publication.ErrManifestNotFound): + return nil, fmt.Errorf("inspect existing generation: %w", err) + } + } summary, err := s.generationRunner.RunGeneration(ctx, req, nil) if err != nil { s.logger.Error("generation load failed", "project", req.Project, "generation", req.Generation, "error", err.Error()) @@ -163,5 +205,51 @@ func (s *Service) RunGeneration(ctx context.Context, req GenerationLoadRequest) s.onSuccess(req.Project) } s.logger.Info("generation load succeeded", "project", req.Project, "generation", req.Generation, "vertices", summary.VerticesInserted, "edges", summary.EdgesInserted) - return &GenerationLoadResult{Project: req.Project, Generation: req.Generation, AuthResourcePath: req.AuthResourcePath, SubmittedBy: req.SubmittedBy, Summary: &summary}, nil + return &GenerationLoadResult{Project: req.Project, Generation: req.Generation, AuthResourcePath: req.AuthResourcePath, SubmittedBy: req.SubmittedBy, Summary: &summary, Activated: !req.DeferActivation && !req.StageOnly}, nil +} + +// ActivateGeneration performs the release switch only after the exact +// dataframe bundle supplied by the caller is durably READY and remains the +// active pointer for its recipe/generation namespace. +func (s *Service) ActivateGeneration(ctx context.Context, project, generation, executionID string) error { + if s.generationActivator == nil || s.dataframeReleases == nil { + return errors.New("generation release activation is not configured") + } + ref, err := publication.NewRef(project, generation) + if err != nil { + return err + } + execution, err := s.dataframeReleases.GetExecution(ctx, executionID) + if err != nil { + return fmt.Errorf("load dataframe release %q: %w", executionID, err) + } + if execution.Project != project || execution.DatasetGeneration != generation || execution.State != dataframepublication.BundleReady || len(execution.Outputs) == 0 { + return fmt.Errorf("dataframe release %q is not a READY bundle for %s/%s", executionID, project, generation) + } + for _, output := range execution.Outputs { + if output.State != dataframepublication.BundleReady { + return fmt.Errorf("dataframe release %q output %q is not READY", executionID, output.Name) + } + } + pointer, err := s.dataframeReleases.GetPointer(ctx, execution.PointerName()) + if err != nil { + return fmt.Errorf("resolve dataframe release pointer: %w", err) + } + if pointer.ExecutionID != execution.ID { + return fmt.Errorf("dataframe release %q is no longer active", executionID) + } + manifest, err := s.generationActivator.ReadManifest(ctx, ref) + if err != nil { + return fmt.Errorf("read generation release: %w", err) + } + if !manifest.IsReady() { + return fmt.Errorf("generation %s/%s is not READY", project, generation) + } + if err := s.generationActivator.Activate(ctx, manifest); err != nil { + return fmt.Errorf("activate generation release: %w", err) + } + if s.onSuccess != nil { + s.onSuccess(project) + } + return nil } diff --git a/internal/api/bulk/load/service_test.go b/internal/api/bulk/load/service_test.go new file mode 100644 index 00000000..ceec4132 --- /dev/null +++ b/internal/api/bulk/load/service_test.go @@ -0,0 +1,254 @@ +package load + +import ( + "context" + "errors" + "fmt" + "testing" + "time" + + dataframepublication "github.com/calypr/loom/internal/dataframe/publication" + publication "github.com/calypr/loom/internal/dataset" + "github.com/calypr/loom/internal/ingest" +) + +type activationGenerationRunner struct{} + +func (activationGenerationRunner) RunGeneration(context.Context, GenerationLoadRequest, ingest.EventSink) (ingest.LoadSummary, error) { + return ingest.LoadSummary{}, nil +} + +type activationManifestStore struct { + manifest publication.Manifest + readErr error + activateErr error + readCalls int + activateCalls int + activated publication.Manifest +} + +func (s *activationManifestStore) ReadManifest(context.Context, publication.Ref) (publication.Manifest, error) { + s.readCalls++ + if s.readErr != nil { + return publication.Manifest{}, s.readErr + } + return s.manifest, nil +} + +func (s *activationManifestStore) Activate(_ context.Context, manifest publication.Manifest) error { + s.activateCalls++ + s.activated = manifest + return s.activateErr +} + +type activationReleaseStore struct { + execution dataframepublication.BundleExecution + pointer dataframepublication.BundlePointer + getErr error + pointerErr error +} + +func (s *activationReleaseStore) GetExecution(context.Context, string) (dataframepublication.BundleExecution, error) { + if s.getErr != nil { + return dataframepublication.BundleExecution{}, s.getErr + } + return s.execution, nil +} + +func (s *activationReleaseStore) GetPointer(context.Context, string) (dataframepublication.BundlePointer, error) { + if s.pointerErr != nil { + return dataframepublication.BundlePointer{}, s.pointerErr + } + return s.pointer, nil +} + +func TestRunGenerationPropagatesDeferActivationAndResult(t *testing.T) { + runner := &activationCapturingRunner{} + svc, err := NewService(ServiceConfig{GenerationRunner: runner}) + if err != nil { + t.Fatal(err) + } + for _, deferred := range []bool{false, true} { + result, err := svc.RunGeneration(context.Background(), GenerationLoadRequest{Project: "project-a", Generation: "generation-a", StagedDir: t.TempDir(), DeferActivation: deferred}) + if err != nil { + t.Fatal(err) + } + if runner.request.DeferActivation != deferred { + t.Fatalf("runner request DeferActivation = %v, want %v", runner.request.DeferActivation, deferred) + } + if result.Activated == deferred { + t.Fatalf("result Activated = %v for DeferActivation=%v", result.Activated, deferred) + } + } +} + +type activationCapturingRunner struct { + request GenerationLoadRequest + calls int +} + +func (r *activationCapturingRunner) RunGeneration(_ context.Context, request GenerationLoadRequest, _ ingest.EventSink) (ingest.LoadSummary, error) { + r.calls++ + r.request = request + return ingest.LoadSummary{}, nil +} + +func TestRunGenerationReusesReadyManifest(t *testing.T) { + runner := &activationCapturingRunner{} + manifest := activationManifest(t, "project-a", "generation-a") + store := &activationManifestStore{manifest: manifest} + svc, err := NewService(ServiceConfig{GenerationRunner: runner, GenerationActivator: store}) + if err != nil { + t.Fatal(err) + } + result, err := svc.RunGeneration(context.Background(), GenerationLoadRequest{ + Project: "project-a", Generation: "generation-a", StagedDir: t.TempDir(), DeferActivation: true, + }) + if err != nil { + t.Fatal(err) + } + if !result.Reused || result.Activated { + t.Fatalf("result = %#v, want reused and inactive", result) + } + if runner.calls != 0 { + t.Fatalf("runner calls = %d, want 0", runner.calls) + } +} + +func TestRunGenerationLoadsWhenManifestDoesNotExist(t *testing.T) { + runner := &activationCapturingRunner{} + store := &activationManifestStore{readErr: fmt.Errorf("lookup: %w", publication.ErrManifestNotFound)} + svc, err := NewService(ServiceConfig{GenerationRunner: runner, GenerationActivator: store}) + if err != nil { + t.Fatal(err) + } + result, err := svc.RunGeneration(context.Background(), GenerationLoadRequest{ + Project: "project-a", Generation: "generation-a", StagedDir: t.TempDir(), DeferActivation: true, + }) + if err != nil { + t.Fatal(err) + } + if result.Reused || runner.calls != 1 { + t.Fatalf("result reused = %v, runner calls = %d; want false, 1", result.Reused, runner.calls) + } +} + +func TestRunGenerationRejectsManifestLookupFailure(t *testing.T) { + runner := &activationCapturingRunner{} + store := &activationManifestStore{readErr: errors.New("database unavailable")} + svc, err := NewService(ServiceConfig{GenerationRunner: runner, GenerationActivator: store}) + if err != nil { + t.Fatal(err) + } + _, err = svc.RunGeneration(context.Background(), GenerationLoadRequest{ + Project: "project-a", Generation: "generation-a", StagedDir: t.TempDir(), DeferActivation: true, + }) + if err == nil || runner.calls != 0 { + t.Fatalf("error = %v, runner calls = %d; want lookup failure and no load", err, runner.calls) + } +} + +func TestActivateGenerationRejectsInvalidDataframeRelease(t *testing.T) { + readyManifest := activationManifest(t, "project-a", "generation-a") + base := dataframepublication.BundleExecution{ + ID: "release-1", BundleIdentity: dataframepublication.BundleIdentity{Project: "project-a", DatasetGeneration: "generation-a", Name: "all"}, + State: dataframepublication.BundleReady, UpdatedAt: time.Now().UTC(), + Outputs: []dataframepublication.BundleOutputRecord{ + {Name: "Patient", State: dataframepublication.BundleReady}, + {Name: "Observation", State: dataframepublication.BundleReady}, + }, + } + tests := []struct { + name string + mutate func(*dataframepublication.BundleExecution, *dataframepublication.BundlePointer) + }{ + {name: "mismatched project", mutate: func(execution *dataframepublication.BundleExecution, _ *dataframepublication.BundlePointer) { + execution.Project = "project-b" + }}, + {name: "mismatched generation", mutate: func(execution *dataframepublication.BundleExecution, _ *dataframepublication.BundlePointer) { + execution.DatasetGeneration = "generation-b" + }}, + {name: "bundle not ready", mutate: func(execution *dataframepublication.BundleExecution, _ *dataframepublication.BundlePointer) { + execution.State = dataframepublication.BundleLoading + }}, + {name: "output not ready", mutate: func(execution *dataframepublication.BundleExecution, _ *dataframepublication.BundlePointer) { + execution.Outputs[1].State = dataframepublication.BundleLoading + }}, + {name: "pointer mismatch", mutate: func(_ *dataframepublication.BundleExecution, pointer *dataframepublication.BundlePointer) { + pointer.ExecutionID = "another-release" + }}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + execution := base + execution.Outputs = append([]dataframepublication.BundleOutputRecord(nil), base.Outputs...) + pointer := dataframepublication.BundlePointer{Name: execution.PointerName(), ExecutionID: execution.ID} + test.mutate(&execution, &pointer) + activator := &activationManifestStore{manifest: readyManifest} + releases := &activationReleaseStore{execution: execution, pointer: pointer} + svc, err := NewService(ServiceConfig{GenerationRunner: activationGenerationRunner{}, GenerationActivator: activator, DataframeReleases: releases}) + if err != nil { + t.Fatal(err) + } + if err := svc.ActivateGeneration(context.Background(), "project-a", "generation-a", execution.ID); err == nil { + t.Fatal("ActivateGeneration() unexpectedly succeeded") + } + if activator.readCalls != 0 || activator.activateCalls != 0 { + t.Fatalf("manifest calls = read %d activate %d, want no activation", activator.readCalls, activator.activateCalls) + } + }) + } +} + +func TestActivateGenerationActivatesReadyAllOutputBundle(t *testing.T) { + manifest := activationManifest(t, "project-a", "generation-a") + execution := dataframepublication.BundleExecution{ + ID: "release-1", BundleIdentity: dataframepublication.BundleIdentity{Project: "project-a", DatasetGeneration: "generation-a", Name: "all"}, + State: dataframepublication.BundleReady, UpdatedAt: time.Now().UTC(), + Outputs: []dataframepublication.BundleOutputRecord{ + {Name: "Patient", State: dataframepublication.BundleReady}, + {Name: "Observation", State: dataframepublication.BundleReady}, + }, + } + activator := &activationManifestStore{manifest: manifest} + calledSuccess := false + svc, err := NewService(ServiceConfig{ + GenerationRunner: activationGenerationRunner{}, + GenerationActivator: activator, + DataframeReleases: &activationReleaseStore{execution: execution, pointer: dataframepublication.BundlePointer{Name: execution.PointerName(), ExecutionID: execution.ID}}, + OnSuccess: func(string) { calledSuccess = true }, + }) + if err != nil { + t.Fatal(err) + } + if err := svc.ActivateGeneration(context.Background(), "project-a", "generation-a", execution.ID); err != nil { + t.Fatal(err) + } + if activator.readCalls != 1 || activator.activateCalls != 1 || !calledSuccess { + t.Fatalf("activation calls = read %d activate %d success %v", activator.readCalls, activator.activateCalls, calledSuccess) + } + if activator.activated.Dataset != manifest.Dataset || !activator.activated.IsReady() { + t.Fatalf("activated manifest = %#v", activator.activated) + } +} + +func activationManifest(t *testing.T, project, generation string) publication.Manifest { + t.Helper() + ref, err := publication.NewRef(project, generation) + if err != nil { + t.Fatal(err) + } + schema, err := publication.NewSchemaSnapshot("urn:test", "R5", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", []string{"Patient"}) + if err != nil { + t.Fatal(err) + } + manifest, err := publication.NewManifest(ref, schema) + if err != nil { + t.Fatal(err) + } + manifest, err = manifest.Transition(publication.StateReady) + if err != nil { + t.Fatal(err) + } + return manifest +} diff --git a/internal/api/graphql/graph/materialization/output.go b/internal/api/graphql/graph/materialization/output.go index 7143f06d..935e4b4e 100644 --- a/internal/api/graphql/graph/materialization/output.go +++ b/internal/api/graphql/graph/materialization/output.go @@ -6,6 +6,7 @@ import ( "github.com/calypr/loom/generated/graphql/graph/model" dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" + publication "github.com/calypr/loom/internal/dataframe/publication" materialization "github.com/calypr/loom/internal/dataframe/published" ) @@ -19,8 +20,7 @@ func Model(value materialization.Materialization) *model.DataframeMaterializatio if column.Name == "auth_resource_path" || column.Name == "__loom_row_id" { continue } - logical, nullable, repeated, filterable, sortable, aggregatable := columnCapabilities(column.ClickHouse) - columns = append(columns, &model.DataframeColumn{Name: column.Name, ClickhouseType: column.ClickHouse, LogicalType: logical, Nullable: nullable, Repeated: repeated, Filterable: filterable, Sortable: sortable, Aggregatable: aggregatable}) + columns = append(columns, ColumnModel(column)) } var readyAt *string if value.ReadyAt != nil { @@ -35,6 +35,7 @@ func Model(value materialization.Materialization) *model.DataframeMaterializatio } result := &model.DataframeMaterialization{ ID: value.ID, Name: value.Name, Revision: revision, + ProjectID: value.Project, DatasetGeneration: value.DatasetGeneration, State: model.DataframeMaterializationState(value.State), Columns: columns, RowCount: rowCount, CreatedAt: value.CreatedAt.UTC().Format("2006-01-02T15:04:05.999Z07:00"), @@ -90,6 +91,27 @@ func projectStatusModels(values []materialization.ProjectStatus) []*model.Datafr return result } +// ColumnFromPhysical adapts candidate execution metadata before activation. +// It intentionally mirrors the published materialization representation while +// retaining semantic identity for browser-side configuration. +func ColumnFromPhysical(column publication.PhysicalColumn) *model.DataframeColumn { + return ColumnModel(materialization.Column{Name: column.Name, SemanticPath: column.SemanticPath, ClickHouse: column.ClickHouse, LogicalType: column.LogicalType, Nullable: column.Nullable, Repeated: column.Repeated}) +} + +func ColumnModel(column materialization.Column) *model.DataframeColumn { + logical, nullable, repeated, filterable, sortable, aggregatable := columnCapabilities(column.ClickHouse) + if column.LogicalType != "" { + logical = column.LogicalType + } + if column.Nullable { + nullable = true + } + if column.Repeated { + repeated = true + } + return &model.DataframeColumn{SemanticPath: column.SemanticPath, Name: column.Name, ClickhouseType: column.ClickHouse, LogicalType: logical, Nullable: nullable, Repeated: repeated, Filterable: filterable, Sortable: sortable, Aggregatable: aggregatable} +} + func PersistedFailure(raw, code string, retryable bool) (message, failureCode *string, failureRetryable *bool) { if code == "" && raw == "" { return nil, nil, nil diff --git a/internal/api/graphql/graph/materialization/service.go b/internal/api/graphql/graph/materialization/service.go index 888ef03c..5800b1ac 100644 --- a/internal/api/graphql/graph/materialization/service.go +++ b/internal/api/graphql/graph/materialization/service.go @@ -129,6 +129,46 @@ func (s *Service) Datasets(ctx context.Context) ([]dfmaterialization.Materializa return result, nil } +// ProjectDatasets exposes the exact active-generation schemas for one +// authorized project. It intentionally does not federate across projects. +func (s *Service) ProjectDatasets(ctx context.Context, projectID string) ([]dfmaterialization.Materialization, error) { + if s.reader == nil { + return nil, readerUnavailable() + } + projectID = strings.TrimSpace(projectID) + if projectID == "" { + return nil, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") + } + principal, err := s.principal(ctx) + if err != nil { + return nil, err + } + if len(principal.Projects) > 0 && !containsProject(principal.Projects, projectID) { + return nil, dataframeerrors.NewError(dataframeerrors.CodeUnauthorizedProject, "") + } + values, err := s.reader.CurrentProjectDatasets(ctx, projectID) + if err != nil { + return nil, mapReaderError(err) + } + for _, value := range values { + if s.scopeResolver != nil { + if _, scopeErr := s.scopeResolver.ResolveReadScopeForGeneration(ctx, principal, value.Project, value.DatasetGeneration, nil); scopeErr != nil { + return nil, mapReaderError(scopeErr) + } + } + } + return values, nil +} + +func containsProject(projects []string, project string) bool { + for _, value := range projects { + if strings.TrimSpace(value) == project { + return true + } + } + return false +} + // Get preserves the legacy published-materialization lookup by ID. func (s *Service) Get(ctx context.Context, id string) (*dfmaterialization.Materialization, error) { if s.reader == nil { diff --git a/internal/api/graphql/graph/query/recipe_discovery.go b/internal/api/graphql/graph/query/recipe_discovery.go index 6687ed4e..59df6f1d 100644 --- a/internal/api/graphql/graph/query/recipe_discovery.go +++ b/internal/api/graphql/graph/query/recipe_discovery.go @@ -46,6 +46,13 @@ func (d recipeFieldDiscovery) Fields(ctx context.Context, scope schema.Scope, re DistinctValues: append([]string(nil), field.DistinctValues...), DistinctTruncated: field.DistinctTruncated, PivotCandidate: field.PivotCandidate, PivotFamily: field.PivotFamily, PivotColumns: append([]string(nil), field.PivotColumns...), PivotColumnSelect: field.PivotColumnSelect, PivotValueSelect: field.PivotValueSelect, + ExtensionValues: func() []schema.ExtensionValueObservation { + values := make([]schema.ExtensionValueObservation, len(field.ExtensionValues)) + for i, value := range field.ExtensionValues { + values[i] = schema.ExtensionValueObservation{URL: value.URL, SourcePath: value.SourcePath, ValuePath: value.ValuePath, ValueType: value.ValueType, URLPath: append([]string(nil), value.URLPath...)} + } + return values + }(), }) } return result, nil diff --git a/internal/api/graphql/graph/resolver/recipe_control_graphql.go b/internal/api/graphql/graph/resolver/recipe_control_graphql.go index b6e7baee..e5f1302a 100644 --- a/internal/api/graphql/graph/resolver/recipe_control_graphql.go +++ b/internal/api/graphql/graph/resolver/recipe_control_graphql.go @@ -323,6 +323,11 @@ func executionModel(value RecipeExecution) *model.DataframeRecipeExecution { for _, output := range value.Outputs { errorText, errorCode, errorRetryable := materializationapi.PersistedFailure(output.Error, output.ErrorCode, output.ErrorRetryable) item := &model.DataframeRecipeExecutionOutput{Name: output.Name, State: model.DataframeRecipeExecutionState(output.State), RowCount: output.RowCount, Error: errorText, ErrorCode: errorCode, ErrorRetryable: errorRetryable} + columns := make([]*model.DataframeColumn, 0, len(output.Columns)) + for _, column := range output.Columns { + columns = append(columns, materializationapi.ColumnFromPhysical(column)) + } + item.Columns = columns if output.Selector.Valid() { item.Selector = &model.DataframeSelector{Recipe: output.Selector.Recipe, TranslationVersion: output.Selector.TranslationVersion, Output: output.Selector.Output} } diff --git a/internal/api/graphql/graph/resolver/recipe_execution_reader.go b/internal/api/graphql/graph/resolver/recipe_execution_reader.go index 6d596ef8..d9fdaee9 100644 --- a/internal/api/graphql/graph/resolver/recipe_execution_reader.go +++ b/internal/api/graphql/graph/resolver/recipe_execution_reader.go @@ -65,7 +65,7 @@ func NewAuthorizedRecipeExecutionReader(store RecipeExecutionStore, scopeResolve } rowCount := int(output.RowCount) result.Outputs = append(result.Outputs, RecipeExecutionOutput{ - Name: output.Name, State: outputState, RowCount: &rowCount, Error: execution.Error, + Name: output.Name, State: outputState, RowCount: &rowCount, Columns: append([]materialization.PhysicalColumn(nil), output.Columns...), Error: execution.Error, ErrorCode: output.FailureCode, ErrorRetryable: output.FailureRetryable, Selector: output.Selector, Phase: output.FailurePhase, }) diff --git a/internal/api/graphql/graph/resolver/recipe_revision_model.go b/internal/api/graphql/graph/resolver/recipe_revision_model.go new file mode 100644 index 00000000..c4994447 --- /dev/null +++ b/internal/api/graphql/graph/resolver/recipe_revision_model.go @@ -0,0 +1,17 @@ +package resolver + +import ( + "encoding/json" + + "github.com/calypr/loom/generated/graphql/graph/model" + "github.com/calypr/loom/internal/dataframe/recipe" +) + +func recipeRevisionModel(value recipe.RecipeRevision) *model.DataframeRecipeRevision { + canonical, _ := json.Marshal(value.Bundle) + var parent *string + if value.Parent != "" { + parent = &value.Parent + } + return &model.DataframeRecipeRevision{ProjectID: value.Project, Name: value.Name, Digest: value.Digest, ParentDigest: parent, Recipe: canonical, CreatedAt: value.CreatedAt.UTC().Format("2006-01-02T15:04:05.999Z07:00")} +} diff --git a/internal/api/graphql/graph/resolver/resolver.go b/internal/api/graphql/graph/resolver/resolver.go index cc98b3b0..66ba5031 100644 --- a/internal/api/graphql/graph/resolver/resolver.go +++ b/internal/api/graphql/graph/resolver/resolver.go @@ -8,6 +8,7 @@ import ( "github.com/calypr/loom/generated/graphql/graph/model" materializationapi "github.com/calypr/loom/internal/api/graphql/graph/materialization" queryapi "github.com/calypr/loom/internal/api/graphql/graph/query" + publication "github.com/calypr/loom/internal/dataframe/publication" materialization "github.com/calypr/loom/internal/dataframe/published" "github.com/calypr/loom/internal/dataframe/recipe" "github.com/calypr/loom/internal/dataframe/recipe/engine" @@ -50,6 +51,7 @@ type RecipeExecutionOutput struct { Name string State string RowCount *int + Columns []publication.PhysicalColumn Error string ErrorCode string ErrorRetryable bool @@ -89,6 +91,7 @@ type Resolver struct { projectReleaseActivator ProjectReleaseActivator dataframeContractPromoter DataframeContractPromoter dataframeContractAuthorizer DataframeContractAuthorizer + recipeRevisions recipe.RevisionStore } type ResolverConfig struct { @@ -107,6 +110,7 @@ type ResolverConfig struct { DataframeContractPromoter DataframeContractPromoter DataframeContractAuthorizer DataframeContractAuthorizer CandidateProjects func(context.Context) ([]string, error) + RecipeRevisions recipe.RevisionStore } func NewResolver(cfg ResolverConfig) *Resolver { @@ -135,6 +139,7 @@ func NewResolver(cfg ResolverConfig) *Resolver { projectReleaseActivator: cfg.ProjectReleaseActivator, dataframeContractPromoter: cfg.DataframeContractPromoter, dataframeContractAuthorizer: cfg.DataframeContractAuthorizer, + recipeRevisions: cfg.RecipeRevisions, } } @@ -158,7 +163,7 @@ func recipeBindings(input model.DataframeRecipeBindingsInput) recipe.RuntimeBind limit = *input.PreviewLimit } return recipe.RuntimeBindings{ - Project: input.Project, DatasetGeneration: valueOrEmpty(input.DatasetGeneration), + Project: input.Project, RecipeDigest: valueOrEmpty(input.RecipeDigest), DatasetGeneration: valueOrEmpty(input.DatasetGeneration), AuthResourcePaths: append([]string(nil), input.AuthResourcePaths...), PreviewLimit: limit, } } diff --git a/internal/api/graphql/graph/resolver/schema.resolvers.go b/internal/api/graphql/graph/resolver/schema.resolvers.go index f6f7457f..2aea813b 100644 --- a/internal/api/graphql/graph/resolver/schema.resolvers.go +++ b/internal/api/graphql/graph/resolver/schema.resolvers.go @@ -8,6 +8,7 @@ package resolver import ( "context" "encoding/json" + "fmt" "strings" "github.com/calypr/loom/generated/graphql/graph/executor" @@ -202,6 +203,29 @@ func (r *mutationResolver) PromoteDataframeContract(ctx context.Context, input m return &model.DataframeContract{Recipe: contract.Recipe, TranslationVersion: contract.TranslationVersion, PromotedAt: contract.PromotedAt}, nil } +// RegisterDataframeRecipeRevision is the resolver for the registerDataframeRecipeRevision field. +func (r *mutationResolver) RegisterDataframeRecipeRevision(ctx context.Context, input model.RegisterDataframeRecipeRevisionInput) (*model.DataframeRecipeRevision, error) { + if r.recipeRevisions == nil { + return nil, recipeGraphQLError(fmt.Errorf("recipe revision store is unavailable")) + } + if _, err := r.authorizeRecipeWrite(ctx, recipe.RuntimeBindings{Project: input.ProjectID}); err != nil { + return nil, recipeGraphQLError(err) + } + var bundle recipe.Bundle + if err := json.Unmarshal(input.Recipe, &bundle); err != nil { + return nil, recipeGraphQLError(err) + } + parent := "" + if input.ParentDigest != nil { + parent = *input.ParentDigest + } + value, err := r.recipeRevisions.Register(ctx, input.ProjectID, bundle, parent) + if err != nil { + return nil, recipeGraphQLError(err) + } + return recipeRevisionModel(value), nil +} + // DataframeBuilderIntrospection is the resolver for the dataframeBuilderIntrospection field. func (r *queryResolver) DataframeBuilderIntrospection(ctx context.Context, input model.DataframeBuilderIntrospectionInput) (*model.DataframeBuilderIntrospection, error) { includePivotOnlyFields := true @@ -251,6 +275,11 @@ func (r *queryResolver) DataframeDatasets(ctx context.Context) ([]*model.Datafra return result, nil } +// ProjectDataframeDatasets is the resolver for the projectDataframeDatasets field. +func (r *queryResolver) ProjectDataframeDatasets(ctx context.Context, projectID string) ([]*model.DataframeMaterialization, error) { + panic(fmt.Errorf("not implemented: ProjectDataframeDatasets - projectDataframeDatasets")) +} + // DataframeDataset is the resolver for the dataframeDataset field. func (r *queryResolver) DataframeDataset(ctx context.Context, input model.DataframeDatasetInput) (*model.DataframeMaterialization, error) { value, err := r.materializations.Dataset(ctx, input) @@ -323,6 +352,40 @@ func (r *queryResolver) DataframeRecipeExecution(ctx context.Context, id string) return executionModel(*execution), nil } +// DataframeRecipeRevision is the resolver for the dataframeRecipeRevision field. +func (r *queryResolver) DataframeRecipeRevision(ctx context.Context, projectID string, name string, digest string) (*model.DataframeRecipeRevision, error) { + if r.recipeRevisions == nil { + return nil, nil + } + if _, err := r.authorizeRecipeRead(ctx, recipe.RuntimeBindings{Project: projectID}); err != nil { + return nil, recipeGraphQLError(err) + } + value, err := r.recipeRevisions.Get(ctx, projectID, name, digest) + if err != nil { + return nil, recipeGraphQLError(err) + } + return recipeRevisionModel(value), nil +} + +// DataframeRecipeRevisions is the resolver for the dataframeRecipeRevisions field. +func (r *queryResolver) DataframeRecipeRevisions(ctx context.Context, projectID string, name string) ([]*model.DataframeRecipeRevision, error) { + if r.recipeRevisions == nil { + return []*model.DataframeRecipeRevision{}, nil + } + if _, err := r.authorizeRecipeRead(ctx, recipe.RuntimeBindings{Project: projectID}); err != nil { + return nil, recipeGraphQLError(err) + } + values, err := r.recipeRevisions.List(ctx, projectID, name) + if err != nil { + return nil, recipeGraphQLError(err) + } + result := make([]*model.DataframeRecipeRevision, 0, len(values)) + for _, value := range values { + result = append(result, recipeRevisionModel(value)) + } + return result, nil +} + // ExplainDataframeRecipe is the resolver for the explainDataframeRecipe field. func (r *queryResolver) ExplainDataframeRecipe(ctx context.Context, input model.ExplainDataframeRecipeInput) (*model.DataframeRecipeExplanation, error) { bindings, err := graphqlRecipeBindings(input.Bindings) diff --git a/internal/api/graphql/graph/schema/schema.graphqls b/internal/api/graphql/graph/schema/schema.graphqls index 662af5ea..3d3652dc 100644 --- a/internal/api/graphql/graph/schema/schema.graphqls +++ b/internal/api/graphql/graph/schema/schema.graphqls @@ -5,11 +5,14 @@ type Query { dataframeMaterialization(id: ID!): DataframeMaterialization dataframeDatasets: [DataframeMaterialization!]! + projectDataframeDatasets(projectId: String!): [DataframeMaterialization!]! dataframeDataset(input: DataframeDatasetInput!): DataframeMaterialization dataframeRows(input: DataframeRowsInput!): DataframeRowConnection! dataframeAggregate(input: DataframeAggregateInput!): DataframeAggregateResult! dataframeAggregations(input: DataframeAggregationsInput!): DataframeAggregationsResult! dataframeRecipeExecution(id: ID!): DataframeRecipeExecution + dataframeRecipeRevision(projectId: String!, name: String!, digest: String!): DataframeRecipeRevision + dataframeRecipeRevisions(projectId: String!, name: String!): [DataframeRecipeRevision!]! explainDataframeRecipe(input: ExplainDataframeRecipeInput!): DataframeRecipeExplanation! preflightDataframeRecipe(input: PreflightDataframeRecipeInput!): DataframeRecipePreflight! fhirGraph(input: FhirGraphQueryInput!): FhirGraphQueryResult! @@ -30,6 +33,7 @@ type Mutation { startDataframeMaterialization(input: StartDataframeMaterializationInput!): DataframeRecipeExecution! activateProjectRelease(input: ActivateProjectReleaseInput!): ProjectRelease! promoteDataframeContract(input: PromoteDataframeContractInput!): DataframeContract! + registerDataframeRecipeRevision(input: RegisterDataframeRecipeRevisionInput!): DataframeRecipeRevision! } input StartDataframeMaterializationInput { @@ -65,8 +69,25 @@ type DataframeContract { promotedAt: String! } +input RegisterDataframeRecipeRevisionInput { + projectId: String! + name: String! + parentDigest: String + recipe: JSON! +} + +type DataframeRecipeRevision { + projectId: String! + name: String! + digest: String! + parentDigest: String + recipe: JSON! + createdAt: String! +} + input DataframeRecipeBindingsInput { project: String! + recipeDigest: String datasetGeneration: String authResourcePaths: [String!] previewLimit: Int = 25 @@ -314,6 +335,7 @@ type DataframeRecipeExecutionOutput { name: String! state: DataframeRecipeExecutionState! rowCount: Int + columns: [DataframeColumn!]! error: String errorCode: String errorRetryable: Boolean @@ -329,6 +351,7 @@ enum DataframeMaterializationState { } type DataframeColumn { + semanticPath: String! name: String! clickhouseType: String! logicalType: String! @@ -343,6 +366,8 @@ type DataframeMaterialization { id: ID! name: String! revision: String! + projectId: String! + datasetGeneration: String! state: DataframeMaterializationState! columns: [DataframeColumn!]! rowCount: Int diff --git a/internal/api/http/recipe_execution.go b/internal/api/http/recipe_execution.go new file mode 100644 index 00000000..1f6a7736 --- /dev/null +++ b/internal/api/http/recipe_execution.go @@ -0,0 +1,86 @@ +package httpapi + +import ( + "errors" + "net/http" + "strings" + + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/dataframe/publication" + "github.com/gofiber/fiber/v3" +) + +// RegisterRecipeExecutionRoute exposes candidate schema metadata without +// exposing physical table names. Authentication is provided by HTTPServer's +// middleware; project/scope authorization is checked against the execution. +func RegisterRecipeExecutionRoute(app *fiber.App, catalog publication.BundleCatalog, scopes *authscope.ScopeResolver) { + if app == nil || catalog == nil { + return + } + app.Get("/api/v1/dataframe/recipe-executions/:id", func(c fiber.Ctx) error { + id := strings.TrimSpace(c.Params("id")) + execution, err := catalog.GetExecution(c.Context(), id) + if err != nil || execution.ID == "" { + return c.Status(http.StatusNotFound).JSON(fiber.Map{"error": "recipe execution not found"}) + } + if scopes != nil { + principal, _ := authscope.PrincipalFromContext(c.Context()) + if _, scopeErr := scopes.ResolveReadScopeForGeneration(c.Context(), principal, execution.Project, execution.DatasetGeneration, execution.AuthResourcePaths); scopeErr != nil { + status := http.StatusForbidden + if errors.Is(scopeErr, authscope.ErrUnauthenticated) { + status = http.StatusUnauthorized + } + return c.Status(status).JSON(fiber.Map{"error": "recipe execution not found"}) + } + } + outputs := make([]fiber.Map, 0, len(execution.Outputs)) + for _, output := range execution.Outputs { + columns := make([]fiber.Map, 0, len(output.Columns)) + for _, column := range output.Columns { + logical, nullable, repeated, filterable, sortable, aggregatable := columnCapabilities(column.ClickHouse) + if column.LogicalType != "" { + logical = column.LogicalType + } + if column.Nullable { + nullable = true + } + if column.Repeated { + repeated = true + } + columns = append(columns, fiber.Map{"name": column.Name, "semanticPath": column.SemanticPath, "clickhouseType": column.ClickHouse, "logicalType": logical, "nullable": nullable, "repeated": repeated, "filterable": filterable, "sortable": sortable, "aggregatable": aggregatable}) + } + outputs = append(outputs, fiber.Map{"name": output.Name, "dataType": output.Name, "state": string(output.State), "rowCount": output.RowCount, "columns": columns}) + } + return c.JSON(fiber.Map{"id": execution.ID, "projectId": execution.Project, "datasetGeneration": execution.DatasetGeneration, "recipeDigest": execution.RecipeDigest, "schemaDigest": execution.SchemaDigest, "resolvedSchemaDigest": execution.SchemaDigest, "state": string(execution.State), "outputs": outputs}) + }) +} + +func columnCapabilities(clickHouseType string) (logical string, nullable, repeated, filterable, sortable, aggregatable bool) { + typ := clickHouseType + if strings.HasPrefix(typ, "Nullable(") && strings.HasSuffix(typ, ")") { + nullable = true + typ = strings.TrimSuffix(strings.TrimPrefix(typ, "Nullable("), ")") + } + if strings.HasPrefix(typ, "Array(") && strings.HasSuffix(typ, ")") { + repeated = true + typ = strings.TrimSuffix(strings.TrimPrefix(typ, "Array("), ")") + } + switch { + case strings.HasPrefix(typ, "Bool"): + logical = "boolean" + case strings.HasPrefix(typ, "Int") || strings.HasPrefix(typ, "UInt"): + logical = "integer" + case strings.HasPrefix(typ, "Float") || strings.HasPrefix(typ, "Decimal"): + logical = "number" + case strings.HasPrefix(typ, "Date"): + logical = "date" + case strings.HasPrefix(typ, "String") || strings.HasPrefix(typ, "FixedString") || strings.HasPrefix(typ, "UUID"): + logical = "string" + default: + logical = "json" + } + filterable = true + sortable = !repeated + aggregatable = !repeated && logical != "json" + return +} diff --git a/internal/catalog/arango/store.go b/internal/catalog/arango/store.go index 6f58cece..d8ee306f 100644 --- a/internal/catalog/arango/store.go +++ b/internal/catalog/arango/store.go @@ -231,6 +231,36 @@ func decodeStrings(value any) ([]string, error) { } } +func decodeExtensionValues(value any) ([]catalog.ExtensionValueObservation, error) { + if value == nil { + return nil, nil + } + items, ok := value.([]any) + if !ok { + if typed, ok := value.([]map[string]any); ok { + items = make([]any, len(typed)) + for i := range typed { + items[i] = typed[i] + } + } else { + return nil, fmt.Errorf("unsupported extension observation slice type %T", value) + } + } + result := make([]catalog.ExtensionValueObservation, 0, len(items)) + for i, item := range items { + row, ok := item.(map[string]any) + if !ok { + return nil, fmt.Errorf("unsupported extension observation type %T at index %d", item, i) + } + urlPath, err := decodeStrings(row["url_path"]) + if err != nil { + return nil, fmt.Errorf("extension observation URL path: %w", err) + } + result = append(result, catalog.ExtensionValueObservation{URL: stringValue(row["url"]), SourcePath: stringValue(row["source_path"]), ValuePath: stringValue(row["value_path"]), ValueType: stringValue(row["value_type"]), URLPath: urlPath}) + } + return result, nil +} + func decode(row map[string]any, out *catalog.PopulatedField) error { out.Project = stringValue(row["project"]) out.DatasetGeneration = stringValue(row["dataset_generation"]) @@ -262,6 +292,9 @@ func decode(row map[string]any, out *catalog.PopulatedField) error { if out.PivotValueSelectors, err = decodeStrings(row["pivot_value_selectors"]); err != nil { return fmt.Errorf("decode field row %s/%s pivot_value_selectors: %w", out.ResourceType, out.Path, err) } + if out.ExtensionValues, err = decodeExtensionValues(row["extension_values"]); err != nil { + return fmt.Errorf("decode field row %s/%s extension_values: %w", out.ResourceType, out.Path, err) + } out.PivotKind = stringValue(row["pivot_kind"]) out.PivotFamily = stringValue(row["pivot_family"]) out.PivotColumnSelect = stringValue(row["pivot_column_selector"]) @@ -290,6 +323,7 @@ FOR d IN fhir_field_catalog sample_count: d.sample_count, distinct_values: d.distinct_values, distinct_truncated: d.distinct_truncated, + extension_values: d.extension_values, pivot_candidate: d.pivot_candidate, pivot_kind: d.pivot_kind, pivot_columns: d.pivot_columns, diff --git a/internal/catalog/arango/store_test.go b/internal/catalog/arango/store_test.go index 2c091ecb..16d48c1e 100644 --- a/internal/catalog/arango/store_test.go +++ b/internal/catalog/arango/store_test.go @@ -53,6 +53,7 @@ func TestStorePreservesFieldMetadataAndRejectsMalformedRows(t *testing.T) { "pivot_kind": "code", "pivot_columns": []any{"A"}, "pivot_family": "family", "pivot_column_selector": "coding.display", "pivot_value_selector": "coding.code", "pivot_item_source": "item", "pivot_item_resource_type": "Observation", "pivot_value_selectors": []any{"code"}, + "extension_values": []any{map[string]any{"url": "http://example.org/source_path", "source_path": "extension[]", "value_path": "valueUrl", "value_type": "string"}}, }} adapter, err := New(client) if err != nil { @@ -63,7 +64,7 @@ func TestStorePreservesFieldMetadataAndRejectsMalformedRows(t *testing.T) { t.Fatal(err) } field := fields[0] - if !field.PivotCandidate || field.PivotKind != "code" || len(field.DistinctValues) != 1 || field.PivotItemResourceType != "Observation" { + if !field.PivotCandidate || field.PivotKind != "code" || len(field.DistinctValues) != 1 || field.PivotItemResourceType != "Observation" || len(field.ExtensionValues) != 1 || field.ExtensionValues[0].ValuePath != "valueUrl" { t.Fatalf("field metadata = %#v", field) } diff --git a/internal/catalog/cache.go b/internal/catalog/cache.go index 430d7dac..2f07602c 100644 --- a/internal/catalog/cache.go +++ b/internal/catalog/cache.go @@ -154,6 +154,12 @@ func cloneFields(in []PopulatedField) []PopulatedField { if in[i].PivotColumns != nil { out[i].PivotColumns = append([]string(nil), in[i].PivotColumns...) } + if in[i].ExtensionValues != nil { + out[i].ExtensionValues = append([]ExtensionValueObservation(nil), in[i].ExtensionValues...) + for j := range out[i].ExtensionValues { + out[i].ExtensionValues[j].URLPath = append([]string(nil), in[i].ExtensionValues[j].URLPath...) + } + } } return out } diff --git a/internal/catalog/cache_test.go b/internal/catalog/cache_test.go index e1a3c6ea..0c875c93 100644 --- a/internal/catalog/cache_test.go +++ b/internal/catalog/cache_test.go @@ -41,6 +41,26 @@ func TestCacheDiscoverFieldsCachesAndInvalidatesByProject(t *testing.T) { } } +func TestCacheClonesExtensionObservations(t *testing.T) { + cache := NewCache() + value := PopulatedField{ResourceType: "DocumentReference", Path: "extension[].url", ExtensionValues: []ExtensionValueObservation{{URL: "u", SourcePath: "extension[]", ValuePath: "valueString", ValueType: "string"}}} + discover := cache.DiscoverFields(func(context.Context, PopulatedFieldOptions) ([]PopulatedField, error) { + return []PopulatedField{value}, nil + }) + first, err := discover(context.Background(), PopulatedFieldOptions{Project: "P1", ResourceType: "DocumentReference"}) + if err != nil { + t.Fatal(err) + } + first[0].ExtensionValues[0].URL = "mutated" + second, err := discover(context.Background(), PopulatedFieldOptions{Project: "P1", ResourceType: "DocumentReference"}) + if err != nil { + t.Fatal(err) + } + if second[0].ExtensionValues[0].URL != "u" { + t.Fatalf("cached extension observation mutated: %#v", second[0].ExtensionValues) + } +} + func TestCacheDiscoverReferencesSeparatesAuthScopes(t *testing.T) { cache := NewCache() calls := 0 diff --git a/internal/catalog/types.go b/internal/catalog/types.go index 7aaf76e3..6a2b4496 100644 --- a/internal/catalog/types.go +++ b/internal/catalog/types.go @@ -27,24 +27,40 @@ type FieldCatalogDocument struct { // produced this catalog row. An omitted value is intentionally the legacy // dataset namespace; readers always bind either this exact value or null so // legacy and generation-qualified observations never mix. - DatasetGeneration string `json:"dataset_generation,omitempty"` - AuthResourcePath string `json:"auth_resource_path,omitempty"` - ResourceType string `json:"resource_type"` - Path string `json:"path"` - Kind string `json:"kind"` - DocCount int64 `json:"doc_count"` - SampleCount int `json:"sample_count"` - DistinctValues []string `json:"distinct_values,omitempty"` - DistinctTruncated bool `json:"distinct_truncated"` - PivotCandidate bool `json:"pivot_candidate"` - PivotKind string `json:"pivot_kind,omitempty"` - PivotColumns []string `json:"pivot_columns,omitempty"` - PivotFamily string `json:"pivot_family,omitempty"` - PivotColumnSelect string `json:"pivot_column_selector,omitempty"` - PivotValueSelect string `json:"pivot_value_selector,omitempty"` - PivotItemSource string `json:"pivot_item_source,omitempty"` - PivotItemResourceType string `json:"pivot_item_resource_type,omitempty"` - PivotValueSelectors []string `json:"pivot_value_selectors,omitempty"` + DatasetGeneration string `json:"dataset_generation,omitempty"` + AuthResourcePath string `json:"auth_resource_path,omitempty"` + ResourceType string `json:"resource_type"` + Path string `json:"path"` + Kind string `json:"kind"` + DocCount int64 `json:"doc_count"` + SampleCount int `json:"sample_count"` + DistinctValues []string `json:"distinct_values,omitempty"` + DistinctTruncated bool `json:"distinct_truncated"` + ExtensionValues []ExtensionValueObservation `json:"extension_values,omitempty"` + PivotCandidate bool `json:"pivot_candidate"` + PivotKind string `json:"pivot_kind,omitempty"` + PivotColumns []string `json:"pivot_columns,omitempty"` + PivotFamily string `json:"pivot_family,omitempty"` + PivotColumnSelect string `json:"pivot_column_selector,omitempty"` + PivotValueSelect string `json:"pivot_value_selector,omitempty"` + PivotItemSource string `json:"pivot_item_source,omitempty"` + PivotItemResourceType string `json:"pivot_item_resource_type,omitempty"` + PivotValueSelectors []string `json:"pivot_value_selectors,omitempty"` +} + +// ExtensionValueObservation preserves the correlation between an Extension +// URL and the concrete value[x] member observed on the same object. Keeping +// this pairing in the catalog avoids independently combining unrelated URL +// and value distinct-value sets during recipe schema discovery. +type ExtensionValueObservation struct { + URL string `json:"url"` + SourcePath string `json:"source_path"` + ValuePath string `json:"value_path"` + ValueType string `json:"value_type"` + // URLPath contains ancestor Extension URLs for nested extensions. It is + // empty for top-level extensions and lets recipe discovery avoid leaf-name + // collisions while retaining deterministic parent__child names. + URLPath []string `json:"url_path,omitempty"` } // Read-side field discovery request and response types. @@ -66,25 +82,26 @@ type PopulatedFieldOptions struct { } type PopulatedField struct { - Project string `json:"project"` - DatasetGeneration string `json:"dataset_generation,omitempty"` - AuthResourcePath string `json:"auth_resource_path,omitempty"` - ResourceType string `json:"resource_type"` - Path string `json:"path"` - Kind string `json:"kind"` - DocCount int64 `json:"doc_count"` - SampleCount int `json:"sample_count"` - DistinctValues []string `json:"distinct_values,omitempty"` - DistinctTruncated bool `json:"distinct_truncated"` - PivotCandidate bool `json:"pivot_candidate"` - PivotKind string `json:"pivot_kind,omitempty"` - PivotColumns []string `json:"pivot_columns,omitempty"` - PivotFamily string `json:"pivot_family,omitempty"` - PivotColumnSelect string `json:"pivot_column_selector,omitempty"` - PivotValueSelect string `json:"pivot_value_selector,omitempty"` - PivotItemSource string `json:"pivot_item_source,omitempty"` - PivotItemResourceType string `json:"pivot_item_resource_type,omitempty"` - PivotValueSelectors []string `json:"pivot_value_selectors,omitempty"` + Project string `json:"project"` + DatasetGeneration string `json:"dataset_generation,omitempty"` + AuthResourcePath string `json:"auth_resource_path,omitempty"` + ResourceType string `json:"resource_type"` + Path string `json:"path"` + Kind string `json:"kind"` + DocCount int64 `json:"doc_count"` + SampleCount int `json:"sample_count"` + DistinctValues []string `json:"distinct_values,omitempty"` + DistinctTruncated bool `json:"distinct_truncated"` + ExtensionValues []ExtensionValueObservation `json:"extension_values,omitempty"` + PivotCandidate bool `json:"pivot_candidate"` + PivotKind string `json:"pivot_kind,omitempty"` + PivotColumns []string `json:"pivot_columns,omitempty"` + PivotFamily string `json:"pivot_family,omitempty"` + PivotColumnSelect string `json:"pivot_column_selector,omitempty"` + PivotValueSelect string `json:"pivot_value_selector,omitempty"` + PivotItemSource string `json:"pivot_item_source,omitempty"` + PivotItemResourceType string `json:"pivot_item_resource_type,omitempty"` + PivotValueSelectors []string `json:"pivot_value_selectors,omitempty"` } // Read-side auth path discovery request type. @@ -168,6 +185,8 @@ type fieldCatalogStats struct { pivotItemSource string pivotItemResourceType string pivotValueSelectors []string + extensionValues []ExtensionValueObservation + extensionValueSet map[string]struct{} } // Shared write-side shape planning cache. diff --git a/internal/catalog/write_profiler.go b/internal/catalog/write_profiler.go index f428a609..43b3a82e 100644 --- a/internal/catalog/write_profiler.go +++ b/internal/catalog/write_profiler.go @@ -68,6 +68,7 @@ func (p *Profiler) ObservePayload(payload map[string]any, timings map[string]flo } } p.observeObservationCodePivot(payload) + p.observeExtensionValues(payload) timings["field_profile"] += time.Since(observeStart).Seconds() } @@ -136,6 +137,7 @@ func (p *Profiler) Merge(other *Profiler) error { pivotValueSelectors: append([]string(nil), otherStat.pivotValueSelectors...), distinctSet: make(map[string]struct{}), pivotColumnSet: make(map[string]struct{}), + extensionValueSet: make(map[string]struct{}), } p.stats[path] = stat } @@ -149,6 +151,9 @@ func (p *Profiler) Merge(other *Profiler) error { for _, value := range otherStat.pivotColumns { stat.addPivotColumn(value) } + for _, observation := range otherStat.extensionValues { + stat.addExtensionValue(observation) + } } return nil } @@ -165,8 +170,21 @@ func (p *Profiler) Documents() []FieldCatalogDocument { stat := p.stats[path] distinctValues := append([]string(nil), stat.distinctValues...) pivotColumns := append([]string(nil), stat.pivotColumns...) + extensionValues := append([]ExtensionValueObservation(nil), stat.extensionValues...) slices.Sort(distinctValues) slices.Sort(pivotColumns) + sort.Slice(extensionValues, func(i, j int) bool { + if extensionValues[i].URL != extensionValues[j].URL { + return extensionValues[i].URL < extensionValues[j].URL + } + if strings.Join(extensionValues[i].URLPath, "\x00") != strings.Join(extensionValues[j].URLPath, "\x00") { + return strings.Join(extensionValues[i].URLPath, "\x00") < strings.Join(extensionValues[j].URLPath, "\x00") + } + if extensionValues[i].SourcePath != extensionValues[j].SourcePath { + return extensionValues[i].SourcePath < extensionValues[j].SourcePath + } + return extensionValues[i].ValuePath < extensionValues[j].ValuePath + }) out = append(out, FieldCatalogDocument{ Key: fieldCatalogKeyForGeneration(p.project, datasetGeneration, p.authResourcePath, p.resourceType, stat.path), Project: p.project, @@ -188,6 +206,7 @@ func (p *Profiler) Documents() []FieldCatalogDocument { PivotItemSource: stat.pivotItemSource, PivotItemResourceType: stat.pivotItemResourceType, PivotValueSelectors: append([]string(nil), stat.pivotValueSelectors...), + ExtensionValues: extensionValues, }) } return out @@ -198,12 +217,13 @@ func (p *Profiler) ensureStat(field *fieldPlan) *fieldCatalogStats { return stat } stat := &fieldCatalogStats{ - path: field.Path, - kind: field.Kind, - pivotCandidate: field.PivotCandidate, - pivotKind: field.PivotKind, - distinctSet: make(map[string]struct{}), - pivotColumnSet: make(map[string]struct{}), + path: field.Path, + kind: field.Kind, + pivotCandidate: field.PivotCandidate, + pivotKind: field.PivotKind, + distinctSet: make(map[string]struct{}), + pivotColumnSet: make(map[string]struct{}), + extensionValueSet: make(map[string]struct{}), } if field.PivotCandidate { if spec, ok := fhirschema.DefaultPivotSpec(p.resourceType, field.Path, ""); ok { @@ -243,6 +263,109 @@ func (s *fieldCatalogStats) addPivotColumn(value string) { s.pivotColumns = append(s.pivotColumns, value) } +func (s *fieldCatalogStats) addExtensionValue(observation ExtensionValueObservation) { + observation.URL = strings.TrimSpace(observation.URL) + observation.SourcePath = strings.TrimSpace(observation.SourcePath) + observation.ValuePath = strings.TrimSpace(observation.ValuePath) + observation.ValueType = strings.TrimSpace(observation.ValueType) + if observation.URL == "" || observation.SourcePath == "" || observation.ValueType == "" { + return + } + if s.extensionValueSet == nil { + s.extensionValueSet = make(map[string]struct{}) + } + key := observation.URL + "\x00" + strings.Join(observation.URLPath, "\x00") + "\x00" + observation.SourcePath + "\x00" + observation.ValuePath + "\x00" + observation.ValueType + if _, ok := s.extensionValueSet[key]; ok { + return + } + s.extensionValueSet[key] = struct{}{} + s.extensionValues = append(s.extensionValues, observation) +} + +func (p *Profiler) observeExtensionValues(payload map[string]any) { + walkExtensionValues(payload, "", p) +} + +func walkExtensionValues(value any, path string, profiler *Profiler) { + walkExtensionValuesWithAncestors(value, path, profiler, nil) +} + +func walkExtensionValuesWithAncestors(value any, path string, profiler *Profiler, ancestors []string) { + switch typed := value.(type) { + case map[string]any: + isExtension := strings.HasSuffix(path, "extension[]") + if url, ok := typed["url"].(string); ok && strings.TrimSpace(url) != "" && isExtension { + stat := profiler.ensureExtensionURLStat(path + ".url") + for key, raw := range typed { + if !strings.HasPrefix(key, "value") || len(key) == len("value") || raw == nil { + continue + } + valuePath, valueType := extensionValueMapping(key, raw) + stat.addExtensionValue(ExtensionValueObservation{URL: url, SourcePath: path, ValuePath: valuePath, ValueType: valueType, URLPath: append([]string(nil), ancestors...)}) + } + } + for _, key := range sortedKeys(typed) { + child := typed[key] + if child == nil { + continue + } + childPath := appendPath(path, key, false) + if _, ok := child.([]any); ok { + childPath = appendPath(path, key, true) + } + nextAncestors := ancestors + if key == "extension" && isExtension { + if url, ok := typed["url"].(string); ok && strings.TrimSpace(url) != "" { + nextAncestors = append(append([]string(nil), ancestors...), strings.TrimSpace(url)) + } + } + walkExtensionValuesWithAncestors(child, childPath, profiler, nextAncestors) + } + case []any: + for _, item := range typed { + if item != nil { + walkExtensionValuesWithAncestors(item, path, profiler, ancestors) + } + } + } +} + +func (p *Profiler) ensureExtensionURLStat(path string) *fieldCatalogStats { + if stat, ok := p.stats[path]; ok { + return stat + } + stat := &fieldCatalogStats{path: path, kind: fieldKindScalar, distinctSet: make(map[string]struct{}), pivotColumnSet: make(map[string]struct{}), extensionValueSet: make(map[string]struct{})} + p.stats[path] = stat + return stat +} + +func extensionValueMapping(path string, value any) (string, string) { + // FHIR complex value[x] payloads and arrays require lossless JSON fallback; + // an empty value path is the resolver's explicit canonical-JSON marker. + switch value.(type) { + case map[string]any, []any: + return "", "string" + } + suffix := strings.TrimPrefix(path, "value") + switch suffix { + case "Integer", "PositiveInt", "UnsignedInt", "Integer64": + return path, "integer" + case "Decimal": + return path, "decimal" + case "Boolean": + return path, "boolean" + case "Date": + return path, "date" + case "DateTime": + return path, "date_time" + default: + if _, ok := scalarStringValue(value); ok { + return path, "string" + } + return "", "string" + } +} + func (s *fieldCatalogStats) setPivotDefaults(family string, columnSelector string, valueSelector string) { if strings.TrimSpace(family) != "" { s.pivotFamily = family diff --git a/internal/catalog/write_profiler_test.go b/internal/catalog/write_profiler_test.go index 44be01ec..9c2993bb 100644 --- a/internal/catalog/write_profiler_test.go +++ b/internal/catalog/write_profiler_test.go @@ -80,6 +80,32 @@ func TestFieldCatalogProfilerCanonicalPaths(t *testing.T) { } } +func TestFieldCatalogProfilerCorrelatesExtensionValuesRecursively(t *testing.T) { + profiler := NewProfilerForGeneration("TEST", "generation-1", "pathA", "DocumentReference", NewShapePlanCache()) + profiler.ObservePayload(map[string]any{ + "content": []any{map[string]any{ + "attachment": map[string]any{"url": "file:///not-an-extension-url", "extension": []any{map[string]any{ + "url": "http://example.org/source_path", + "valueUrl": "https://source.example/file", + "extension": []any{map[string]any{"url": "http://example.org/sha256", "valueString": "abc123"}}, + }}}, + }}, + }, map[string]float64{}) + + byPath := make(map[string]FieldCatalogDocument) + for _, document := range profiler.Documents() { + byPath[document.Path] = document + } + outer := byPath["content[].attachment.extension[].url"] + if len(outer.ExtensionValues) != 1 || !reflect.DeepEqual(outer.ExtensionValues[0], ExtensionValueObservation{URL: "http://example.org/source_path", SourcePath: "content[].attachment.extension[]", ValuePath: "valueUrl", ValueType: "string"}) { + t.Fatalf("outer extension observations = %#v", outer.ExtensionValues) + } + inner := byPath["content[].attachment.extension[].extension[].url"] + if len(inner.ExtensionValues) != 1 || inner.ExtensionValues[0].SourcePath != "content[].attachment.extension[].extension[]" || inner.ExtensionValues[0].ValuePath != "valueString" { + t.Fatalf("nested extension observations = %#v", inner.ExtensionValues) + } +} + func TestFieldCatalogProfilerSkipsLoomMetadata(t *testing.T) { profiler := NewProfilerForGeneration("TEST", "", "pathA", "Patient", NewShapePlanCache()) profiler.ObservePayload(map[string]any{ diff --git a/internal/dataframe/compiler/ir/physical_validation_expr.go b/internal/dataframe/compiler/ir/physical_validation_expr.go index 4cc5c108..f70fd660 100644 --- a/internal/dataframe/compiler/ir/physical_validation_expr.go +++ b/internal/dataframe/compiler/ir/physical_validation_expr.go @@ -235,7 +235,8 @@ func validatePhysicalCall(call PhysicalCall, defined map[string]bool, bindVars m } known := map[string]bool{ "coalesce": true, "coalesce_string": true, "fallback": true, "first": true, "all": true, "distinct": true, - "concat": true, "join": true, "cast": true, "reference_id": true, + "canonical_json": true, + "concat": true, "join": true, "cast": true, "reference_id": true, "path_segment": true, "basename": true, "last_segment": true, "sanitize_name": true, "sanitize_graphql_name": true, "uuid3": true, "uuid5": true, "if": true, "case": true, "not": true, "and": true, "or": true, diff --git a/internal/dataframe/compiler/lower/recipe_compile.go b/internal/dataframe/compiler/lower/recipe_compile.go index 3fd50471..39a196b3 100644 --- a/internal/dataframe/compiler/lower/recipe_compile.go +++ b/internal/dataframe/compiler/lower/recipe_compile.go @@ -60,19 +60,25 @@ type CompiledRecipeOutput struct { // Cardinality are logical, backend-neutral values; Internal projections are // never exposed by dataframe transports. type CompiledOutputColumn struct { - Name string - Kind string - Cardinality string - Nullable bool - Internal bool - Identity bool + Name string + // SemanticPath is the stable FHIR/provenance identity for this column. + // Physical names are deliberately excluded so storage renames do not + // invalidate Explorer configuration. + SemanticPath string + Kind string + Cardinality string + Nullable bool + Internal bool + Identity bool } type DynamicColumnMetadata struct { - Name string - DynamicName string - SourceKey string - ValueType string + Name string + SemanticPath string + DynamicName string + SourceKey string + ValueType string + AllowUnknownKeys bool } // CompileResolvedRecipePlan lowers every resolved recipe output into the @@ -157,7 +163,10 @@ func compileRecipeOutput(output semantic.OutputPlan, bindings recipe.RuntimeBind if err := physical.Validate(); err != nil { return CompiledRecipeOutput{}, fmt.Errorf("validate canonical physical plan: %w", err) } - outputSchema := recipeOutputSchema(physical, output) + outputSchema, err := recipeOutputSchema(physical, output, dynamicMetadata) + if err != nil { + return CompiledRecipeOutput{}, err + } return CompiledRecipeOutput{ Name: output.Name, RootResourceType: output.RootResourceType, RowGrain: output.RowGrain, Columns: physicalOutputColumns(outputSchema), OutputSchema: outputSchema, diff --git a/internal/dataframe/compiler/lower/recipe_dynamic_columns.go b/internal/dataframe/compiler/lower/recipe_dynamic_columns.go index 980c563a..10b74f16 100644 --- a/internal/dataframe/compiler/lower/recipe_dynamic_columns.go +++ b/internal/dataframe/compiler/lower/recipe_dynamic_columns.go @@ -38,7 +38,6 @@ func appendRecipeDynamicColumns(plan *ir.PhysicalPlan, output semantic.OutputPla projectionIndexes[projection.Name] = index } metadata := make([]DynamicColumnMetadata, 0) - metadataIndexes := map[string]int{} runtimeKeyFields := make([]ir.PhysicalExpressionProjection, 0, len(dynamics)) setVariables := recipeSetVariables(*plan) for _, dynamic := range dynamics { @@ -104,7 +103,17 @@ func appendRecipeDynamicColumns(plan *ir.PhysicalPlan, output semantic.OutputPla matchBindKey := nextDynamicBindKey(plan.BindVars, projectionPrefix+dynamic.Name, index) plan.BindVars[matchBindKey] = column.Column.SourceKey lookup := ir.PhysicalExpression{Kind: ir.PhysicalObjectLookupExpression, Cardinality: value.Cardinality, NullBehavior: value.NullBehavior, ObjectLookup: &ir.PhysicalObjectLookup{ObjectVariable: familyVariable, KeyBindKey: matchBindKey}} - entry := DynamicColumnMetadata{Name: outputName, DynamicName: runtimeName, SourceKey: column.Column.SourceKey, ValueType: column.Column.ValueType} + semanticPath := strings.TrimSpace(dynamic.ResourceType) + if semanticPath == "" { + semanticPath = output.RootResourceType + } + if source := strings.Trim(strings.TrimSpace(dynamic.Source.SourcePath), "."); source != "" { + semanticPath += "." + source + } + if column.Column.SourceKey != "" { + semanticPath += "[" + column.Column.SourceKey + "]" + } + entry := DynamicColumnMetadata{Name: outputName, SemanticPath: semanticPath, DynamicName: runtimeName, SourceKey: column.Column.SourceKey, ValueType: column.Column.ValueType, AllowUnknownKeys: dynamic.AllowUnknownKeys} if projectionIndex, exists := projectionIndexes[outputName]; exists { if output.Collision != "overwrite" { return nil, fmt.Errorf("dynamic column %q collides with another output column", outputName) @@ -113,17 +122,15 @@ func appendRecipeDynamicColumns(plan *ir.PhysicalPlan, output semantic.OutputPla // order. Preserve that contract for an explicit overwrite policy // instead of rejecting a category/identifier or extension collision. plan.Operations[returnOp].Return.Projections[projectionIndex] = ir.PhysicalProjection{Name: outputName, Expression: &lookup} - if metadataIndex, dynamicExists := metadataIndexes[outputName]; dynamicExists { - metadata[metadataIndex] = entry - } else { - metadataIndexes[outputName] = len(metadata) - metadata = append(metadata, entry) - } + // Keep validation metadata for every family sharing this public + // compatibility column. The physical projection is intentionally + // overwritten in declaration order, but runtime-key validation must + // still accept keys frozen for the earlier family. + metadata = append(metadata, entry) continue } projectionIndexes[outputName] = len(plan.Operations[returnOp].Return.Projections) plan.Operations[returnOp].Return.Projections = append(plan.Operations[returnOp].Return.Projections, ir.PhysicalProjection{Name: outputName, Expression: &lookup}) - metadataIndexes[outputName] = len(metadata) metadata = append(metadata, entry) } } @@ -204,6 +211,9 @@ func lowerDynamicItemExpression(input semantic.SemanticExpression, bindVars map[ // resource type carried by the dynamic map. Re-validating it against the // parent schema would reject valid generic choice fields. func lowerDynamicItemAST(input expression.Expression, bindVars map[string]any, resourceType string) (ir.PhysicalExpression, error) { + if input.Document != nil && strings.EqualFold(strings.TrimSpace(input.Document.Context), "item") { + return ir.PhysicalExpression{Kind: ir.PhysicalValueExpression, Cardinality: ir.PhysicalObjectCardinality, NullBehavior: ir.PhysicalPreserveNull, Value: &ir.PhysicalValue{Variable: "dynamic_item"}}, nil + } if input.Selector != nil && strings.EqualFold(strings.TrimSpace(input.Selector.Context), "item") { selector, err := spec.ParseSelector(input.Selector.Path) if err != nil { diff --git a/internal/dataframe/compiler/lower/recipe_output_test.go b/internal/dataframe/compiler/lower/recipe_output_test.go index 0b7e90ab..2df20acd 100644 --- a/internal/dataframe/compiler/lower/recipe_output_test.go +++ b/internal/dataframe/compiler/lower/recipe_output_test.go @@ -40,6 +40,19 @@ func TestCompileResolvedRecipePlanProducesCanonicalPhysicalPlans(t *testing.T) { if output.Plan.Operations[0].Kind != ir.PhysicalRootScanOp { t.Fatalf("output %q first operation = %s, want ROOT_SCAN", output.Name, output.Plan.Operations[0].Kind) } + semanticPaths := map[string]string{} + for _, column := range output.OutputSchema { + if column.Internal { + continue + } + if column.SemanticPath == "" { + t.Fatalf("output %q column %q has no semantic path", output.Name, column.Name) + } + if previous, exists := semanticPaths[column.SemanticPath]; exists { + t.Fatalf("output %q columns %q and %q share semantic path %q", output.Name, previous, column.Name, column.SemanticPath) + } + semanticPaths[column.SemanticPath] = column.Name + } } } @@ -264,6 +277,84 @@ func TestCompileResolvedRecipePlanLowersDynamicItemLookup(t *testing.T) { t.Fatal("dynamic item lookup projection not found") } +func TestCompileExtensionColumnsPreservesAttachmentValuesAndNestedJSON(t *testing.T) { + emptyPrefix := "" + bundle := recipe.Bundle{RecipeSchemaVersion: 1, Name: "attachment-extensions", TranslationVersion: "test", Outputs: []recipe.Output{{ + Name: "DocumentReference", RootResourceType: "DocumentReference", RowGrain: "file", + ExtensionColumns: []recipe.ExtensionColumn{{ + Name: "attachment", ColumnPrefix: &emptyPrefix, MaxColumns: 8, + Source: recipe.Expression{Select: "root.content[].attachment.extension[]"}, + Columns: []recipe.ExtensionColumnMapping{ + {Name: "source_path", URL: "http://example.org/source_path", SourcePath: "content[].attachment.extension[]", ValuePath: "valueUrl", ValueType: "string"}, + {Name: "source_path__sha256", URL: "http://example.org/sha256", SourcePath: "content[].attachment.extension[].extension[]", ValuePath: "valueString", ValueType: "string"}, + {Name: "complex", URL: "http://example.org/complex", SourcePath: "content[].attachment.extension[]", ValueType: "string"}, + }, + }}, + }}} + plan, err := semantic.BuildRecipePlan(bundle, recipe.RuntimeBindings{Project: "project", DatasetGeneration: "generation"}) + if err != nil { + t.Fatal(err) + } + resolved, err := semantic.ResolveRecipePlan(plan, "scope", "generation") + if err != nil { + t.Fatal(err) + } + compiled, err := CompileResolvedRecipePlan(resolved, ir.DefaultPhysicalOptimizationPolicy()) + if err != nil { + t.Fatal(err) + } + if len(compiled.Outputs) != 1 { + t.Fatalf("compiled outputs = %d", len(compiled.Outputs)) + } + output := compiled.Outputs[0] + if len(output.DynamicColumns) != 3 { + t.Fatalf("dynamic metadata = %#v", output.DynamicColumns) + } + metadata := map[string]DynamicColumnMetadata{} + for _, column := range output.DynamicColumns { + metadata[column.Name] = column + } + if metadata["source_path"].DynamicName != "attachment__source_path" || metadata["source_path__sha256"].DynamicName != "attachment__source_path__sha256" || metadata["source_path__sha256"].SourceKey != "sha256" || !metadata["source_path"].AllowUnknownKeys || !metadata["source_path__sha256"].AllowUnknownKeys { + t.Fatalf("nested extension metadata = %#v", metadata) + } + var maps []ir.PhysicalKeyedMap + for _, operation := range output.Plan.Operations { + if operation.Kind == ir.PhysicalExpressionLetOp && operation.ExpressionLet != nil && operation.ExpressionLet.Expression.KeyedMap != nil { + maps = append(maps, *operation.ExpressionLet.Expression.KeyedMap) + } + } + if len(maps) != 3 { + t.Fatalf("keyed maps = %d", len(maps)) + } + seenScalar, seenNested, seenJSON := false, false, false + for _, keyed := range maps { + if keyed.ItemValue.Value != nil && len(keyed.ItemValue.Value.Path) == 1 { + switch keyed.ItemValue.Value.Path[0] { + case "valueUrl": + seenScalar = true + case "valueString": + seenNested = true + } + } + if keyed.ItemValue.Call != nil && keyed.ItemValue.Call.Name == "canonical_json" { + seenJSON = true + } + } + if !seenScalar || !seenNested || !seenJSON { + t.Fatalf("extension values were not lowered independently: scalar=%v nested=%v json=%v", seenScalar, seenNested, seenJSON) + } + if err := output.Plan.Validate(); err != nil { + t.Fatalf("extension plan validation: %v", err) + } + rendered, err := aql.RenderPhysicalPlan(output.Plan) + if err != nil { + t.Fatal(err) + } + if !strings.Contains(rendered.Query, "__loom_postquery_call") || strings.Contains(rendered.Query, "JSON_STRINGIFY") { + t.Fatalf("complex extension was not deferred to canonical post-query JSON: %s", rendered.Query) + } +} + func TestCompileResolvedRecipePlanOverwritesCollidingCompatibilityDynamicColumns(t *testing.T) { emptyPrefix := "" bundle := recipe.Bundle{RecipeSchemaVersion: 1, Name: "legacy-dynamic", TranslationVersion: "test", Outputs: []recipe.Output{{ @@ -293,7 +384,7 @@ func TestCompileResolvedRecipePlanOverwritesCollidingCompatibilityDynamicColumns if err != nil { t.Fatal(err) } - if got := compiled.Outputs[0].DynamicColumns; len(got) != 1 || got[0].Name != "HTAN_DATA_FILE_ID" || got[0].DynamicName != "category_keys" { + if got := compiled.Outputs[0].DynamicColumns; len(got) != 2 || got[0].Name != "HTAN_DATA_FILE_ID" || got[0].DynamicName != "identifier_keys" || got[1].Name != "HTAN_DATA_FILE_ID" || got[1].DynamicName != "category_keys" { t.Fatalf("dynamic overwrite metadata = %#v", got) } count := 0 diff --git a/internal/dataframe/compiler/lower/recipe_schema.go b/internal/dataframe/compiler/lower/recipe_schema.go index b6dd65f1..a34ed88b 100644 --- a/internal/dataframe/compiler/lower/recipe_schema.go +++ b/internal/dataframe/compiler/lower/recipe_schema.go @@ -5,6 +5,7 @@ package lower // ir.PhysicalPlan used by the GraphQL dataframe compiler. import ( + "fmt" "strings" "github.com/calypr/loom/internal/dataframe/compiler/ir" @@ -48,18 +49,25 @@ func cloneRecipeNodeForPhysical(node semantic.SemanticNode) semantic.SemanticNod // identity and bounded dynamic projections have been appended. Semantic // metadata is used only to enrich those already-finalized projections with // logical type/cardinality information. -func recipeOutputSchema(plan ir.PhysicalPlan, output semantic.OutputPlan) []CompiledOutputColumn { +func recipeOutputSchema(plan ir.PhysicalPlan, output semantic.OutputPlan, dynamicMetadata []DynamicColumnMetadata) ([]CompiledOutputColumn, error) { logical := make(map[string]CompiledOutputColumn) - addLogical := func(name, kind, cardinality string, nullable bool) { + for _, dynamic := range dynamicMetadata { + kind := dynamic.ValueType + if kind == "" || kind == "unknown" { + kind = string(expression.KindString) + } + logical[dynamic.Name] = CompiledOutputColumn{Name: dynamic.Name, SemanticPath: dynamic.SemanticPath, Kind: kind, Cardinality: string(expression.OptionalOne), Nullable: true} + } + addLogical := func(name, semanticPath, kind, cardinality string, nullable bool) { if strings.TrimSpace(name) == "" { return } if _, exists := logical[name]; exists { return } - logical[name] = CompiledOutputColumn{Name: name, Kind: kind, Cardinality: cardinality, Nullable: nullable} + logical[name] = CompiledOutputColumn{Name: name, SemanticPath: semanticPath, Kind: kind, Cardinality: cardinality, Nullable: nullable} } - addType := func(name string, typ expression.Type) { + addType := func(name, semanticPath string, typ expression.Type) { kind := string(typ.Kind) if kind == "" { kind = string(expression.KindString) @@ -68,23 +76,23 @@ func recipeOutputSchema(plan ir.PhysicalPlan, output semantic.OutputPlan) []Comp if cardinality == "" { cardinality = string(expression.RequiredOne) } - addLogical(name, kind, cardinality, typ.Cardinality.Optional()) + addLogical(name, semanticPath, kind, cardinality, typ.Cardinality.Optional()) } for _, field := range output.Fields { - addType(field.Name, field.Expr.Type) + addType(field.Name, recipeSemanticPath(output.RootResourceType, output.RootResourceType, field.FieldRef, field.Expr.Expression), field.Expr.Type) } var addNode func(semantic.SemanticNode, string) addNode = func(node semantic.SemanticNode, prefix string) { for _, field := range node.Fields { name := prefix + field.Name if field.Expr != nil { - addType(name, field.ExprType) + addType(name, recipeSemanticPath(output.RootResourceType, node.ResourceType, field.FieldRef, *field.Expr), field.ExprType) } else { - addLogical(name, string(expression.KindString), string(expression.RequiredOne), true) + addLogical(name, recipeSemanticPath(output.RootResourceType, node.ResourceType, field.FieldRef, expression.Expression{}), string(expression.KindString), string(expression.RequiredOne), true) } } for _, aggregate := range node.Aggregates { - addLogical(prefix+aggregate.Name, string(expression.KindInteger), string(expression.RequiredOne), true) + addLogical(prefix+aggregate.Name, recipeSemanticPath(output.RootResourceType, node.ResourceType, aggregate.FieldRef, expression.Expression{}), string(expression.KindInteger), string(expression.RequiredOne), true) } for _, pivot := range node.Pivots { kind := pivot.ValueKind @@ -92,11 +100,11 @@ func recipeOutputSchema(plan ir.PhysicalPlan, output semantic.OutputPlan) []Comp kind = expression.KindString } for _, column := range pivot.Columns { - addLogical(prefix+pivot.Name+"__"+sanitizeColumnName(column), string(kind), string(expression.RequiredOne), true) + addLogical(prefix+pivot.Name+"__"+sanitizeColumnName(column), recipeSemanticPath(output.RootResourceType, node.ResourceType, pivot.FieldRef, expression.Expression{})+"["+column+"]", string(kind), string(expression.RequiredOne), true) } } for _, slice := range node.Slices { - addLogical(prefix+slice.Name, string(expression.KindObject), string(expression.RequiredOne), true) + addLogical(prefix+slice.Name, recipeSemanticPath(output.RootResourceType, node.ResourceType, "", expression.Expression{})+"."+slice.Name, string(expression.KindObject), string(expression.RequiredOne), true) } for _, child := range node.Children { childPrefix := child.Alias @@ -116,7 +124,7 @@ func recipeOutputSchema(plan ir.PhysicalPlan, output semantic.OutputPlan) []Comp for _, projection := range operation.Return.Projections { column, ok := logical[projection.Name] if !ok { - column = CompiledOutputColumn{Name: projection.Name, Kind: string(expression.KindString), Cardinality: string(expression.RequiredOne), Nullable: true} + column = CompiledOutputColumn{Name: projection.Name, SemanticPath: "recipe:" + output.Name + "/" + projection.Name, Kind: string(expression.KindString), Cardinality: string(expression.RequiredOne), Nullable: true} } if projection.Expression != nil { if column.Cardinality == string(expression.RequiredOne) && projection.Expression.Cardinality == ir.PhysicalArrayCardinality { @@ -132,9 +140,52 @@ func recipeOutputSchema(plan ir.PhysicalPlan, output semantic.OutputPlan) []Comp column.Identity = projection.Name == "_key" || projection.Name == "__loom_row_id" result = append(result, column) } - return result + semanticCounts := make(map[string]int, len(result)) + for _, column := range result { + if column.Internal { + continue + } + path := strings.TrimSpace(column.SemanticPath) + if path == "" { + return nil, fmt.Errorf("output %q column %q has no semantic identity", output.Name, column.Name) + } + semanticCounts[path]++ + } + // Legacy recipes may intentionally project the same FHIR value more than + // once. Keep those columns addressable by qualifying the ambiguous source + // with the authored projection name. New recipes should use fieldRef when + // they need rename-stable identities for such duplicate projections. + for index := range result { + if !result[index].Internal && semanticCounts[result[index].SemanticPath] > 1 { + result[index].SemanticPath += "#" + result[index].Name + } + } + return result, nil + } + return nil, nil +} + +// recipeSemanticPath produces a storage-independent identity. Explicit +// fieldRef values are frontend/catalog provenance and are retained verbatim; +// selector expressions fall back to resource type plus normalized FHIR path. +func recipeSemanticPath(rootResource, resource, fieldRef string, expr expression.Expression) string { + ref := strings.TrimSpace(fieldRef) + if ref != "" { + return strings.TrimPrefix(ref, ".") + } + if expr.Selector != nil { + path := strings.Trim(strings.TrimSpace(expr.Selector.Path), ".") + if path != "" { + if strings.Contains(path, ".") && strings.HasPrefix(path, resource+".") { + return path + } + return strings.TrimSpace(resource) + "." + path + } + } + if strings.TrimSpace(resource) == "" { + return strings.TrimSpace(rootResource) } - return nil + return strings.TrimSpace(resource) } func physicalOutputColumns(schema []CompiledOutputColumn) []string { diff --git a/internal/dataframe/compiler/lower/recipe_semantic_path_test.go b/internal/dataframe/compiler/lower/recipe_semantic_path_test.go new file mode 100644 index 00000000..d2476c7b --- /dev/null +++ b/internal/dataframe/compiler/lower/recipe_semantic_path_test.go @@ -0,0 +1,20 @@ +package lower + +import ( + "testing" + + "github.com/calypr/loom/internal/dataframe/expression" +) + +func TestRecipeSemanticPathUsesProvenanceAndNotPhysicalNames(t *testing.T) { + if got := recipeSemanticPath("Patient", "Patient", "Patient.case_id", expression.Expression{}); got != "Patient.case_id" { + t.Fatalf("explicit semantic path = %q", got) + } + expr := expression.Expression{Selector: &expression.SelectorRef{Path: "identifier[].value"}} + if got := recipeSemanticPath("Patient", "Patient", "", expr); got != "Patient.identifier[].value" { + t.Fatalf("selector semantic path = %q", got) + } + if got := recipeSemanticPath("ResearchSubject", "Patient", "", expr); got != "Patient.identifier[].value" { + t.Fatalf("nested semantic path = %q", got) + } +} diff --git a/internal/dataframe/compiler/render/aql/calls.go b/internal/dataframe/compiler/render/aql/calls.go index bf9960ab..05c755d8 100644 --- a/internal/dataframe/compiler/render/aql/calls.go +++ b/internal/dataframe/compiler/render/aql/calls.go @@ -22,6 +22,12 @@ func (r *physicalPlanRenderer) renderCall(expression ir.PhysicalExpression) (str } args[index] = value } + if name == "canonical_json" { + if len(args) != 1 { + return "", fmt.Errorf("canonical_json requires 1 argument, got %d", len(args)) + } + return fmt.Sprintf("{\"__loom_postquery_call\": %q, \"__loom_postquery_args\": [%s]}", name, strings.Join(args, ", ")), nil + } if nestedUUID { return fmt.Sprintf("{\"__loom_postquery_call\": %q, \"__loom_postquery_target\": %q, \"__loom_postquery_args\": [%s]}", name, call.TargetKind, strings.Join(args, ", ")), nil } diff --git a/internal/dataframe/expression/expression_checking.go b/internal/dataframe/expression/expression_checking.go index 52fde0e6..6c588f95 100644 --- a/internal/dataframe/expression/expression_checking.go +++ b/internal/dataframe/expression/expression_checking.go @@ -191,6 +191,12 @@ func (s *checkState) checkCall(c Call, path string, depth int) (Type, error) { } func inferCall(name string, args []Type, target *Type) (Type, error) { + if name == "canonical_json" { + if len(args) != 1 || args[0].Cardinality == Many { + return Type{}, fmt.Errorf("canonical_json requires one scalar value") + } + return Type{Kind: KindString, Cardinality: OptionalOne}, nil + } if name == "coalesce_string" { if len(args) == 0 { return Type{}, fmt.Errorf("coalesce_string requires at least one argument") diff --git a/internal/dataframe/publication/bundle.go b/internal/dataframe/publication/bundle.go index 26df9b21..4a6b3f1b 100644 --- a/internal/dataframe/publication/bundle.go +++ b/internal/dataframe/publication/bundle.go @@ -117,8 +117,12 @@ func (o BundleOutputRecord) Queryable() bool { } type PhysicalColumn struct { - Name string `json:"name"` - ClickHouse string `json:"clickhouseType"` + Name string `json:"name"` + SemanticPath string `json:"semanticPath,omitempty"` + ClickHouse string `json:"clickhouseType"` + LogicalType string `json:"logicalType,omitempty"` + Nullable bool `json:"nullable,omitempty"` + Repeated bool `json:"repeated,omitempty"` } type BundleExecution struct { diff --git a/internal/dataframe/publication/clickhouse/bundle_store.go b/internal/dataframe/publication/clickhouse/bundle_store.go index 46375b00..30b55136 100644 --- a/internal/dataframe/publication/clickhouse/bundle_store.go +++ b/internal/dataframe/publication/clickhouse/bundle_store.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "regexp" + "sort" "strings" "sync" "time" @@ -295,6 +296,40 @@ func (t *clickHouseBundleTx) CreateOutput(ctx context.Context, name string, colu return t.save(ctx) } +// SetOutputMetadata persists semantic schema alongside the physical table +// definition. The optional transaction method preserves compatibility with +// existing AtomicBundleTx implementations and test fakes. +func (t *clickHouseBundleTx) SetOutputMetadata(name string, columns []publication.LogicalColumn) error { + if t.idempotent { + return nil + } + if t.closed { + return fmt.Errorf("bundle transaction is closed") + } + idx := t.outputIndex(name) + if idx < 0 { + return fmt.Errorf("bundle output %q was not created", name) + } + record := &t.execution.Outputs[idx] + if len(columns) == 0 { + return fmt.Errorf("bundle output %q has no metadata columns", name) + } + physical := make(map[string]publication.LogicalColumn, len(columns)) + for _, column := range columns { + physical[column.Name] = column + } + for index := range record.Columns { + column := &record.Columns[index] + if logical, ok := physical[column.Name]; ok { + column.SemanticPath = logical.SemanticPath + column.LogicalType = logical.Kind + column.Nullable = logical.Nullable + column.Repeated = logical.Repeated + } + } + return t.save(context.Background()) +} + func (t *clickHouseBundleTx) InsertRows(ctx context.Context, name string, columns []clickhouse.Column, rows []map[string]any) error { if t.idempotent || len(rows) == 0 { return nil @@ -611,3 +646,131 @@ func (s *ClickHouseBundleStore) Reconcile(ctx context.Context, olderThan time.Ti } return nil } + +// RetentionCandidate describes a physical table that is eligible for cleanup. +// The planner is deliberately non-destructive: callers must perform the +// actual backend operation after applying their own cleanup scheduling and +// retry policy. Candidates are always derived from READY executions only. +type RetentionCandidate struct { + ExecutionID string + PointerName string + PhysicalTable string +} + +// PlanReadyCleanup returns old, unreferenced READY publication tables using +// pointer references as a conservative fallback. For generation-aware +// cleanup, use PlanReadyCleanupForActiveGenerations. +// +// No execution, pointer, lease, or physical table is changed by this method. +// Backend/catalog failures are retryable and return no partial plan. +func (s *ClickHouseBundleStore) PlanReadyCleanup(ctx context.Context) ([]RetentionCandidate, error) { + return s.planReadyCleanup(ctx, nil) +} + +// PlanReadyCleanupForActiveGenerations is the generation-aware retention +// planner. activeGenerations maps each project to the generation selected by +// the project-level release pointer. Because dataframe pointers are +// generation-scoped, callers must provide this map when historical generation +// pointers remain in the catalog; those historical pointers are rollback +// metadata, not currently visible releases. +func (s *ClickHouseBundleStore) PlanReadyCleanupForActiveGenerations(ctx context.Context, activeGenerations map[string]string) ([]RetentionCandidate, error) { + return s.planReadyCleanup(ctx, activeGenerations) +} + +func (s *ClickHouseBundleStore) planReadyCleanup(ctx context.Context, activeGenerations map[string]string) ([]RetentionCandidate, error) { + before := time.Now().UTC().Add(time.Second) + executions, err := s.catalog.ListExecutions(ctx, publication.BundleReady, before) + if err != nil { + return nil, dataframeerrors.Wrap(err, dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) + } + protected := make(map[string]struct{}, len(executions)) + for _, execution := range executions { + if activeGenerations != nil { + activeGeneration, ok := activeGenerations[execution.Project] + if !ok || execution.DatasetGeneration != activeGeneration { + continue + } + } + pointer, pointerErr := s.catalog.GetPointer(ctx, execution.PointerName()) + if pointerErr == nil { + if pointer.ExecutionID == execution.ID { + protected[execution.ID] = struct{}{} + } + continue + } + if !errors.Is(pointerErr, publication.ErrBundleNotFound) { + return nil, dataframeerrors.Wrap(pointerErr, dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) + } + } + + groups := make(map[string][]publication.BundleExecution) + for _, execution := range executions { + if activeGenerations != nil { + if _, ok := activeGenerations[execution.Project]; !ok { + // A partial map is intentionally safe for per-project cleanup: + // projects whose active release was not resolved are out of scope. + protected[execution.ID] = struct{}{} + continue + } + } + key := execution.Project + "\x00" + execution.Name + groups[key] = append(groups[key], execution) + } + for _, group := range groups { + sort.SliceStable(group, func(i, j int) bool { + return bundleCompletionTime(group[i]).After(bundleCompletionTime(group[j])) + }) + priorRetained := false + for _, execution := range group { + if activeGenerations != nil && execution.DatasetGeneration == activeGenerations[execution.Project] { + continue + } + if !completeBundleExecution(execution) || priorRetained { + continue + } + protected[execution.ID] = struct{}{} + priorRetained = true + } + } + + result := make([]RetentionCandidate, 0) + for _, execution := range executions { + if _, keep := protected[execution.ID]; keep { + continue + } + for _, output := range execution.Outputs { + // This is a hard guard against turning retention into a general + // purpose table deletion mechanism. + if strings.TrimSpace(output.PhysicalTable) == "" || !strings.HasPrefix(output.PhysicalTable, s.prefix+"_") { + continue + } + result = append(result, RetentionCandidate{ExecutionID: execution.ID, PointerName: execution.PointerName(), PhysicalTable: output.PhysicalTable}) + } + } + sort.Slice(result, func(i, j int) bool { + if result[i].ExecutionID != result[j].ExecutionID { + return result[i].ExecutionID < result[j].ExecutionID + } + return result[i].PhysicalTable < result[j].PhysicalTable + }) + return result, nil +} + +func completeBundleExecution(execution publication.BundleExecution) bool { + if execution.State != publication.BundleReady || len(execution.Outputs) == 0 { + return false + } + for _, output := range execution.Outputs { + if output.State != publication.BundleReady { + return false + } + } + return true +} + +func bundleCompletionTime(execution publication.BundleExecution) time.Time { + if execution.ReadyAt != nil { + return *execution.ReadyAt + } + return execution.UpdatedAt +} diff --git a/internal/dataframe/publication/clickhouse/clickhouse_bundle_test.go b/internal/dataframe/publication/clickhouse/clickhouse_bundle_test.go index dfb72dc2..5010af0b 100644 --- a/internal/dataframe/publication/clickhouse/clickhouse_bundle_test.go +++ b/internal/dataframe/publication/clickhouse/clickhouse_bundle_test.go @@ -400,3 +400,149 @@ func TestClickHouseBundleLeaseRenewalStopsWithTransactionCleanup(t *testing.T) { t.Fatal("transaction cleanup did not cancel lease renewal") } } + +func TestPlanReadyCleanupRetainsActiveAndPriorRelease(t *testing.T) { + catalog := newBundleCatalogFixture() + client := newBundleClickHouseFixture() + store, err := NewBundleStore(client, catalog) + if err != nil { + t.Fatal(err) + } + now := time.Now().UTC() + for i, generation := range []string{"g1", "g2", "g3"} { + readyAt := now.Add(-time.Duration(3-i) * time.Hour) + execution := publication.BundleExecution{ + ID: "execution-" + generation, + BundleIdentity: publication.BundleIdentity{Project: "project-a", DatasetGeneration: generation, Name: "Observation"}, + State: publication.BundleReady, ReadyAt: &readyAt, CreatedAt: readyAt, UpdatedAt: readyAt, + Outputs: []publication.BundleOutputRecord{{Name: "Observation", PhysicalTable: "loom_bundle_" + generation + "_Observation", State: publication.BundleReady}}, + } + catalog.executions[execution.ID] = execution + client.tables[execution.Outputs[0].PhysicalTable] = nil + } + // Every generation has its own dataframe pointer. Only g3 is the active + // project generation; g1/g2 pointers represent rollback metadata. + for _, id := range []string{"execution-g1", "execution-g2", "execution-g3"} { + execution := catalog.executions[id] + catalog.pointers[execution.PointerName()] = publication.BundlePointer{Name: execution.PointerName(), ExecutionID: execution.ID} + } + + plan, err := store.PlanReadyCleanupForActiveGenerations(context.Background(), map[string]string{"project-a": "g3"}) + if err != nil { + t.Fatal(err) + } + if len(plan) != 1 || plan[0].ExecutionID != "execution-g1" { + t.Fatalf("cleanup plan = %#v, want only execution-g1", plan) + } + if plan[0].PhysicalTable != "loom_bundle_g1_Observation" { + t.Fatalf("planned table = %q", plan[0].PhysicalTable) + } + if len(client.tables) != 3 { + t.Fatalf("planner changed physical tables: %#v", client.tables) + } +} + +func TestPlanReadyCleanupNeverPlansReferencedRollbackOrForeignTable(t *testing.T) { + catalog := newBundleCatalogFixture() + store, err := NewBundleStore(newBundleClickHouseFixture(), catalog) + if err != nil { + t.Fatal(err) + } + readyAt := time.Now().UTC().Add(-time.Hour) + execution := publication.BundleExecution{ + ID: "rollback", BundleIdentity: publication.BundleIdentity{Project: "project-a", DatasetGeneration: "rollback", Name: "Observation"}, + State: publication.BundleReady, ReadyAt: &readyAt, CreatedAt: readyAt, UpdatedAt: readyAt, + Outputs: []publication.BundleOutputRecord{ + {Name: "Observation", PhysicalTable: "loom_bundle_rollback_Observation", State: publication.BundleReady}, + {Name: "bad", PhysicalTable: "other_table", State: publication.BundleReady}, + }, + } + catalog.executions[execution.ID] = execution + catalog.pointers[execution.PointerName()] = publication.BundlePointer{Name: execution.PointerName(), ExecutionID: execution.ID} + plan, err := store.PlanReadyCleanup(context.Background()) + if err != nil { + t.Fatal(err) + } + if len(plan) != 0 { + t.Fatalf("cleanup plan = %#v, referenced/foreign tables must be protected", plan) + } +} + +func TestClickHouseBundleCandidateIsInvisibleUntilReadyPointerCAS(t *testing.T) { + catalog := newBundleCatalogFixture() + client := newBundleClickHouseFixture() + store, err := NewBundleStore(client, catalog) + if err != nil { + t.Fatal(err) + } + identity := publication.BundleIdentity{Project: "project-a", DatasetGeneration: "g1", Name: "Observation"} + tx, err := store.BeginBundleFor(context.Background(), identity) + if err != nil { + t.Fatal(err) + } + if err := tx.CreateOutput(context.Background(), "Observation", []clickhouse.Column{{Name: "id", Type: "String"}}); err != nil { + t.Fatal(err) + } + if _, err := catalog.GetPointer(context.Background(), identity.PointerName()); !errors.Is(err, publication.ErrBundleNotFound) { + t.Fatalf("candidate became visible before commit: %v", err) + } + if err := tx.InsertRows(context.Background(), "Observation", []clickhouse.Column{{Name: "id", Type: "String"}}, []map[string]any{{"id": "1"}}); err != nil { + t.Fatal(err) + } + if _, err := catalog.GetPointer(context.Background(), identity.PointerName()); !errors.Is(err, publication.ErrBundleNotFound) { + t.Fatalf("candidate became visible before CAS: %v", err) + } + if err := tx.Commit(context.Background()); err != nil { + t.Fatal(err) + } + pointer, err := catalog.GetPointer(context.Background(), identity.PointerName()) + if err != nil { + t.Fatal(err) + } + if pointer.ExecutionID == "" { + t.Fatal("successful CAS published an empty execution ID") + } + execution, err := catalog.GetExecution(context.Background(), pointer.ExecutionID) + if err != nil || !execution.State.Successful() { + t.Fatalf("published execution = %#v, err = %v", execution, err) + } +} + +func TestClickHouseBundleFailedCandidatePreservesOldPointer(t *testing.T) { + catalog := newBundleCatalogFixture() + client := newBundleClickHouseFixture() + store, err := NewBundleStore(client, catalog) + if err != nil { + t.Fatal(err) + } + old := publication.BundleExecution{ + ID: "old", BundleIdentity: publication.BundleIdentity{Project: "project-a", DatasetGeneration: "g1", Name: "Observation"}, + State: publication.BundleReady, UpdatedAt: time.Now().UTC(), + Outputs: []publication.BundleOutputRecord{{Name: "Observation", PhysicalTable: "loom_bundle_old_Observation", State: publication.BundleReady}}, + } + catalog.executions[old.ID] = old + catalog.pointers[old.PointerName()] = publication.BundlePointer{Name: old.PointerName(), ExecutionID: old.ID} + client.tables[old.Outputs[0].PhysicalTable] = nil + + client.failInsert = true + candidateIdentity := old.BundleIdentity + candidateIdentity.RecipeDigest = "new-recipe" + tx, err := store.BeginBundleFor(context.Background(), candidateIdentity) + if err != nil { + t.Fatal(err) + } + if err := tx.CreateOutput(context.Background(), "Observation", []clickhouse.Column{{Name: "id", Type: "String"}}); err != nil { + t.Fatal(err) + } + if err := tx.InsertRows(context.Background(), "Observation", []clickhouse.Column{{Name: "id", Type: "String"}}, []map[string]any{{"id": "1"}}); err == nil { + t.Fatal("failed candidate insert unexpectedly succeeded") + } + _ = tx.Abort(context.Background(), errors.New("candidate failed")) + pointer, err := catalog.GetPointer(context.Background(), old.PointerName()) + if err != nil { + t.Fatal(err) + } + if pointer.ExecutionID != old.ID { + t.Fatalf("failed candidate changed visible pointer to %q", pointer.ExecutionID) + } +} diff --git a/internal/dataframe/publication/clickhouse/target.go b/internal/dataframe/publication/clickhouse/target.go index d38511af..db060859 100644 --- a/internal/dataframe/publication/clickhouse/target.go +++ b/internal/dataframe/publication/clickhouse/target.go @@ -56,6 +56,16 @@ func (t *Target) Begin(ctx context.Context, identity publication.PublicationIden cancel() return nil, fmt.Errorf("output %q create: %w", schema.Name, err) } + if metadata, ok := tx.(interface { + SetOutputMetadata(string, []publication.LogicalColumn) error + }); ok { + if err := metadata.SetOutputMetadata(schema.Name, schema.Columns); err != nil { + cleanupCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 10*time.Second) + _ = tx.Abort(cleanupCtx, fmt.Errorf("output %q metadata: %w", schema.Name, err)) + cancel() + return nil, fmt.Errorf("output %q metadata: %w", schema.Name, err) + } + } result.columns[schema.Name] = columns } return result, nil diff --git a/internal/dataframe/publication/types.go b/internal/dataframe/publication/types.go index 478e6ace..5d03eae2 100644 --- a/internal/dataframe/publication/types.go +++ b/internal/dataframe/publication/types.go @@ -11,11 +11,14 @@ import "context" // boolean, or object. Object values are rejected by the generic MVP runner // unless a target explicitly opts into a serialization policy. type LogicalColumn struct { - Name string - Kind string - Repeated bool - Nullable bool - IsIdentity bool + Name string + // SemanticPath is the stable FHIR/provenance identity. It is persisted + // alongside the physical schema but never used to name ClickHouse columns. + SemanticPath string + Kind string + Repeated bool + Nullable bool + IsIdentity bool } type OutputSchema struct { diff --git a/internal/dataframe/published/federation.go b/internal/dataframe/published/federation.go index 50ddb570..56d0d3ad 100644 --- a/internal/dataframe/published/federation.go +++ b/internal/dataframe/published/federation.go @@ -522,6 +522,37 @@ func (r *Reader) CurrentFederatedSelectors(ctx context.Context, projects []strin return result, nil } +// CurrentProjectDatasets returns the current output materializations for one +// project without merging them with other projects. +func (r *Reader) CurrentProjectDatasets(ctx context.Context, project string) ([]Materialization, error) { + project = strings.TrimSpace(project) + if project == "" { + return nil, dataframeerrors.NewError(dataframeerrors.CodeDatasetNotFound, "") + } + selectors, err := r.CurrentFederatedSelectors(ctx, []string{project}) + if err != nil { + return nil, err + } + result := make([]Materialization, 0, len(selectors)) + for _, selector := range selectors { + sources, sourceErr := r.CurrentFederatedSources(ctx, []string{project}, selector) + if sourceErr != nil { + return nil, sourceErr + } + result = append(result, sources...) + } + sort.Slice(result, func(i, j int) bool { + if result[i].Name != result[j].Name { + return result[i].Name < result[j].Name + } + return result[i].ID < result[j].ID + }) + if len(result) == 0 { + return nil, dataframeerrors.NewError(dataframeerrors.CodeDatasetNotFound, "") + } + return result, nil +} + func ReconcileFederatedDataset(selector DataframeSelector, expectedProjects []string, sources []Materialization) (FederatedDataset, error) { if len(sources) == 0 { statuses := make([]ProjectStatus, 0, len(expectedProjects)) diff --git a/internal/dataframe/published/read.go b/internal/dataframe/published/read.go index e580e1a9..75eac68b 100644 --- a/internal/dataframe/published/read.go +++ b/internal/dataframe/published/read.go @@ -280,9 +280,12 @@ func (r *Reader) pageResolved(ctx context.Context, req PageRequest, m Materializ if req.Sort.Desc { direction = "DESC" } - query += fmt.Sprintf(" ORDER BY `%s` %s, `__loom_row_id` ASC", req.Sort.Column, direction) + query += fmt.Sprintf(" ORDER BY `%s` %s, toString(`__loom_row_id`) ASC", req.Sort.Column, direction) } else { - query += " ORDER BY toUInt64(`__loom_row_id`) ASC" + // Published recipe identities are deterministic strings, while legacy + // tables may use UInt64. Ordering through the shared string + // representation keeps keyset pagination valid for both schemas. + query += " ORDER BY toString(`__loom_row_id`) ASC" } query += fmt.Sprintf(" LIMIT %d", first+1) rows, err := r.ClickHouse.QueryRowsArgs(ctx, query, queryColumns, whereArgs...) @@ -426,7 +429,7 @@ func decodeCursor(cursor string) (*pageCursor, error) { } func cursorPredicate(cursor *pageCursor, sort *Sort) (string, []any, error) { - row := "toUInt64(`__loom_row_id`) > toUInt64(?)" + row := "toString(`__loom_row_id`) > ?" if sort == nil { return row, []any{cursor.RowID}, nil } diff --git a/internal/dataframe/published/read_test.go b/internal/dataframe/published/read_test.go index ee8e74b1..821acfc6 100644 --- a/internal/dataframe/published/read_test.go +++ b/internal/dataframe/published/read_test.go @@ -18,7 +18,7 @@ func TestKeysetCursorRoundTrip(t *testing.T) { if err != nil { t.Fatal(err) } - if predicate == "" || len(args) != 3 || predicate == "toUInt64(`__loom_row_id`) > toUInt64(\"42\")" { + if predicate == "" || len(args) != 3 || predicate != "(`name` > ? OR (`name` = ? AND toString(`__loom_row_id`) > ?))" { t.Fatalf("unexpected sort predicate %q", predicate) } } diff --git a/internal/dataframe/published/types.go b/internal/dataframe/published/types.go index d676c6bb..f28cb0c7 100644 --- a/internal/dataframe/published/types.go +++ b/internal/dataframe/published/types.go @@ -15,8 +15,12 @@ const projectIDColumn = "project_id" const StateReady State = "READY" type Column struct { - Name string `json:"name"` - ClickHouse string `json:"clickhouseType"` + Name string `json:"name"` + SemanticPath string `json:"semanticPath,omitempty"` + ClickHouse string `json:"clickhouseType"` + LogicalType string `json:"logicalType,omitempty"` + Nullable bool `json:"nullable,omitempty"` + Repeated bool `json:"repeated,omitempty"` } type DataframeSelector = dataset.DataframeSelector @@ -70,7 +74,7 @@ func publishedMaterialization(execution publication.BundleExecution, output publ func publishedColumns(columns []publication.PhysicalColumn) []Column { result := make([]Column, len(columns)) for index, column := range columns { - result[index] = Column{Name: column.Name, ClickHouse: column.ClickHouse} + result[index] = Column{Name: column.Name, SemanticPath: column.SemanticPath, ClickHouse: column.ClickHouse, LogicalType: column.LogicalType, Nullable: column.Nullable, Repeated: column.Repeated} } return result } diff --git a/internal/dataframe/recipe/canonical.go b/internal/dataframe/recipe/canonical.go index 66d819ad..537a9af6 100644 --- a/internal/dataframe/recipe/canonical.go +++ b/internal/dataframe/recipe/canonical.go @@ -44,6 +44,9 @@ func (b Bundle) Explain() (Explanation, error) { for _, d := range out.DynamicColumns { e.DynamicColumns = append(e.DynamicColumns, d.Name) } + for _, d := range out.ExtensionColumns { + e.ExtensionColumns = append(e.ExtensionColumns, d.Name) + } for _, projection := range out.CatalogProjections { e.CatalogProjections = append(e.CatalogProjections, projection.Name) } diff --git a/internal/dataframe/recipe/document_types.go b/internal/dataframe/recipe/document_types.go index 531dad5c..b3f725e5 100644 --- a/internal/dataframe/recipe/document_types.go +++ b/internal/dataframe/recipe/document_types.go @@ -43,6 +43,7 @@ type Output struct { Expand *Expansion `json:"expand,omitempty"` Identity *Identity `json:"identity,omitempty"` DynamicColumns []DynamicColumn `json:"dynamicColumns,omitempty"` + ExtensionColumns []ExtensionColumn `json:"extensionColumns,omitempty"` CatalogProjections []CatalogProjection `json:"catalogProjections,omitempty"` CollisionPolicy string `json:"collisionPolicy,omitempty"` } @@ -298,6 +299,7 @@ type Traversal struct { Slices []RepresentativeSlice `json:"slices,omitempty"` Traversals []Traversal `json:"traversals,omitempty"` DynamicColumns []DynamicColumn `json:"dynamicColumns,omitempty"` + ExtensionColumns []ExtensionColumn `json:"extensionColumns,omitempty"` CatalogProjections []CatalogProjection `json:"catalogProjections,omitempty"` } @@ -327,6 +329,37 @@ type DynamicColumn struct { Value *Expression `json:"value,omitempty"` Columns []string `json:"columns,omitempty"` MaxColumns int `json:"maxColumns,omitempty"` + // ColumnTypes carries resolver-observed logical types for frozen keys. It + // is optional for legacy dynamicColumns and is populated for typed + // extensionColumns. + ColumnTypes map[string]string `json:"columnTypes,omitempty"` + // ColumnSourceKeys decouples a public frozen column name from the runtime + // keyed-map lookup key. Extension columns use this for parent__child names + // while matching the leaf Extension.url segment inside its scoped source. + ColumnSourceKeys map[string]string `json:"-"` +} + +// ExtensionColumn is a bounded, URL-keyed projection of FHIR Extension +// values. Unlike dynamicColumns, its resolver understands nested Extension +// arrays and freezes both the URL mapping and the value representation. +type ExtensionColumn struct { + Name string `json:"name"` + Source Expression `json:"source"` + ColumnPrefix *string `json:"columnPrefix,omitempty"` + MaxColumns int `json:"maxColumns"` + Columns []ExtensionColumnMapping `json:"columns,omitempty"` +} + +// ExtensionColumnMapping is immutable schema-discovery output. Name is the +// normalized public key, URL is the raw Extension.url, and ValuePath is the +// relative item selector for a single primitive value[x]. Empty ValuePath +// means the extension object is represented by canonical JSON. +type ExtensionColumnMapping struct { + Name string `json:"name"` + URL string `json:"url"` + SourcePath string `json:"sourcePath,omitempty"` + ValuePath string `json:"valuePath,omitempty"` + ValueType string `json:"valueType"` } // CatalogProjection describes a bounded family of populated FHIR paths. It @@ -352,7 +385,10 @@ const ( // RuntimeBindings are request-scoped and deliberately not part of a stored // recipe digest. type RuntimeBindings struct { - Project string + Project string + // RecipeDigest selects an immutable project-scoped revision when supplied. + // Empty preserves the server-owned name lookup used by legacy callers. + RecipeDigest string DatasetGeneration string AuthResourcePaths []string AuthScopeMode authscope.ReadScopeMode diff --git a/internal/dataframe/recipe/document_validation.go b/internal/dataframe/recipe/document_validation.go index cdb8a163..b546322f 100644 --- a/internal/dataframe/recipe/document_validation.go +++ b/internal/dataframe/recipe/document_validation.go @@ -74,6 +74,9 @@ func (b Bundle) Validate() error { if err := validateDynamicColumns(output.DynamicColumns, path+".dynamicColumns", &budget); err != nil { return err } + if err := validateExtensionColumns(output.ExtensionColumns, path+".extensionColumns", &budget); err != nil { + return err + } for index, projection := range output.CatalogProjections { if err := projection.validateAt(fmt.Sprintf("%s.catalogProjections[%d]", path, index)); err != nil { return err @@ -124,6 +127,9 @@ func validateTraversals(items []Traversal, path string, depth int) error { if err := validateDynamicColumns(t.DynamicColumns, p+".dynamicColumns", &budget); err != nil { return err } + if err := validateExtensionColumns(t.ExtensionColumns, p+".extensionColumns", &budget); err != nil { + return err + } for index, projection := range t.CatalogProjections { if err := projection.validateAt(fmt.Sprintf("%s.catalogProjections[%d]", p, index)); err != nil { return err @@ -216,7 +222,8 @@ type arity struct{ min, max int } var callArities = map[string]arity{ "coalesce": {1, -1}, "coalesce_string": {1, -1}, "first": {1, 1}, "all": {1, 1}, "distinct": {1, 1}, - "concat": {1, -1}, "join": {2, 2}, "cast": {2, 2}, "reference_id": {1, 1}, + "canonical_json": {1, 1}, + "concat": {1, -1}, "join": {2, 2}, "cast": {2, 2}, "reference_id": {1, 1}, "path_segment": {1, 1}, "basename": {1, 1}, "last_segment": {1, 1}, "sanitize_name": {1, 1}, "sanitize_graphql_name": {1, 1}, "uuid3": {3, 3}, "uuid5": {3, 3}, "if": {3, 3}, "case": {2, -1}, diff --git a/internal/dataframe/recipe/dynamic_validation.go b/internal/dataframe/recipe/dynamic_validation.go index 00b1d592..fce62c1a 100644 --- a/internal/dataframe/recipe/dynamic_validation.go +++ b/internal/dataframe/recipe/dynamic_validation.go @@ -50,3 +50,43 @@ func validateDynamicColumns(items []DynamicColumn, path string, budget *int) err } return nil } + +func validateExtensionColumns(items []ExtensionColumn, path string, budget *int) error { + seen := map[string]bool{} + for index, item := range items { + p := fmt.Sprintf("%s[%d]", path, index) + if err := validateRecipeName(item.Name, p+".name"); err != nil { + return err + } + if seen[item.Name] { + return validationError("duplicate_name", p+".name", "duplicate extension column name") + } + seen[item.Name] = true + if item.ColumnPrefix != nil && *item.ColumnPrefix != "" { + if err := validateRecipeName(*item.ColumnPrefix, p+".columnPrefix"); err != nil { + return err + } + } + if item.MaxColumns <= 0 { + return validationError("invalid_limit", p+".maxColumns", "must be greater than zero") + } + if err := validateExpressionBudget(item.Source, p+".source", budget); err != nil { + return err + } + seenColumns := map[string]bool{} + for columnIndex, column := range item.Columns { + cp := fmt.Sprintf("%s.columns[%d]", p, columnIndex) + if strings.TrimSpace(column.Name) == "" || strings.TrimSpace(column.URL) == "" { + return validationError("required", cp, "name and url are required") + } + if seenColumns[column.Name] { + return validationError("duplicate_name", cp+".name", "duplicate extension column") + } + seenColumns[column.Name] = true + if strings.TrimSpace(column.ValueType) == "" { + return validationError("required", cp+".valueType", "valueType is required") + } + } + } + return nil +} diff --git a/internal/dataframe/recipe/engine/engine.go b/internal/dataframe/recipe/engine/engine.go index 8227c0ba..42749af7 100644 --- a/internal/dataframe/recipe/engine/engine.go +++ b/internal/dataframe/recipe/engine/engine.go @@ -36,6 +36,7 @@ type QueryRows func(context.Context, string, int, map[string]any, func(map[strin type Config struct { Registry Registry + Revisions recipe.RevisionStore ResolveBundle func(context.Context, recipe.Bundle, recipe.RuntimeBindings) (recipe.Bundle, error) QueryRows QueryRows ScopeDigest func(recipe.RuntimeBindings) string @@ -44,6 +45,7 @@ type Config struct { type Engine struct { registry Registry + revisions recipe.RevisionStore resolveBundle func(context.Context, recipe.Bundle, recipe.RuntimeBindings) (recipe.Bundle, error) queryRows QueryRows scopeDigest func(recipe.RuntimeBindings) string @@ -90,8 +92,9 @@ type OutputStream struct { } type DynamicColumnCheck struct { - ColumnName string - ValueType string + ColumnName string + ValueType string + AllowUnknownKeys bool } type StreamResult struct { @@ -111,13 +114,26 @@ func New(cfg Config) (*Engine, error) { if batch <= 0 { batch = 1000 } - return &Engine{registry: cfg.Registry, resolveBundle: cfg.ResolveBundle, queryRows: cfg.QueryRows, scopeDigest: cfg.ScopeDigest, batchSize: batch}, nil + return &Engine{registry: cfg.Registry, revisions: cfg.Revisions, resolveBundle: cfg.ResolveBundle, queryRows: cfg.QueryRows, scopeDigest: cfg.ScopeDigest, batchSize: batch}, nil } func (e *Engine) Resolve(ctx context.Context, name string, bindings recipe.RuntimeBindings) (Resolved, error) { - entry, err := e.registry.LoadRecipe(ctx, name) - if err != nil { - return Resolved{}, err + if strings.TrimSpace(bindings.Project) == "" { + return Resolved{}, fmt.Errorf("recipe project is required") + } + var entry exec.Entry + var err error + if bindings.RecipeDigest != "" && e.revisions != nil { + revision, revisionErr := e.revisions.Get(ctx, bindings.Project, name, bindings.RecipeDigest) + if revisionErr != nil { + return Resolved{}, revisionErr + } + entry = exec.Entry{Bundle: revision.Bundle, Digest: revision.Digest} + } else { + entry, err = e.registry.LoadRecipe(ctx, name) + if err != nil { + return Resolved{}, err + } } return e.resolveEntry(ctx, entry, bindings) } @@ -413,7 +429,7 @@ func dynamicChecks(metadata []lower.DynamicColumnMetadata) map[string]map[string if checks[column.DynamicName] == nil { checks[column.DynamicName] = map[string]DynamicColumnCheck{} } - checks[column.DynamicName][column.SourceKey] = DynamicColumnCheck{ColumnName: column.Name, ValueType: column.ValueType} + checks[column.DynamicName][column.SourceKey] = DynamicColumnCheck{ColumnName: column.Name, ValueType: column.ValueType, AllowUnknownKeys: column.AllowUnknownKeys} } return checks } diff --git a/internal/dataframe/recipe/engine/postquery.go b/internal/dataframe/recipe/engine/postquery.go index af81e6e3..7dad4419 100644 --- a/internal/dataframe/recipe/engine/postquery.go +++ b/internal/dataframe/recipe/engine/postquery.go @@ -1,6 +1,7 @@ package engine import ( + "encoding/json" "fmt" "math" "reflect" @@ -16,6 +17,22 @@ const ( postQueryTargetKey = "__loom_postquery_target" ) +// DynamicDriftError means a runtime key was not part of the dynamic-column +// schema frozen from the field catalog. It carries schema metadata only, so +// transport adapters can report the mismatch without exposing row values. +type DynamicDriftError struct { + DynamicName string + Key string + FrozenKeyCount int +} + +func (e *DynamicDriftError) Error() string { + if e == nil { + return "dynamic column schema drift" + } + return fmt.Sprintf("dynamic map %q emitted unexpected key %q", e.DynamicName, e.Key) +} + func materializePostQueryRowWithChecks(row map[string]any, checks map[string]map[string]DynamicColumnCheck) (map[string]any, error) { value, err := materializePostQueryValue(row) if err != nil { @@ -50,7 +67,10 @@ func validateDynamicDrift(row map[string]any, checks map[string]map[string]Dynam key := fmt.Sprint(value) column, ok := allowed[key] if !ok { - return fmt.Errorf("dynamic map %q emitted unexpected key %q", dynamicName, key) + if dynamicFamilyAllowsUnknownKeys(allowed) { + continue + } + return &DynamicDriftError{DynamicName: dynamicName, Key: key, FrozenKeyCount: len(allowed)} } if actual, exists := row[column.ColumnName]; exists && !dynamicValueMatches(actual, column.ValueType) { return fmt.Errorf("dynamic map %q column %q has incompatible value type %q", dynamicName, column.ColumnName, column.ValueType) @@ -60,6 +80,15 @@ func validateDynamicDrift(row map[string]any, checks map[string]map[string]Dynam return nil } +func dynamicFamilyAllowsUnknownKeys(checks map[string]DynamicColumnCheck) bool { + for _, check := range checks { + if check.AllowUnknownKeys { + return true + } + } + return false +} + func dynamicRuntimeKeys(value any) ([]any, error) { switch typed := value.(type) { case []any: @@ -179,6 +208,15 @@ func evaluatePostQueryCall(operation, target string, args []any) (any, error) { } isNull := func(value any) bool { return value == nil } switch operation { + case "canonical_json": + if len(args) != 1 { + return nil, fmt.Errorf("canonical_json requires one argument") + } + encoded, err := json.Marshal(args[0]) + if err != nil { + return nil, fmt.Errorf("canonical_json: %w", err) + } + return string(encoded), nil case "coalesce", "fallback": for _, value := range args { if !isNull(value) { diff --git a/internal/dataframe/recipe/engine/postquery_test.go b/internal/dataframe/recipe/engine/postquery_test.go index e72b40e5..bf22abf6 100644 --- a/internal/dataframe/recipe/engine/postquery_test.go +++ b/internal/dataframe/recipe/engine/postquery_test.go @@ -1,6 +1,24 @@ package engine -import "testing" +import ( + "errors" + "testing" + + "github.com/calypr/loom/internal/dataframe/compiler/lower" +) + +func TestDynamicChecksRetainsEveryFamilySharingACompatibilityColumn(t *testing.T) { + checks := dynamicChecks([]lower.DynamicColumnMetadata{ + {Name: "HTAN_DATA_FILE_ID", DynamicName: "identifier_keys", SourceKey: "HTAN_DATA_FILE_ID", ValueType: "string"}, + {Name: "HTAN_DATA_FILE_ID", DynamicName: "category_keys", SourceKey: "HTAN_DATA_FILE_ID", ValueType: "string"}, + }) + if _, ok := checks["identifier_keys"]["HTAN_DATA_FILE_ID"]; !ok { + t.Fatalf("identifier compatibility key was discarded: %#v", checks) + } + if _, ok := checks["category_keys"]["HTAN_DATA_FILE_ID"]; !ok { + t.Fatalf("category compatibility key was discarded: %#v", checks) + } +} func TestMaterializePostQueryRejectsDynamicKeyDrift(t *testing.T) { checks := map[string]map[string]DynamicColumnCheck{ @@ -10,9 +28,14 @@ func TestMaterializePostQueryRejectsDynamicKeyDrift(t *testing.T) { "code_a": "value", "__loom_dynamic_runtime_keys": map[string]any{"code": []any{"unexpected"}}, } - if _, err := materializePostQueryRowWithChecks(row, checks); err == nil { + _, err := materializePostQueryRowWithChecks(row, checks) + if err == nil { t.Fatal("unexpected dynamic key was accepted") } + var drift *DynamicDriftError + if !errors.As(err, &drift) || drift.DynamicName != "code" || drift.Key != "unexpected" || drift.FrozenKeyCount != 1 { + t.Fatalf("dynamic drift = %#v, want code/unexpected/1", drift) + } } func TestMaterializePostQueryRejectsDynamicTypeDrift(t *testing.T) { @@ -28,6 +51,43 @@ func TestMaterializePostQueryRejectsDynamicTypeDrift(t *testing.T) { } } +func TestMaterializePostQueryExtensionFamilyIgnoresSiblingKeys(t *testing.T) { + checks := map[string]map[string]DynamicColumnCheck{ + "attachment_extension_keys__checksum_sha256": { + "checksum_sha256": {ColumnName: "checksum_sha256", ValueType: "string", AllowUnknownKeys: true}, + }, + } + row, err := materializePostQueryRowWithChecks(map[string]any{ + "checksum_sha256": "abc123", + "__loom_dynamic_runtime_keys": map[string]any{ + "attachment_extension_keys__checksum_sha256": []any{"checksum_sha256", "sha256"}, + }, + }, checks) + if err != nil { + t.Fatal(err) + } + if row["checksum_sha256"] != "abc123" { + t.Fatalf("projected extension value = %#v", row["checksum_sha256"]) + } +} + +func TestMaterializePostQueryExtensionFamilyStillRejectsKnownKeyTypeDrift(t *testing.T) { + checks := map[string]map[string]DynamicColumnCheck{ + "attachment_extension_keys__checksum_sha256": { + "checksum_sha256": {ColumnName: "checksum_sha256", ValueType: "string", AllowUnknownKeys: true}, + }, + } + _, err := materializePostQueryRowWithChecks(map[string]any{ + "checksum_sha256": 42, + "__loom_dynamic_runtime_keys": map[string]any{ + "attachment_extension_keys__checksum_sha256": []any{"checksum_sha256", "sha256"}, + }, + }, checks) + if err == nil { + t.Fatal("known extension key type drift was accepted") + } +} + func TestMaterializePostQueryStripsDynamicMetadata(t *testing.T) { checks := map[string]map[string]DynamicColumnCheck{ "code": {"a": {ColumnName: "code_a", ValueType: "string"}}, diff --git a/internal/dataframe/recipe/exec/arango/revisions.go b/internal/dataframe/recipe/exec/arango/revisions.go new file mode 100644 index 00000000..a07247fb --- /dev/null +++ b/internal/dataframe/recipe/exec/arango/revisions.go @@ -0,0 +1,150 @@ +package arango + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "sort" + "strings" + "time" + + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataframe/recipe/exec" + arangostore "github.com/calypr/loom/internal/store/arango" +) + +const RevisionCollection = "loom_dataframe_recipe_revisions" + +// RevisionRegistry persists immutable project recipe revisions in the same +// Arango database/client as the legacy name-addressed recipe registry. +type RevisionRegistry struct { + client Client + batchSize int +} + +func NewRevisionRegistry(client Client) (*RevisionRegistry, error) { + if client == nil { + return nil, fmt.Errorf("Arango recipe revision registry client is required") + } + return &RevisionRegistry{client: client, batchSize: 32}, nil +} + +func RevisionBootstrapSpec() arangostore.BootstrapSpec { + return arangostore.BootstrapSpec{Collections: []arangostore.CollectionSpec{{Name: RevisionCollection, Indexes: [][]string{{"project", "name"}, {"project", "name", "digest"}}}}} +} + +func revisionKey(project, name, digest string) string { + sum := sha256.Sum256([]byte(project + "\x00" + name + "\x00" + digest)) + return hex.EncodeToString(sum[:]) +} + +func (r *RevisionRegistry) Register(ctx context.Context, project string, bundle recipe.Bundle, parent string) (recipe.RecipeRevision, error) { + if strings.TrimSpace(project) == "" || strings.TrimSpace(bundle.Name) == "" { + return recipe.RecipeRevision{}, fmt.Errorf("project and recipe name are required") + } + if err := bundle.Validate(); err != nil { + return recipe.RecipeRevision{}, err + } + digest, err := bundle.Digest() + if err != nil { + return recipe.RecipeRevision{}, err + } + if parent != "" { + current, currentErr := r.currentDigest(ctx, project, bundle.Name) + if currentErr != nil && currentErr != exec.ErrRecipeNotFound { + return recipe.RecipeRevision{}, currentErr + } + if current != "" && current != parent { + return recipe.RecipeRevision{}, fmt.Errorf("recipe revision parent %q is not current (current %q)", parent, current) + } + } + value := recipe.RecipeRevision{Project: project, Name: bundle.Name, Digest: digest, Parent: parent, Bundle: bundle, CreatedAt: time.Now().UTC()} + data, err := json.Marshal(value) + if err != nil { + return recipe.RecipeRevision{}, err + } + var doc map[string]any + if err := json.Unmarshal(data, &doc); err != nil { + return recipe.RecipeRevision{}, err + } + doc["project"], doc["name"], doc["digest"], doc["parentDigest"], doc["_key"] = project, bundle.Name, digest, parent, revisionKey(project, bundle.Name, digest) + doc["createdAt"] = value.CreatedAt + data, err = json.Marshal(doc) + if err != nil { + return recipe.RecipeRevision{}, err + } + if err := r.client.InsertBatchRaw(ctx, RevisionCollection, []json.RawMessage{data}, true, "document"); err != nil { + return recipe.RecipeRevision{}, err + } + return value, nil +} + +func (r *RevisionRegistry) currentDigest(ctx context.Context, project, name string) (string, error) { + var digest string + err := r.client.QueryRows(ctx, `FOR doc IN @@collection FILTER doc.project == @project AND doc.name == @name SORT doc.createdAt DESC LIMIT 1 RETURN doc.digest`, r.batchSize, map[string]any{"@collection": RevisionCollection, "project": project, "name": name}, func(row map[string]any) error { + digest = stringValue(row["digest"]) + return nil + }) + if err != nil { + return "", err + } + if digest == "" { + return "", exec.ErrRecipeNotFound + } + return digest, nil +} + +func (r *RevisionRegistry) Get(ctx context.Context, project, name, digest string) (recipe.RecipeRevision, error) { + var found *recipe.RecipeRevision + err := r.client.QueryRows(ctx, `FOR doc IN @@collection FILTER doc.project == @project AND doc.name == @name AND doc.digest == @digest LIMIT 1 RETURN doc`, r.batchSize, map[string]any{"@collection": RevisionCollection, "project": project, "name": name, "digest": digest}, func(row map[string]any) error { + data, err := json.Marshal(row) + if err != nil { + return err + } + var value recipe.RecipeRevision + if err := json.Unmarshal(data, &value); err != nil { + return err + } + found = &value + return nil + }) + if err != nil { + return recipe.RecipeRevision{}, err + } + if found == nil { + return recipe.RecipeRevision{}, recipe.ErrRecipeRevisionNotFound + } + return *found, nil +} + +func (r *RevisionRegistry) List(ctx context.Context, project, name string) ([]recipe.RecipeRevision, error) { + result := make([]recipe.RecipeRevision, 0) + err := r.client.QueryRows(ctx, `FOR doc IN @@collection FILTER doc.project == @project AND doc.name == @name SORT doc.createdAt DESC RETURN doc`, r.batchSize, map[string]any{"@collection": RevisionCollection, "project": project, "name": name}, func(row map[string]any) error { + data, err := json.Marshal(row) + if err != nil { + return err + } + var value recipe.RecipeRevision + if err := json.Unmarshal(data, &value); err != nil { + return err + } + result = append(result, value) + return nil + }) + if err != nil { + return nil, err + } + sort.SliceStable(result, func(i, j int) bool { return result[i].CreatedAt.After(result[j].CreatedAt) }) + return result, nil +} + +var _ recipe.RevisionStore = (*RevisionRegistry)(nil) + +func stringValue(value any) string { + if value == nil { + return "" + } + return fmt.Sprint(value) +} diff --git a/internal/dataframe/recipe/exec/arango/revisions_test.go b/internal/dataframe/recipe/exec/arango/revisions_test.go new file mode 100644 index 00000000..1a2cf238 --- /dev/null +++ b/internal/dataframe/recipe/exec/arango/revisions_test.go @@ -0,0 +1,83 @@ +package arango + +import ( + "context" + "encoding/json" + "strings" + "testing" + + "github.com/calypr/loom/internal/dataframe/recipe" + arangostore "github.com/calypr/loom/internal/store/arango" +) + +type revisionClient struct{ docs []map[string]any } + +func (c *revisionClient) InsertBatchRaw(_ context.Context, _ string, data []json.RawMessage, _ bool, _ string) error { + for _, raw := range data { + var doc map[string]any + if err := json.Unmarshal(raw, &doc); err != nil { + return err + } + key := doc["_key"] + replaced := false + for i := range c.docs { + if c.docs[i]["_key"] == key { + c.docs[i] = doc + replaced = true + break + } + } + if !replaced { + c.docs = append(c.docs, doc) + } + } + return nil +} + +func (c *revisionClient) QueryRows(_ context.Context, query string, _ int, vars map[string]interface{}, visit arangostore.RowVisitor) error { + for _, doc := range c.docs { + if doc["project"] != vars["project"] || doc["name"] != vars["name"] { + continue + } + if digest, ok := vars["digest"]; ok && doc["digest"] != digest { + continue + } + if strings.Contains(query, "RETURN doc.digest") { + if err := visit(map[string]any{"digest": doc["digest"]}); err != nil { + return err + } + continue + } + if err := visit(doc); err != nil { + return err + } + } + return nil +} + +func TestRevisionRegistryRoundTrip(t *testing.T) { + client := &revisionClient{} + registry, err := NewRevisionRegistry(client) + if err != nil { + t.Fatal(err) + } + bundle := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "files", TranslationVersion: "1", Outputs: []recipe.Output{{Name: "DocumentReference", RootResourceType: "DocumentReference", RowGrain: "document_reference"}}} + first, err := registry.Register(context.Background(), "project-a", bundle, "") + if err != nil { + t.Fatal(err) + } + loaded, err := registry.Get(context.Background(), "project-a", "files", first.Digest) + if err != nil { + t.Fatal(err) + } + if loaded.Digest != first.Digest || loaded.Project != "project-a" || loaded.Bundle.Name != "files" { + t.Fatalf("loaded=%+v", loaded) + } + list, err := registry.List(context.Background(), "project-a", "files") + if err != nil || len(list) != 1 { + t.Fatalf("list=%d err=%v", len(list), err) + } + if _, err := registry.Get(context.Background(), "project-b", "files", first.Digest); err != recipe.ErrRecipeRevisionNotFound { + t.Fatalf("cross-project err=%v", err) + } +} diff --git a/internal/dataframe/recipe/json_encoding.go b/internal/dataframe/recipe/json_encoding.go index 8239a413..161385b2 100644 --- a/internal/dataframe/recipe/json_encoding.go +++ b/internal/dataframe/recipe/json_encoding.go @@ -40,6 +40,7 @@ type OutputExplanation struct { TraversalNames []string `json:"traversalNames,omitempty"` Expanded bool `json:"expanded,omitempty"` DynamicColumns []string `json:"dynamicColumns,omitempty"` + ExtensionColumns []string `json:"extensionColumns,omitempty"` CatalogProjections []string `json:"catalogProjections,omitempty"` } diff --git a/internal/dataframe/recipe/revisions.go b/internal/dataframe/recipe/revisions.go new file mode 100644 index 00000000..37f46204 --- /dev/null +++ b/internal/dataframe/recipe/revisions.go @@ -0,0 +1,101 @@ +package recipe + +import ( + "context" + "errors" + "fmt" + "sync" + "time" +) + +// RecipeRevision is an immutable, project-scoped recipe document. The digest +// is the canonical Bundle digest and is therefore safe to use as an optimistic +// concurrency and publication address. +type RecipeRevision struct { + Project string `json:"project"` + Name string `json:"name"` + Digest string `json:"digest"` + Parent string `json:"parentDigest,omitempty"` + Bundle Bundle `json:"bundle"` + CreatedAt time.Time `json:"createdAt"` +} + +var ErrRecipeRevisionNotFound = errors.New("recipe revision not found") + +type RevisionStore interface { + Register(context.Context, string, Bundle, string) (RecipeRevision, error) + Get(context.Context, string, string, string) (RecipeRevision, error) + List(context.Context, string, string) ([]RecipeRevision, error) +} + +// MemoryRevisionStore is the default process-local implementation. Production +// deployments can replace it with a durable project registry without changing +// compiler or GraphQL contracts. +type MemoryRevisionStore struct { + mu sync.RWMutex + values map[string]RecipeRevision + current map[string]string +} + +func NewMemoryRevisionStore() *MemoryRevisionStore { + return &MemoryRevisionStore{values: make(map[string]RecipeRevision), current: make(map[string]string)} +} + +func revisionKey(project, name, digest string) string { + return project + "\x00" + name + "\x00" + digest +} +func currentKey(project, name string) string { return project + "\x00" + name } + +func (s *MemoryRevisionStore) Register(_ context.Context, project string, bundle Bundle, parent string) (RecipeRevision, error) { + if s == nil { + return RecipeRevision{}, fmt.Errorf("recipe revision store is required") + } + if project == "" || bundle.Name == "" { + return RecipeRevision{}, fmt.Errorf("project and recipe name are required") + } + if err := bundle.Validate(); err != nil { + return RecipeRevision{}, err + } + digest, err := bundle.Digest() + if err != nil { + return RecipeRevision{}, err + } + now := time.Now().UTC() + revision := RecipeRevision{Project: project, Name: bundle.Name, Digest: digest, Parent: parent, Bundle: bundle, CreatedAt: now} + s.mu.Lock() + defer s.mu.Unlock() + key := revisionKey(project, bundle.Name, digest) + if existing, ok := s.values[key]; ok { + return existing, nil + } + if parent != "" { + if current := s.current[currentKey(project, bundle.Name)]; current != "" && current != parent { + return RecipeRevision{}, fmt.Errorf("recipe revision parent %q is not current (current %q)", parent, current) + } + } + s.values[key] = revision + s.current[currentKey(project, bundle.Name)] = digest + return revision, nil +} + +func (s *MemoryRevisionStore) Get(_ context.Context, project, name, digest string) (RecipeRevision, error) { + s.mu.RLock() + defer s.mu.RUnlock() + value, ok := s.values[revisionKey(project, name, digest)] + if !ok { + return RecipeRevision{}, ErrRecipeRevisionNotFound + } + return value, nil +} + +func (s *MemoryRevisionStore) List(_ context.Context, project, name string) ([]RecipeRevision, error) { + s.mu.RLock() + defer s.mu.RUnlock() + result := make([]RecipeRevision, 0) + for _, value := range s.values { + if value.Project == project && value.Name == name { + result = append(result, value) + } + } + return result, nil +} diff --git a/internal/dataframe/recipe/revisions_test.go b/internal/dataframe/recipe/revisions_test.go new file mode 100644 index 00000000..b116ed65 --- /dev/null +++ b/internal/dataframe/recipe/revisions_test.go @@ -0,0 +1,28 @@ +package recipe + +import ( + "context" + "testing" +) + +func TestMemoryRevisionStoreRegistersImmutableProjectRevision(t *testing.T) { + store := NewMemoryRevisionStore() + bundle := Bundle{RecipeSchemaVersion: CurrentSchemaVersion, Name: "files", TranslationVersion: "1", Outputs: []Output{{Name: "DocumentReference", RootResourceType: "DocumentReference", RowGrain: "document_reference"}}} + revision, err := store.Register(context.Background(), "project-a", bundle, "") + if err != nil { + t.Fatal(err) + } + if revision.Digest == "" || revision.Project != "project-a" { + t.Fatalf("revision = %+v", revision) + } + loaded, err := store.Get(context.Background(), "project-a", "files", revision.Digest) + if err != nil { + t.Fatal(err) + } + if loaded.Digest != revision.Digest || loaded.Bundle.Name != "files" { + t.Fatalf("loaded revision = %+v", loaded) + } + if _, err := store.Get(context.Background(), "project-b", "files", revision.Digest); err != ErrRecipeRevisionNotFound { + t.Fatalf("cross-project lookup error = %v", err) + } +} diff --git a/internal/dataframe/recipe/schema/discovery.go b/internal/dataframe/recipe/schema/discovery.go index 3e9d43db..4be60b03 100644 --- a/internal/dataframe/recipe/schema/discovery.go +++ b/internal/dataframe/recipe/schema/discovery.go @@ -37,10 +37,7 @@ func resolveProjectionSets(ctx context.Context, scope Scope, discovery Discovery } sort.SliceStable(selected, func(i, j int) bool { return selected[i].Path < selected[j].Path }) for _, candidate := range selected { - name := projectionName(set, candidate.Path) - if _, exists := seen[name]; exists { - return nil, fmt.Errorf("projection set %q produced duplicate column %q", set.Name, name) - } + name := uniqueProjectionName(set, candidate.Path, seen) seen[name] = struct{}{} selectPath := strings.TrimPrefix(candidate.Path, ".") if alias != "" && alias != "root" { @@ -383,6 +380,29 @@ func projectionName(set recipe.CatalogProjection, fieldPath string) string { return strings.Trim(b.String(), "_") } +// uniqueProjectionName preserves the established PATH column spelling when it +// is unambiguous. FHIR catalogs may contain both scalar and repeated variants +// of a path (for example author.reference and author[].reference), which +// normalize to the same SQL-safe name. Keep both catalog-backed fields rather +// than rejecting an otherwise valid, dataset-independent recipe. +func uniqueProjectionName(set recipe.CatalogProjection, fieldPath string, used map[string]struct{}) string { + base := projectionName(set, fieldPath) + if _, exists := used[base]; !exists { + return base + } + suffix := "__alternate" + if strings.Contains(fieldPath, "[]") { + suffix = "__repeated" + } + name := base + suffix + for index := 2; ; index++ { + if _, exists := used[name]; !exists { + return name + } + name = fmt.Sprintf("%s%s_%d", base, suffix, index) + } +} + func sortedValues(values map[string]struct{}) []string { result := make([]string, 0, len(values)) for value := range values { @@ -394,7 +414,7 @@ func sortedValues(values map[string]struct{}) []string { func hasCatalogDeclarations(bundle recipe.Bundle) bool { for _, output := range bundle.Outputs { - if len(output.CatalogProjections) > 0 || hasCatalogPivots(output.Pivots) || hasCatalogDynamic(output.DynamicColumns) { + if len(output.CatalogProjections) > 0 || hasCatalogPivots(output.Pivots) || hasCatalogDynamic(output.DynamicColumns) || len(output.ExtensionColumns) > 0 { return true } for _, traversal := range output.Traversals { @@ -407,7 +427,7 @@ func hasCatalogDeclarations(bundle recipe.Bundle) bool { } func traversalHasCatalog(traversal recipe.Traversal) bool { - return len(traversal.CatalogProjections) > 0 || hasCatalogPivots(traversal.Pivots) || hasCatalogDynamic(traversal.DynamicColumns) + return len(traversal.CatalogProjections) > 0 || hasCatalogPivots(traversal.Pivots) || hasCatalogDynamic(traversal.DynamicColumns) || len(traversal.ExtensionColumns) > 0 } func hasCatalogPivots(pivots []recipe.Pivot) bool { diff --git a/internal/dataframe/recipe/schema/extension_columns.go b/internal/dataframe/recipe/schema/extension_columns.go new file mode 100644 index 00000000..e6986243 --- /dev/null +++ b/internal/dataframe/recipe/schema/extension_columns.go @@ -0,0 +1,159 @@ +package schema + +import ( + "context" + "fmt" + "sort" + "strings" + + "github.com/calypr/loom/internal/dataframe/recipe" + fhirschema "github.com/calypr/loom/internal/fhir/schema" +) + +// resolveExtensionColumns freezes URL-to-value mappings from the same scoped +// catalog snapshot used by the other recipe discovery features. Catalog paths +// below nested Extension arrays are deliberately retained; the semantic layer +// lowers each frozen mapping as a bounded dynamic family. +func resolveExtensionColumns(ctx context.Context, scope Scope, discovery Discovery, resourceType, alias string, items []recipe.ExtensionColumn) error { + for index := range items { + item := &items[index] + selector := strings.TrimSpace(item.Source.Select) + if selector == "" { + return fmt.Errorf("extension column %q source must be a selector", item.Name) + } + selector = strings.TrimPrefix(selector, alias+".") + selector = strings.TrimPrefix(selector, "root.") + selector = strings.TrimPrefix(selector, ".") + if !strings.HasSuffix(selector, "extension[]") { + return fmt.Errorf("extension column %q source must select a repeated Extension", item.Name) + } + resolved, ok := fhirschema.ResolvePath(resourceType, selector) + if !ok || resolved.PropertyRef != "Extension" { + return fmt.Errorf("extension column %q source %q is not a schema-valid repeated Extension selector", item.Name, selector) + } + candidates, err := discovery.Fields(ctx, scope, resourceType) + if err != nil { + return err + } + byURL := map[string][]extensionValueCandidate{} + for _, candidate := range candidates { + for _, observation := range candidate.ExtensionValues { + if strings.TrimSpace(observation.URL) == "" { + continue + } + if !extensionSourceWithin(selector, observation.SourcePath) { + continue + } + urlPath := append([]string(nil), observation.URLPath...) + identity := strings.Join(append(append([]string(nil), urlPath...), observation.URL), "\x00") + byURL[identity] = append(byURL[identity], extensionValueCandidate{url: observation.URL, path: observation.SourcePath, valuePath: observation.ValuePath, valueType: observation.ValueType, urlPath: urlPath, fields: candidates}) + } + if len(candidate.ExtensionValues) > 0 { + // Correlated observations supersede the legacy flattened + // distinct-value fallback for this URL field. Mixing both would + // incorrectly assign every observed value[x] kind to every URL. + continue + } + if !strings.HasPrefix(candidate.Path, selector+".") || !strings.HasSuffix(candidate.Path, ".url") { + continue + } + extensionPath := strings.TrimSuffix(candidate.Path, ".url") + if candidate.DistinctTruncated { + return fmt.Errorf("extension column %q URL discovery at %q was truncated", item.Name, candidate.Path) + } + for _, url := range candidate.DistinctValues { + if strings.TrimSpace(url) == "" { + continue + } + byURL[url] = append(byURL[url], extensionValueCandidate{url: url, path: extensionPath, fields: candidates}) + } + } + mappings := make([]recipe.ExtensionColumnMapping, 0, len(byURL)) + for _, values := range byURL { + url := values[0].url + name, err := applyDynamicKeyTransforms(url, []string{"last_segment", "sanitize_name"}) + if err != nil || name == "" { + continue + } + valuePath, valueType, sourcePath := extensionValueMapping(resourceType, values) + if len(values) > 0 && len(values[0].urlPath) > 0 { + parts := make([]string, 0, len(values[0].urlPath)+1) + for _, ancestor := range values[0].urlPath { + segment, segmentErr := applyDynamicKeyTransforms(ancestor, []string{"last_segment", "sanitize_name"}) + if segmentErr == nil && segment != "" { + parts = append(parts, segment) + } + } + parts = append(parts, name) + name = strings.Join(parts, "__") + } + mappings = append(mappings, recipe.ExtensionColumnMapping{Name: name, URL: url, SourcePath: sourcePath, ValuePath: valuePath, ValueType: valueType}) + } + sort.Slice(mappings, func(i, j int) bool { + if mappings[i].Name == mappings[j].Name { + return mappings[i].URL < mappings[j].URL + } + return mappings[i].Name < mappings[j].Name + }) + if len(mappings) > item.MaxColumns { + return fmt.Errorf("extension column %q discovery found %d columns, exceeding maxColumns %d", item.Name, len(mappings), item.MaxColumns) + } + item.Columns = mappings + } + return nil +} + +type extensionValueCandidate struct { + url string + path string + valuePath string + valueType string + urlPath []string + fields []FieldCandidate +} + +func extensionSourceWithin(declared, observed string) bool { + declared = strings.TrimSuffix(strings.TrimSpace(declared), ".") + observed = strings.TrimSuffix(strings.TrimSpace(observed), ".") + return observed == declared || strings.HasPrefix(observed, declared+".extension[]") +} + +func extensionValueMapping(resourceType string, candidates []extensionValueCandidate) (string, string, string) { + type observed struct{ path, kind string } + values := map[string]observed{} + sourcePath := "" + for _, candidate := range candidates { + if sourcePath == "" || candidate.path < sourcePath { + sourcePath = candidate.path + } + if candidate.valueType != "" { + values[candidate.valuePath+"\x00"+candidate.valueType] = observed{path: candidate.valuePath, kind: candidate.valueType} + continue + } + prefix := candidate.path + "." + for _, field := range candidate.fields { + if !strings.HasPrefix(field.Path, prefix) || !strings.Contains(strings.TrimPrefix(field.Path, prefix), "value") { + continue + } + relative := strings.TrimPrefix(field.Path, prefix) + if strings.Contains(relative, ".") || !strings.HasPrefix(relative, "value") { + continue + } + metadata, ok := fhirschema.ResolveTerminalScalarMetadata(resourceType, field.Path) + if !ok || metadata.Primitive == fhirschema.PrimitiveUnknown || metadata.Repeated { + continue + } + kind := string(metadata.Primitive) + values[kind] = observed{path: relative, kind: kind} + } + } + if len(values) != 1 { + // Complex and mixed value[x] representations are preserved as a JSON + // string by the semantic/physical extension mapper. + return "", "string", sourcePath + } + for _, value := range values { + return value.path, value.kind, sourcePath + } + return "", "string", "" +} diff --git a/internal/dataframe/recipe/schema/resolve.go b/internal/dataframe/recipe/schema/resolve.go index 7d79507f..6574f67f 100644 --- a/internal/dataframe/recipe/schema/resolve.go +++ b/internal/dataframe/recipe/schema/resolve.go @@ -23,11 +23,15 @@ type Scope struct { } type FieldCandidate struct { - ResourceType string - Path string - Kind string - DistinctValues []string - DistinctTruncated bool + ResourceType string + Path string + Kind string + DistinctValues []string + DistinctTruncated bool + // ExtensionValues is optional profile-level correlation metadata. When + // present it preserves the URL/value[x] pairing that a flattened field + // catalog cannot represent with independent distinct-value lists. + ExtensionValues []ExtensionValueObservation PivotCandidate bool PivotFamily string PivotColumns []string @@ -38,6 +42,14 @@ type FieldCandidate struct { PivotValueSelectors []string } +type ExtensionValueObservation struct { + URL string + SourcePath string + ValuePath string + ValueType string + URLPath []string +} + // Discovery is the only backend-facing seam needed by recipe resolution. The // implementation in server adapts Loom's existing field catalog reader. type Discovery interface { @@ -163,6 +175,10 @@ func cloneCandidates(in []FieldCandidate) []FieldCandidate { for i := range in { out[i] = in[i] out[i].DistinctValues = append([]string(nil), in[i].DistinctValues...) + out[i].ExtensionValues = append([]ExtensionValueObservation(nil), in[i].ExtensionValues...) + for j := range out[i].ExtensionValues { + out[i].ExtensionValues[j].URLPath = append([]string(nil), in[i].ExtensionValues[j].URLPath...) + } out[i].PivotColumns = append([]string(nil), in[i].PivotColumns...) } return out @@ -181,6 +197,9 @@ func resolveOutput(ctx context.Context, output *recipe.Output, scope Scope, disc if err := resolveDynamicColumns(ctx, scope, discovery, output.RootResourceType, "root", output.DynamicColumns); err != nil { return fmt.Errorf("dynamic columns: %w", err) } + if err := resolveExtensionColumns(ctx, scope, discovery, output.RootResourceType, "root", output.ExtensionColumns); err != nil { + return fmt.Errorf("extension columns: %w", err) + } for index := range output.Traversals { if err := resolveTraversal(ctx, &output.Traversals[index], scope, discovery); err != nil { return err @@ -206,6 +225,9 @@ func resolveTraversal(ctx context.Context, traversal *recipe.Traversal, scope Sc if err := resolveDynamicColumns(ctx, scope, discovery, traversal.ToResourceType, alias, traversal.DynamicColumns); err != nil { return fmt.Errorf("traversal %q dynamic columns: %w", traversal.Name, err) } + if err := resolveExtensionColumns(ctx, scope, discovery, traversal.ToResourceType, alias, traversal.ExtensionColumns); err != nil { + return fmt.Errorf("traversal %q extension columns: %w", traversal.Name, err) + } for index := range traversal.Traversals { if err := resolveTraversal(ctx, &traversal.Traversals[index], scope, discovery); err != nil { return err diff --git a/internal/dataframe/recipe/schema/resolve_test.go b/internal/dataframe/recipe/schema/resolve_test.go index cc5353f8..c37b0a6d 100644 --- a/internal/dataframe/recipe/schema/resolve_test.go +++ b/internal/dataframe/recipe/schema/resolve_test.go @@ -55,6 +55,24 @@ func TestResolveCatalogProjectionBeforeSemanticTyping(t *testing.T) { } } +func TestResolveCatalogProjectionKeepsPathsThatNormalizeToTheSameColumn(t *testing.T) { + bundle := recipe.Bundle{RecipeSchemaVersion: 1, Name: "catalog", TranslationVersion: "1", Outputs: []recipe.Output{{ + Name: "DocumentReference", RootResourceType: "DocumentReference", RowGrain: "file", + CatalogProjections: []recipe.CatalogProjection{{Name: "fields", IncludePaths: []string{"author*"}, Kinds: []string{"scalar"}, MaxColumns: 4, ValueMode: recipe.ValueModeFirst}}, + }}} + resolved, err := Resolve(context.Background(), bundle, Scope{Project: "p"}, fakeDiscovery{fields: []FieldCandidate{ + {ResourceType: "DocumentReference", Path: "author.reference", Kind: "scalar"}, + {ResourceType: "DocumentReference", Path: "author[].reference", Kind: "scalar"}, + }}) + if err != nil { + t.Fatal(err) + } + fields := resolved.Bundle.Outputs[0].Fields + if len(fields) != 2 || fields[0].Name != "author_reference" || fields[1].Name != "author_reference__repeated" { + t.Fatalf("resolved fields = %#v", fields) + } +} + func TestResolveDiscoveryFreezesPivotAndKeyedColumns(t *testing.T) { bundle := recipe.Bundle{RecipeSchemaVersion: 1, Name: "catalog", TranslationVersion: "1", Outputs: []recipe.Output{{ Name: "Patient", RootResourceType: "Patient", RowGrain: "patient", @@ -100,6 +118,46 @@ func TestResolveTransformsDiscoveredDynamicKeys(t *testing.T) { } } +func TestResolveExtensionColumnsFreezesURLMappings(t *testing.T) { + prefix := "" + bundle := recipe.Bundle{RecipeSchemaVersion: 1, Name: "extensions", TranslationVersion: "1", Outputs: []recipe.Output{{ + Name: "DocumentReference", RootResourceType: "DocumentReference", RowGrain: "file", + ExtensionColumns: []recipe.ExtensionColumn{{Name: "attachment", ColumnPrefix: &prefix, MaxColumns: 4, Source: recipe.Expression{Select: "root.content[].attachment.extension[]"}}}, + }}} + resolved, err := Resolve(context.Background(), bundle, Scope{Project: "p", DatasetGeneration: "g"}, fakeDiscovery{fields: []FieldCandidate{ + {ResourceType: "DocumentReference", Path: "content[].attachment.extension[].url", DistinctValues: []string{"http://example.org/source_path", "http://example.org/sha256"}}, + {ResourceType: "DocumentReference", Path: "content[].attachment.extension[].valueString", Kind: "scalar"}, + }}) + if err != nil { + t.Fatal(err) + } + columns := resolved.Bundle.Outputs[0].ExtensionColumns[0].Columns + if len(columns) != 2 || columns[0].Name != "sha256" || columns[1].Name != "source_path" { + t.Fatalf("unexpected extension mappings: %#v", columns) + } + if _, err := semantic.BuildRecipePlan(resolved.Bundle, recipe.RuntimeBindings{Project: "p", DatasetGeneration: "g"}); err != nil { + t.Fatalf("resolved extension columns did not type-check: %v", err) + } +} + +func TestResolveExtensionColumnsPreservesPrimitiveMapping(t *testing.T) { + prefix := "" + bundle := recipe.Bundle{RecipeSchemaVersion: 1, Name: "extensions", TranslationVersion: "1", Outputs: []recipe.Output{{ + Name: "DocumentReference", RootResourceType: "DocumentReference", RowGrain: "file", + ExtensionColumns: []recipe.ExtensionColumn{{Name: "attachment", ColumnPrefix: &prefix, MaxColumns: 4, Source: recipe.Expression{Select: "root.content[].attachment.extension[]"}}}, + }}} + resolved, err := Resolve(context.Background(), bundle, Scope{Project: "p"}, fakeDiscovery{fields: []FieldCandidate{ + {ResourceType: "DocumentReference", Path: "content[].attachment.extension[].url", ExtensionValues: []ExtensionValueObservation{{URL: "http://example.org/source_path", SourcePath: "content[].attachment.extension[]", ValuePath: "valueUrl", ValueType: "string"}, {URL: "http://example.org/sha256", SourcePath: "content[].attachment.extension[]", ValuePath: "valueString", ValueType: "string"}}}, + }}) + if err != nil { + t.Fatal(err) + } + columns := resolved.Bundle.Outputs[0].ExtensionColumns[0].Columns + if columns[0].Name != "sha256" || columns[1].Name != "source_path" || columns[0].ValuePath != "valueString" || columns[1].ValuePath != "valueUrl" { + t.Fatalf("primitive mappings were not retained: %#v", columns) + } +} + func stringPointer(value string) *string { return &value } func TestResolveOmitsPivotWithNoDiscoveredColumns(t *testing.T) { diff --git a/internal/dataframe/semantic/recipe_plan_output.go b/internal/dataframe/semantic/recipe_plan_output.go index 369a3b01..af4cd5ff 100644 --- a/internal/dataframe/semantic/recipe_plan_output.go +++ b/internal/dataframe/semantic/recipe_plan_output.go @@ -133,6 +133,12 @@ func finishRecipeOutput(plan OutputPlan, output recipe.Output, scope scopeFrame) } plan.DynamicMaps = append(plan.DynamicMaps, dynamicMaps...) plan.Root.DynamicMaps = append(plan.Root.DynamicMaps, dynamicMaps...) + extensionMaps, err := buildRecipeExtensionMaps(output.ExtensionColumns, scope, "extensionColumns", "", output.RootResourceType) + if err != nil { + return OutputPlan{}, err + } + plan.DynamicMaps = append(plan.DynamicMaps, extensionMaps...) + plan.Root.DynamicMaps = append(plan.Root.DynamicMaps, extensionMaps...) return plan, nil } @@ -159,6 +165,11 @@ func buildRecipeTraversal(input recipe.Traversal, parent scopeFrame, path string return SemanticNode{}, err } node.DynamicMaps = dynamicMaps + extensionMaps, err := buildRecipeExtensionMaps(input.ExtensionColumns, scope, path+".extensionColumns", alias, input.ToResourceType) + if err != nil { + return SemanticNode{}, err + } + node.DynamicMaps = append(node.DynamicMaps, extensionMaps...) node.Filters, err = LowerRecipeFiltersForAlias(input.ToResourceType, alias, input.Filters) if err != nil { return SemanticNode{}, fmt.Errorf("%s.filters: %w", path, err) @@ -191,6 +202,81 @@ func buildRecipeTraversal(input recipe.Traversal, parent scopeFrame, path string return node, nil } +func buildRecipeExtensionMaps(items []recipe.ExtensionColumn, scope scopeFrame, path, scopeAlias, resourceType string) ([]SemanticDynamicMap, error) { + result := make([]SemanticDynamicMap, 0) + for index, item := range items { + if item.Columns == nil { + return nil, fmt.Errorf("%s[%d] extension column %q is unresolved; resolve it through schema discovery first", path, index, item.Name) + } + if len(item.Columns) == 0 { + continue + } + source, err := scope.expression(item.Source, fmt.Sprintf("%s[%d].source", path, index)) + if err != nil { + return nil, err + } + selector := source.Expression.Selector + if selector == nil || source.Type.Cardinality != expression.Many { + return nil, fmt.Errorf("%s[%d].source must be a repeated Extension selector", path, index) + } + binding, ok := scope.aliases[selector.Context] + if selector.Context == "" { + binding, ok = scope.aliases["root"] + } + if !ok { + return nil, fmt.Errorf("%s[%d].source context %q is not in scope", path, index, selector.Context) + } + selectorPath := strings.TrimPrefix(strings.TrimSpace(selector.Path), ".") + if prefix := strings.TrimSuffix(binding.Prefix, "."); prefix != "" && strings.HasPrefix(selectorPath, prefix+".") { + selectorPath = strings.TrimPrefix(selectorPath, prefix+".") + } + resolved, valid := fhirschema.ResolvePath(binding.ResourceType, selectorPath) + if !valid || resolved.PropertyRef != "Extension" { + return nil, fmt.Errorf("%s[%d].source must select a schema-valid repeated Extension", path, index) + } + for _, mapping := range item.Columns { + sourceExpr := item.Source + if mapping.SourcePath != "" { + prefix := "root" + if scopeAlias != "" { + prefix = scopeAlias + } + sourceExpr = recipe.Expression{Select: prefix + "." + strings.TrimPrefix(mapping.SourcePath, ".")} + } + value := recipe.Expression{Select: "item." + mapping.ValuePath} + if mapping.ValuePath == "" { + value = recipe.Expression{Call: "canonical_json", Args: []recipe.Expression{{Document: &recipe.DocumentRef{Context: "item"}}}} + } + key := recipe.Expression{Call: "sanitize_name", Args: []recipe.Expression{{Call: "last_segment", Args: []recipe.Expression{{Select: "item.url"}}}}} + rawSourceKey := strings.TrimRight(strings.TrimSpace(mapping.URL), "/") + if split := strings.LastIndexAny(rawSourceKey, "/#"); split >= 0 { + rawSourceKey = rawSourceKey[split+1:] + } + sourceKey := sanitize(rawSourceKey) + if sourceKey == "" { + return nil, fmt.Errorf("%s[%d] extension URL %q has no usable column key", path, index, mapping.URL) + } + dynamic := recipe.DynamicColumn{ + Name: item.Name + "__" + mapping.Name, ColumnPrefix: item.ColumnPrefix, + Source: sourceExpr, Key: &key, Value: &value, Columns: []string{mapping.Name}, MaxColumns: item.MaxColumns, + ColumnTypes: map[string]string{mapping.Name: mapping.ValueType}, ColumnSourceKeys: map[string]string{mapping.Name: sourceKey}, + } + maps, err := buildRecipeDynamicMaps([]recipe.DynamicColumn{dynamic}, scope, path, scopeAlias, resourceType) + if err != nil { + return nil, err + } + for index := range maps { + // Each extension mapping projects one URL from an Extension array. + // Other URLs in the same array are valid siblings and may have their + // own independently discovered mappings. + maps[index].AllowUnknownKeys = true + } + result = append(result, maps...) + } + } + return result, nil +} + func buildRecipeDynamicMaps(items []recipe.DynamicColumn, scope scopeFrame, path, scopeAlias, resourceType string) ([]SemanticDynamicMap, error) { result := make([]SemanticDynamicMap, 0, len(items)) for index, dynamic := range items { @@ -200,7 +286,7 @@ func buildRecipeDynamicMaps(items []recipe.DynamicColumn, scope scopeFrame, path // to mark an optional family as resolved with zero discovered keys. columns = append([]string{}, dynamic.Columns...) } - item := SemanticDynamicMap{Name: dynamic.Name, ScopeAlias: scopeAlias, ResourceType: resourceType, Columns: columns, MaxColumns: dynamic.MaxColumns} + item := SemanticDynamicMap{Name: dynamic.Name, ScopeAlias: scopeAlias, ResourceType: resourceType, Columns: columns, MaxColumns: dynamic.MaxColumns, ColumnTypes: dynamic.ColumnTypes, ColumnSourceKeys: dynamic.ColumnSourceKeys} if dynamic.ColumnPrefix != nil { prefix := *dynamic.ColumnPrefix item.ColumnPrefix = &prefix diff --git a/internal/dataframe/semantic/recipe_plan_types.go b/internal/dataframe/semantic/recipe_plan_types.go index fd7a43e0..254283fa 100644 --- a/internal/dataframe/semantic/recipe_plan_types.go +++ b/internal/dataframe/semantic/recipe_plan_types.go @@ -119,15 +119,21 @@ func (u SemanticUnnest) Validate() error { } type SemanticDynamicMap struct { - Name string - ColumnPrefix *string - ScopeAlias string - ResourceType string - Source SemanticExpression - Key *SemanticExpression - Value *SemanticExpression - Columns []string - MaxColumns int + Name string + ColumnPrefix *string + ScopeAlias string + ResourceType string + Source SemanticExpression + Key *SemanticExpression + Value *SemanticExpression + Columns []string + ColumnTypes map[string]string + ColumnSourceKeys map[string]string + // AllowUnknownKeys is used by schema-aware projections that intentionally + // select one key from a shared runtime map. Other keys in that map are + // siblings, not schema drift; frozen matching keys still receive type checks. + AllowUnknownKeys bool + MaxColumns int } // RecipePlanExplanation is stable diagnostic output and contains only logical diff --git a/internal/dataframe/semantic/recipe_projection.go b/internal/dataframe/semantic/recipe_projection.go index fbfe869b..5b80da02 100644 --- a/internal/dataframe/semantic/recipe_projection.go +++ b/internal/dataframe/semantic/recipe_projection.go @@ -70,7 +70,7 @@ func normalizeRecipeProjection(field recipe.Field, scope scopeFrame, path string fallbackSelectors = append(fallbackSelectors, parsed) } fieldSemantic := SemanticField{ - Name: field.Name, Selector: selector, + Name: field.Name, FieldRef: field.FieldRef, Selector: selector, Fallbacks: fallbackSelectors, ValueMode: string(field.ValueMode), Expr: &primary.Expression, ExprType: primary.Type, SourcePath: primary.SourcePath, } @@ -101,7 +101,7 @@ func normalizeRecipeProjection(field recipe.Field, scope scopeFrame, path string } fieldSemantic.ExprType = projected.Type return normalizedRecipeProjection{projection: SemanticProjection{ - Name: field.Name, ValueMode: string(field.ValueMode), Expr: projected, + Name: field.Name, FieldRef: field.FieldRef, ValueMode: string(field.ValueMode), Expr: projected, }, field: fieldSemantic}, nil } @@ -112,8 +112,8 @@ func normalizeRecipeProjection(field recipe.Field, scope scopeFrame, path string if err != nil { return normalizedRecipeProjection{}, fmt.Errorf("%s: %w", path, err) } - return normalizedRecipeProjection{projection: SemanticProjection{Name: field.Name, ValueMode: string(field.ValueMode), Expr: projected}, field: SemanticField{ - Name: field.Name, ValueMode: string(field.ValueMode), Expr: &projected.Expression, ExprType: projected.Type, SourcePath: projected.SourcePath, + return normalizedRecipeProjection{projection: SemanticProjection{Name: field.Name, FieldRef: field.FieldRef, ValueMode: string(field.ValueMode), Expr: projected}, field: SemanticField{ + Name: field.Name, FieldRef: field.FieldRef, ValueMode: string(field.ValueMode), Expr: &projected.Expression, ExprType: projected.Type, SourcePath: projected.SourcePath, }}, nil } diff --git a/internal/dataframe/semantic/recipe_traversal.go b/internal/dataframe/semantic/recipe_traversal.go index 421d38d5..e6d42fec 100644 --- a/internal/dataframe/semantic/recipe_traversal.go +++ b/internal/dataframe/semantic/recipe_traversal.go @@ -73,6 +73,11 @@ func qualifyTraversalLocals(input recipe.Traversal, alias string, visible map[st copy.DynamicColumns[index].Value = &value } } + copy.ExtensionColumns = append([]recipe.ExtensionColumn(nil), input.ExtensionColumns...) + for index := range copy.ExtensionColumns { + copy.ExtensionColumns[index].Source = qualifyRecipeExpression(copy.ExtensionColumns[index].Source, alias, visible) + copy.ExtensionColumns[index].Columns = append([]recipe.ExtensionColumnMapping(nil), input.ExtensionColumns[index].Columns...) + } return copy } diff --git a/internal/dataframe/semantic/resolved_plan.go b/internal/dataframe/semantic/resolved_plan.go index 90b6874a..83035d9f 100644 --- a/internal/dataframe/semantic/resolved_plan.go +++ b/internal/dataframe/semantic/resolved_plan.go @@ -69,7 +69,11 @@ func ResolveRecipePlan(plan RecipePlan, scopeDigest, sourceGeneration string) (R } candidates := make([]Candidate, 0, len(dynamic.Columns)) for _, column := range dynamic.Columns { - candidates = append(candidates, Candidate{Key: column, ValueType: "unknown"}) + valueType := dynamic.ColumnTypes[column] + if valueType == "" { + valueType = "unknown" + } + candidates = append(candidates, Candidate{Key: column, ValueType: valueType}) } schema, err := Freeze(DynamicSpec{ Name: dynamic.Name, ColumnPrefix: dynamic.ColumnPrefix, AllowedKeys: dynamic.Columns, MaxColumns: dynamic.MaxColumns, Collision: output.Collision, @@ -80,6 +84,9 @@ func ResolveRecipePlan(plan RecipePlan, scopeDigest, sourceGeneration string) (R key := dynamicMapKey(output.Name, dynamic) columns := make([]ResolvedColumn, 0, len(schema.Columns)) for _, column := range schema.Columns { + if sourceKey := dynamic.ColumnSourceKeys[column.SourceKey]; sourceKey != "" { + column.SourceKey = sourceKey + } columns = append(columns, ResolvedColumn{Output: output.Name, DynamicName: dynamic.Name, Column: column}) } resolved.ResolvedColumns[key] = columns diff --git a/internal/dataset/arango/manifest_lifecycle.go b/internal/dataset/arango/manifest_lifecycle.go index 46242c55..d14a8610 100644 --- a/internal/dataset/arango/manifest_lifecycle.go +++ b/internal/dataset/arango/manifest_lifecycle.go @@ -17,7 +17,7 @@ const ( var ( ErrNilQueryClient = errors.New("generation store query client is required") ErrManifestAlreadyExists = errors.New("generation manifest already exists") - ErrManifestNotFound = errors.New("generation manifest was not found") + ErrManifestNotFound = publication.ErrManifestNotFound ErrManifestTransitionConflict = errors.New("generation manifest transition conflict") ErrActivationConflict = errors.New("generation activation conflict") ErrUnexpectedStoreResult = errors.New("unexpected generation store result") @@ -54,6 +54,10 @@ func (s *Store) CreateManifest(ctx context.Context, manifest publication.Manifes return publication.Manifest{}, err } bindVars := lifecycleBindVars(manifest.Dataset.Project) + // Arango rejects undeclared bind parameters. The create query derives the + // project and active record from the immutable documents themselves. + delete(bindVars, "project") + delete(bindVars, "active_record_type") bindVars["manifest"] = document bindVars["active_placeholder"] = activePlaceholderDocument(manifest.Dataset.Project) bindVars["active_release_placeholder"] = activeReleasePlaceholderDocument(manifest.Dataset.Project) @@ -108,6 +112,7 @@ func (s *Store) ReadManifest(ctx context.Context, ref publication.Ref) (publicat return publication.Manifest{}, err } bindVars := lifecycleBindVars(ref.Project) + delete(bindVars, "active_record_type") bindVars["manifest_key"] = manifestDocumentKey(ref) bindVars["generation"] = ref.Generation rows, err := s.manifestRows(ctx, readManifestAQL, bindVars) @@ -136,6 +141,7 @@ func (s *Store) TransitionManifest(ctx context.Context, manifest publication.Man return publication.Manifest{}, err } bindVars := lifecycleBindVars(manifest.Dataset.Project) + delete(bindVars, "active_record_type") bindVars["manifest_key"] = manifestDocumentKey(manifest.Dataset) bindVars["generation"] = manifest.Dataset.Generation bindVars["expected_state"] = string(manifest.State) diff --git a/internal/dataset/validation.go b/internal/dataset/validation.go index 3c3f1f7b..618e41f1 100644 --- a/internal/dataset/validation.go +++ b/internal/dataset/validation.go @@ -18,6 +18,7 @@ var ( ErrInvalidSchemaIdentity = errors.New("invalid schema identity") ErrInvalidManifest = errors.New("invalid dataset manifest") ErrInvalidTransition = errors.New("invalid dataset manifest transition") + ErrManifestNotFound = errors.New("generation manifest was not found") ErrGenerationNotReady = errors.New("dataset generation is not ready") ErrInvalidActiveGeneration = errors.New("invalid active dataset generation") ErrNoActiveGeneration = errors.New("no active dataset generation") diff --git a/internal/ingest/generation_orchestration.go b/internal/ingest/generation_orchestration.go index 3bc3168b..316937b4 100644 --- a/internal/ingest/generation_orchestration.go +++ b/internal/ingest/generation_orchestration.go @@ -288,7 +288,7 @@ func loadGeneration(ctx context.Context, opts LoadOptions) (summary LoadSummary, } manifest = stagedManifest manifestStaged = true - if !opts.StageOnly { + if !opts.StageOnly && !opts.DeferActivation { if activationErr := lifecycleStore.Activate(ctx, manifest); activationErr != nil { return summary, &ActivationOutcomeError{Dataset: plan.Dataset, Err: activationErr} } diff --git a/internal/ingest/load_options.go b/internal/ingest/load_options.go index 91fc74bf..74330b6a 100644 --- a/internal/ingest/load_options.go +++ b/internal/ingest/load_options.go @@ -30,6 +30,9 @@ type LoadOptions struct { // StageOnly leaves a successfully loaded immutable generation STAGED. It is // selected for reads only after project-release activation succeeds. StageOnly bool + // DeferActivation is the compatibility spelling used by the generation-load + // HTTP API. Like StageOnly, it leaves the generation STAGED and inactive. + DeferActivation bool // PreflightSampleRows bounds the number of payloads inspected from every // staged file before Loom opens or mutates Arango. Zero uses the safe // default; full row validation still happens in the loader. diff --git a/internal/server/config_test.go b/internal/server/config_test.go index 2fd2f33e..9b38afb7 100644 --- a/internal/server/config_test.go +++ b/internal/server/config_test.go @@ -19,7 +19,7 @@ func TestParseServerOptionsWithoutConfigUsesFlags(t *testing.T) { } } -func TestParseServerOptionsConfigOverridesFlags(t *testing.T) { +func TestParseServerOptionsConfigRetainsSettingsButNoAuthOverridesAuth(t *testing.T) { path := filepath.Join(t.TempDir(), "config.yaml") contents := "server:\n listen: :19092\n allow_unauthenticated: false\n clickhouse:\n enabled: false\nauth:\n mode: basic\n basic:\n username: loom\n password: secret\n" if err := os.WriteFile(path, []byte(contents), 0o600); err != nil { @@ -29,8 +29,8 @@ func TestParseServerOptionsConfigOverridesFlags(t *testing.T) { if err != nil { t.Fatalf("parseServerOptions() error = %v", err) } - if options.Server.Listen != ":19092" || options.Server.AllowUnauthenticated || options.Auth.AllowUnauthenticated { - t.Fatalf("YAML did not retain precedence: %#v", options) + if options.Server.Listen != ":19092" || !options.Server.AllowUnauthenticated || !options.Auth.AllowUnauthenticated { + t.Fatalf("configuration/--no-auth resolution = %#v", options) } } diff --git a/internal/server/options.go b/internal/server/options.go index 3dcdf34d..39dbdf21 100644 --- a/internal/server/options.go +++ b/internal/server/options.go @@ -119,6 +119,14 @@ func parseServerOptions(args []string, handling flag.ErrorHandling) (Config, err if err != nil { return Config{}, err } + // --no-auth is an explicit local-development override. Keep the + // configuration file authoritative for normal server settings, but honor + // this flag even when the server is started with --config (as the Helm + // local-development path does). + if noAuth { + cfg.Server.AllowUnauthenticated = true + cfg.Auth.AllowUnauthenticated = true + } if err := cfg.Validate(); err != nil { return Config{}, fmt.Errorf("invalid server config: %w", err) } diff --git a/internal/server/recipe_discovery.go b/internal/server/recipe_discovery.go index cd6cc912..6e47e187 100644 --- a/internal/server/recipe_discovery.go +++ b/internal/server/recipe_discovery.go @@ -51,6 +51,13 @@ func (d recipeCatalogDiscovery) Fields(ctx context.Context, scope schema.Scope, PivotColumnSelect: field.PivotColumnSelect, PivotValueSelect: field.PivotValueSelect, PivotItemSource: field.PivotItemSource, PivotItemResourceType: field.PivotItemResourceType, PivotValueSelectors: append([]string(nil), field.PivotValueSelectors...), + ExtensionValues: func() []schema.ExtensionValueObservation { + values := make([]schema.ExtensionValueObservation, len(field.ExtensionValues)) + for i, value := range field.ExtensionValues { + values[i] = schema.ExtensionValueObservation{URL: value.URL, SourcePath: value.SourcePath, ValuePath: value.ValuePath, ValueType: value.ValueType, URLPath: append([]string(nil), value.URLPath...)} + } + return values + }(), }) } return result, nil diff --git a/internal/server/recipe_discovery_test.go b/internal/server/recipe_discovery_test.go index a1d9353f..349af7cd 100644 --- a/internal/server/recipe_discovery_test.go +++ b/internal/server/recipe_discovery_test.go @@ -24,3 +24,16 @@ func TestRecipeCatalogDiscoverySkipsLoomMetadata(t *testing.T) { t.Fatalf("discovered fields = %#v", fields) } } + +func TestRecipeCatalogDiscoveryCarriesExtensionObservations(t *testing.T) { + discovery := recipeCatalogDiscovery{read: func(context.Context, catalog.PopulatedFieldOptions) ([]catalog.PopulatedField, error) { + return []catalog.PopulatedField{{ResourceType: "DocumentReference", Path: "content[].attachment.extension[].url", ExtensionValues: []catalog.ExtensionValueObservation{{URL: "http://example.org/source_path", SourcePath: "content[].attachment.extension[]", ValuePath: "valueUrl", ValueType: "string"}}}}, nil + }} + fields, err := discovery.Fields(context.Background(), schema.Scope{}, "DocumentReference") + if err != nil { + t.Fatal(err) + } + if len(fields) != 1 || len(fields[0].ExtensionValues) != 1 || fields[0].ExtensionValues[0].ValuePath != "valueUrl" { + t.Fatalf("extension observations = %#v", fields) + } +} diff --git a/internal/server/recipe_publication.go b/internal/server/recipe_publication.go index 6b0cf528..27b4969a 100644 --- a/internal/server/recipe_publication.go +++ b/internal/server/recipe_publication.go @@ -4,6 +4,7 @@ import ( "context" "crypto/sha256" "encoding/hex" + "errors" "fmt" "log/slog" "sort" @@ -39,13 +40,13 @@ func recipeOutputLogicalColumns(plan engine.Resolved, outputName string) []publi identityAdded := false for _, column := range output.OutputSchema { if column.Identity && column.Name == "__loom_row_id" { - columns = append(columns, publication.LogicalColumn{Name: column.Name, Kind: "string", IsIdentity: true}) + columns = append(columns, publication.LogicalColumn{Name: column.Name, SemanticPath: "loom:row_id", Kind: "string", IsIdentity: true}) identityAdded = true break } } if !identityAdded { - columns = append(columns, publication.LogicalColumn{Name: "__loom_row_id", Kind: "string", IsIdentity: true}) + columns = append(columns, publication.LogicalColumn{Name: "__loom_row_id", SemanticPath: "loom:row_id", Kind: "string", IsIdentity: true}) } for _, column := range output.OutputSchema { if column.Internal { @@ -58,7 +59,11 @@ func recipeOutputLogicalColumns(plan engine.Resolved, outputName string) []publi if kind == "" { kind = "string" } - columns = append(columns, publication.LogicalColumn{Name: publication.FlatColumnName(output.RootResourceType, column.Name), Kind: kind, Repeated: column.Cardinality == "many", Nullable: column.Nullable}) + semanticPath := column.SemanticPath + if semanticPath == "" { + semanticPath = output.RootResourceType + "." + column.Name + } + columns = append(columns, publication.LogicalColumn{Name: publication.FlatColumnName(output.RootResourceType, column.Name), SemanticPath: semanticPath, Kind: kind, Repeated: column.Cardinality == "many", Nullable: column.Nullable}) } return columns } @@ -118,6 +123,14 @@ func publishResolvedRecipe(ctx context.Context, recipeEngine *engine.Engine, tar return identity, err } +func recipeResolvedDynamicColumnCounts(plan engine.Resolved) map[string]int { + counts := make(map[string]int, len(plan.Semantic.ResolvedColumns)) + for dynamicMap, columns := range plan.Semantic.ResolvedColumns { + counts[dynamicMap] = len(columns) + } + return counts +} + func recipeMaterializer(recipeEngine *engine.Engine, bundleTarget publication.Target, registry *materializationarango.Registry, degradation error, logger *slog.Logger, batchRows, batchBytes int) func(context.Context, string, recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { return func(ctx context.Context, name string, bindings recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { if bundleTarget == nil { @@ -130,11 +143,37 @@ func recipeMaterializer(recipeEngine *engine.Engine, bundleTarget publication.Ta bindings.IncludeAuthResourcePath = true var identity publication.BundleIdentity _, err := recipeEngine.Materialize(ctx, name, bindings, func(ctx context.Context, full engine.Resolved) error { + logger.Info("recipe materialization resolved", + "name", name, + "project", bindings.Project, + "resolved_schema_digest", full.ResolvedSchemaDigest, + "dynamic_column_counts", recipeResolvedDynamicColumnCounts(full), + ) var err error identity, err = publishResolvedRecipe(ctx, recipeEngine, bundleTarget, name, bindings, full, batchRows, batchBytes) return err }) if err != nil { + var dynamicDrift *engine.DynamicDriftError + if errors.As(err, &dynamicDrift) { + logger.Error("recipe materialization dynamic schema drift", + "name", name, + "project", bindings.Project, + "dynamic_map", dynamicDrift.DynamicName, + "unexpected_key", dynamicDrift.Key, + "frozen_key_count", dynamicDrift.FrozenKeyCount, + ) + err = dataframeerrors.Wrap( + err, + dataframeerrors.CodeSchemaConflict, + "recipe dynamic-column schema does not match observed data", + dataframeerrors.WithDetails(map[string]any{ + "dynamicMap": dynamicDrift.DynamicName, + "unexpectedKey": dynamicDrift.Key, + "frozenKeyCount": dynamicDrift.FrozenKeyCount, + }), + ) + } logger.Error("recipe materialization failed", "name", name, "project", bindings.Project, "error", err.Error()) return graphresolver.RecipeExecution{}, err } @@ -143,7 +182,15 @@ func recipeMaterializer(recipeEngine *engine.Engine, bundleTarget publication.Ta logger.Error("load published recipe execution failed", "name", name, "project", bindings.Project, "error", err.Error()) return graphresolver.RecipeExecution{}, fmt.Errorf("load published recipe execution: %w", err) } - return graphresolver.RecipeExecution{ID: published.ID, Name: name, RecipeDigest: identity.RecipeDigest, ResolvedSchemaDigest: identity.SchemaDigest, SourceGeneration: identity.DatasetGeneration, State: string(publication.BundlePublished)}, nil + outputs := make([]graphresolver.RecipeExecutionOutput, 0, len(published.Outputs)) + for _, output := range published.Outputs { + rowCount := int(output.RowCount) + outputs = append(outputs, graphresolver.RecipeExecutionOutput{ + Name: output.Name, State: string(output.State.Canonical()), RowCount: &rowCount, + Columns: append([]publication.PhysicalColumn(nil), output.Columns...), + }) + } + return graphresolver.RecipeExecution{ID: published.ID, Name: name, RecipeDigest: identity.RecipeDigest, ResolvedSchemaDigest: identity.SchemaDigest, SourceGeneration: identity.DatasetGeneration, State: string(published.State.Canonical()), Outputs: outputs}, nil } } diff --git a/internal/server/routes.go b/internal/server/routes.go index 2d4650a7..c38b8b3c 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -8,16 +8,27 @@ import ( "github.com/calypr/loom/internal/api/graphql/graph/resolver" api "github.com/calypr/loom/internal/api/http" "github.com/calypr/loom/internal/authscope" + publication "github.com/calypr/loom/internal/dataframe/publication" "github.com/calypr/loom/internal/dataset" ) -func registerRoutes(server *api.HTTPServer, resourceService *loadapi.Service, snapshotService *loadapi.SnapshotService, releaseService *dataset.ReleaseService, authorizer authscope.Authorizer, graphResolver *resolver.Resolver) error { +func registerRoutes(server *api.HTTPServer, resourceService *loadapi.Service, snapshotService *loadapi.SnapshotService, releaseService *dataset.ReleaseService, authorizer authscope.Authorizer, graphResolver *resolver.Resolver, optional ...any) error { resourceHandler, err := loadapi.NewHandler(loadapi.Config{Service: resourceService, Authorizer: authorizer, Snapshots: snapshotService, Releases: releaseService}) if err != nil { return fmt.Errorf("create resource load handler: %w", err) } - resourceHandler.RegisterResourceRoute(server.App()) - resourceHandler.RegisterSnapshotRoutes(server.App()) + resourceHandler.RegisterRoutes(server.App()) + var releases publication.BundleCatalog + var scopes *authscope.ScopeResolver + for _, value := range optional { + switch typed := value.(type) { + case publication.BundleCatalog: + releases = typed + case *authscope.ScopeResolver: + scopes = typed + } + } + api.RegisterRecipeExecutionRoute(server.App(), releases, scopes) graphapi.RegisterRoutes(server.App(), graphapi.RouteConfig{Handler: graphapi.NewHandler(graphResolver, server.Logger()), Playground: graphapi.NewPlaygroundHandler("/graphql/graph"), Sandbox: graphapi.NewApolloSandboxHandler("/graphql/graph")}) return nil } diff --git a/internal/server/routes_test.go b/internal/server/routes_test.go index a2fa665e..4c2fb6f7 100644 --- a/internal/server/routes_test.go +++ b/internal/server/routes_test.go @@ -19,7 +19,7 @@ func (routeRunner) Run(context.Context, loadapi.ImportRequest, ingest.EventSink) return ingest.LoadSummary{}, nil } -func TestRegisterRoutesExposesResourceLoadOnly(t *testing.T) { +func TestRegisterRoutesExposesGenerationReleaseWorkflow(t *testing.T) { server, err := api.NewHTTPServer(api.HTTPConfig{ Authenticator: authscope.StaticAuthenticator{}, Authorizer: authscope.AllowAllAuthorizer{}, @@ -39,9 +39,6 @@ func TestRegisterRoutesExposesResourceLoadOnly(t *testing.T) { method string path string }{ - {http.MethodGet, "/api/v1/raw"}, - {http.MethodPut, "/api/v1/raw"}, - {http.MethodPost, "/api/v1/datasets/project/generations/generation"}, {http.MethodGet, "/api/v1/datasets/project/generations/generation/export"}, {http.MethodPost, "/loom/api/v1/dataframe/export"}, } { @@ -54,6 +51,25 @@ func TestRegisterRoutesExposesResourceLoadOnly(t *testing.T) { t.Fatalf("route %s %s status = %d, want %d", request.method, request.path, resp.StatusCode, http.StatusNotFound) } } + for _, request := range []struct { + method string + path string + want int + }{ + {http.MethodGet, "/api/v1/raw", http.StatusMethodNotAllowed}, + {http.MethodPut, "/api/v1/raw", http.StatusUnsupportedMediaType}, + {http.MethodPost, "/api/v1/datasets/project/generations/generation", http.StatusUnsupportedMediaType}, + {http.MethodPost, "/api/v1/datasets/project/generations/generation/activate", http.StatusBadRequest}, + } { + resp, err := server.App().Test(httptest.NewRequest(request.method, request.path, nil)) + if err != nil { + t.Fatalf("request %s %s: %v", request.method, request.path, err) + } + _ = resp.Body.Close() + if resp.StatusCode != request.want { + t.Fatalf("route %s %s status = %d, want %d", request.method, request.path, resp.StatusCode, request.want) + } + } resp, err := server.App().Test(httptest.NewRequest(http.MethodPut, "/api/v1/projects/project/resources/Patient", nil)) if err != nil { t.Fatal(err) diff --git a/internal/server/server.go b/internal/server/server.go index 875bcbda..a909ddbf 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -95,6 +95,9 @@ func run(ctx context.Context, serverConfig Config) error { if err := lifecycleClient.Bootstrap(ctx, dataframeContractBootstrapSpec()); err != nil { degradation = recordDegradation(logger, degradation, "bootstrap dataframe contract registry", err) } + if err := lifecycleClient.Bootstrap(ctx, recipearango.RevisionBootstrapSpec()); err != nil { + degradation = recordDegradation(logger, degradation, "bootstrap recipe revision registry", err) + } recipeRegistry, err := recipearango.New(lifecycleClient) if err != nil { return fmt.Errorf("create recipe registry: %w", err) @@ -179,8 +182,13 @@ func run(ctx context.Context, serverConfig Config) error { } materializationReader = &published.Reader{ClickHouse: clickhouse, Catalog: publishedRegistry, Logger: logger, MaxPage: 1000, ActiveManifestResolver: activeManifestResolver} } + recipeRevisions, err := recipearango.NewRevisionRegistry(lifecycleClient) + if err != nil { + return fmt.Errorf("create recipe revision registry: %w", err) + } recipeEngine, err := engine.New(engine.Config{ Registry: recipeRegistry, + Revisions: recipeRevisions, ResolveBundle: recipeSchemaResolver(catalogStore.DiscoverFields, discoveryCache), QueryRows: func(ctx context.Context, query string, batchSize int, bindVars map[string]any, visit func(map[string]any) error) error { started := time.Now() @@ -313,6 +321,7 @@ func run(ctx context.Context, serverConfig Config) error { return explainCompiledQuery(ctx, lifecycleClient, compiled) }}, RecipeAuthorizer: recipeAuthorization{resolver: scopeResolver}, + RecipeRevisions: recipeRevisions, RecipeExecutions: graphresolver.NewAuthorizedRecipeExecutionReader(publishedRegistry, scopeResolver), RecipeMaterialize: recipeMaterializer(recipeEngine, bundleTarget, publishedRegistry, degradation, logger, serverConfig.Server.RecipeBatchRows, serverConfig.Server.RecipeBatchBytes), ExactMaterializationStarter: exactStarter, @@ -327,8 +336,11 @@ func run(ctx context.Context, serverConfig Config) error { Schema: serverConfig.Server.Schema, }} resourceService, err := loadapi.NewService(loadapi.ServiceConfig{ - Runner: ingestRunner, GenerationRunner: ingestRunner, - Logger: logger, + Runner: ingestRunner, + GenerationRunner: ingestRunner, + GenerationActivator: lifecycleStore, + DataframeReleases: publishedRegistry, + Logger: logger, OnSuccess: func(project string) { discoveryCache.InvalidateProject(project) if scopeResolver != nil { @@ -366,7 +378,7 @@ func run(ctx context.Context, serverConfig Config) error { if err != nil { return fmt.Errorf("create HTTP server: %w", err) } - if err := registerRoutes(server, resourceService, snapshotService, releaseService, authorizer, resolver); err != nil { + if err := registerRoutes(server, resourceService, snapshotService, releaseService, authorizer, resolver, publishedRegistry, scopeResolver); err != nil { return fmt.Errorf("register HTTP routes: %w", err) } if publicationWorker != nil { From 9b3a85852e88d6a90837b58fa4a2ca6f50d516a0 Mon Sep 17 00:00:00 2001 From: matthewpeterkort Date: Tue, 11 Aug 2026 13:26:23 -0700 Subject: [PATCH 02/15] working dataframer --- docs/DATAFRAMER_RECIPE_REFERENCE.md | 16 ++ internal/api/bulk/dump/export.go | 4 +- internal/api/bulk/load/service.go | 38 +-- internal/api/bulk/load/service_test.go | 16 +- internal/api/graphql/graph/handler.go | 78 +++++- internal/api/graphql/graph/handler_test.go | 35 +++ .../graphql/graph/http_integration_test.go | 36 +++ .../graph/resolver/schema.resolvers.go | 10 +- internal/api/http/errors.go | 8 +- internal/api/http/recipe_execution.go | 15 +- internal/api/http/recipe_execution_test.go | 16 ++ .../compiler/lower/recipe_compile.go | 2 + .../compiler/lower/recipe_dynamic_columns.go | 2 +- .../dataframe/compiler/lower/recipe_schema.go | 28 ++- internal/dataframe/publication/bundle.go | 23 +- .../publication/clickhouse/bundle_store.go | 231 ++++++++---------- .../clickhouse/clickhouse_bundle_test.go | 67 ----- .../publication/clickhouse/target.go | 50 ++++ internal/dataframe/publication/runner.go | 67 ++++- internal/dataframe/publication/runner_test.go | 61 +++++ internal/dataframe/publication/types.go | 60 ++++- internal/dataframe/published/federation.go | 10 +- .../dataframe/published/federation_test.go | 39 +++ internal/dataframe/recipe/document_types.go | 14 +- internal/dataframe/recipe/exec/persistent.go | 6 - .../dataframe/recipe/exec/persistent_test.go | 4 +- internal/dataframe/recipe/schema/discovery.go | 7 +- .../recipe/schema/extension_columns.go | 1 + .../dataframe/semantic/recipe_plan_output.go | 3 +- .../dataframe/semantic/recipe_plan_types.go | 10 +- .../dataframe/semantic/recipe_projection.go | 6 +- .../dataframe/semantic/recipe_rich_shaping.go | 1 + internal/dataframe/semantic/semantic_plan.go | 2 + internal/dataset/active_resolver.go | 2 +- internal/dataset/arango/document_codec.go | 4 + internal/dataset/arango/manifest_lifecycle.go | 16 +- .../dataset/arango/snapshot_release_store.go | 22 +- internal/dataset/arango/store_test.go | 52 +++- internal/dataset/manifest.go | 3 - internal/server/recipe_publication.go | 12 +- internal/server/server.go | 2 +- internal/store/clickhouse/client.go | 34 +++ internal/store/clickhouse/integration_test.go | 19 ++ 43 files changed, 838 insertions(+), 294 deletions(-) create mode 100644 internal/api/http/recipe_execution_test.go diff --git a/docs/DATAFRAMER_RECIPE_REFERENCE.md b/docs/DATAFRAMER_RECIPE_REFERENCE.md index 7f527a93..a1e1b9d0 100644 --- a/docs/DATAFRAMER_RECIPE_REFERENCE.md +++ b/docs/DATAFRAMER_RECIPE_REFERENCE.md @@ -357,6 +357,22 @@ selector, and logical type are included in the resolved schema digest. `dynamicColumns` remains available for general key/value arrays and retains its existing behavior. +### Published schema finalization + +Preflight and preview report the conservative candidate schema produced by +catalog discovery. During publication, discovered columns that are missing or +null in every staged row are removed (empty repeated arrays are also empty); +`false`, zero, and empty strings count as populated. Authored and Loom-owned +columns are always retained. The published execution metadata, ClickHouse +table, Explorer schema, and API responses all use this retained schema. + +Published `schemaDigest` values use the versioned final-schema algorithm over +the recipe digest, scope digest, dataset generation, output order, and ordered +logical column contracts. Physical table names and discovery provenance are +excluded. Newly materialized outputs therefore may have a different digest +from their preflight candidate, and an existing publication changes only after +normal rematerialization. + Use a dynamic column family when FHIR represents repeated key/value metadata and each known key should become its own column. This is the correct tool for identifiers, category coding, and attachment extensions. It is **not** a diff --git a/internal/api/bulk/dump/export.go b/internal/api/bulk/dump/export.go index 2466f6f9..2ba42ee3 100644 --- a/internal/api/bulk/dump/export.go +++ b/internal/api/bulk/dump/export.go @@ -56,7 +56,7 @@ func (e ArangoRawExporter) resolveManifest(ctx context.Context, project, generat if err != nil { return publication.Manifest{}, classifyRawExportError(err) } - if !manifest.IsReady() { + if !manifest.IsStaged() { return publication.Manifest{}, dataframeerrors.NewError(dataframeerrors.CodeNoActiveGeneration, "") } return manifest, nil @@ -69,7 +69,7 @@ func (e ArangoRawExporter) resolveManifest(ctx context.Context, project, generat if err != nil { return publication.Manifest{}, classifyRawExportError(err) } - if !manifest.IsReady() { + if !manifest.IsStaged() { return publication.Manifest{}, dataframeerrors.NewError(dataframeerrors.CodeNoActiveGeneration, "") } return manifest, nil diff --git a/internal/api/bulk/load/service.go b/internal/api/bulk/load/service.go index c7cc2ff1..420fd8df 100644 --- a/internal/api/bulk/load/service.go +++ b/internal/api/bulk/load/service.go @@ -183,7 +183,7 @@ func (s *Service) RunGeneration(ctx context.Context, req GenerationLoadRequest) } manifest, err := s.generationActivator.ReadManifest(ctx, ref) switch { - case err == nil && manifest.IsReady(): + case err == nil && manifest.IsStaged(): s.logger.Info("reusing ready generation", "project", req.Project, "generation", req.Generation) return &GenerationLoadResult{ Project: req.Project, Generation: req.Generation, @@ -209,44 +209,50 @@ func (s *Service) RunGeneration(ctx context.Context, req GenerationLoadRequest) } // ActivateGeneration performs the release switch only after the exact -// dataframe bundle supplied by the caller is durably READY and remains the -// active pointer for its recipe/generation namespace. +// dataframe bundle supplied by the caller is durably successful and remains +// the active pointer for its recipe/generation namespace. func (s *Service) ActivateGeneration(ctx context.Context, project, generation, executionID string) error { + fail := func(err error) error { + if err != nil { + s.logger.Error("generation release activation failed", "project", project, "generation", generation, "dataframe_execution_id", executionID, "error", err) + } + return err + } if s.generationActivator == nil || s.dataframeReleases == nil { - return errors.New("generation release activation is not configured") + return fail(errors.New("generation release activation is not configured")) } ref, err := publication.NewRef(project, generation) if err != nil { - return err + return fail(err) } execution, err := s.dataframeReleases.GetExecution(ctx, executionID) if err != nil { - return fmt.Errorf("load dataframe release %q: %w", executionID, err) + return fail(fmt.Errorf("load dataframe release %q: %w", executionID, err)) } - if execution.Project != project || execution.DatasetGeneration != generation || execution.State != dataframepublication.BundleReady || len(execution.Outputs) == 0 { - return fmt.Errorf("dataframe release %q is not a READY bundle for %s/%s", executionID, project, generation) + if execution.Project != project || execution.DatasetGeneration != generation || !execution.State.Successful() || len(execution.Outputs) == 0 { + return fail(fmt.Errorf("dataframe release %q is not a published bundle for %s/%s", executionID, project, generation)) } for _, output := range execution.Outputs { - if output.State != dataframepublication.BundleReady { - return fmt.Errorf("dataframe release %q output %q is not READY", executionID, output.Name) + if !output.State.Successful() { + return fail(fmt.Errorf("dataframe release %q output %q is not published", executionID, output.Name)) } } pointer, err := s.dataframeReleases.GetPointer(ctx, execution.PointerName()) if err != nil { - return fmt.Errorf("resolve dataframe release pointer: %w", err) + return fail(fmt.Errorf("resolve dataframe release pointer: %w", err)) } if pointer.ExecutionID != execution.ID { - return fmt.Errorf("dataframe release %q is no longer active", executionID) + return fail(fmt.Errorf("dataframe release %q is no longer active", executionID)) } manifest, err := s.generationActivator.ReadManifest(ctx, ref) if err != nil { - return fmt.Errorf("read generation release: %w", err) + return fail(fmt.Errorf("read generation release: %w", err)) } - if !manifest.IsReady() { - return fmt.Errorf("generation %s/%s is not READY", project, generation) + if !manifest.IsStaged() { + return fail(fmt.Errorf("generation %s/%s is not READY", project, generation)) } if err := s.generationActivator.Activate(ctx, manifest); err != nil { - return fmt.Errorf("activate generation release: %w", err) + return fail(fmt.Errorf("activate generation release: %w", err)) } if s.onSuccess != nil { s.onSuccess(project) diff --git a/internal/api/bulk/load/service_test.go b/internal/api/bulk/load/service_test.go index ceec4132..bed03bf0 100644 --- a/internal/api/bulk/load/service_test.go +++ b/internal/api/bulk/load/service_test.go @@ -152,10 +152,10 @@ func TestActivateGenerationRejectsInvalidDataframeRelease(t *testing.T) { readyManifest := activationManifest(t, "project-a", "generation-a") base := dataframepublication.BundleExecution{ ID: "release-1", BundleIdentity: dataframepublication.BundleIdentity{Project: "project-a", DatasetGeneration: "generation-a", Name: "all"}, - State: dataframepublication.BundleReady, UpdatedAt: time.Now().UTC(), + State: dataframepublication.BundlePublished, UpdatedAt: time.Now().UTC(), Outputs: []dataframepublication.BundleOutputRecord{ - {Name: "Patient", State: dataframepublication.BundleReady}, - {Name: "Observation", State: dataframepublication.BundleReady}, + {Name: "Patient", State: dataframepublication.BundlePublished}, + {Name: "Observation", State: dataframepublication.BundlePublished}, }, } tests := []struct { @@ -200,14 +200,14 @@ func TestActivateGenerationRejectsInvalidDataframeRelease(t *testing.T) { } } -func TestActivateGenerationActivatesReadyAllOutputBundle(t *testing.T) { +func TestActivateGenerationActivatesPublishedAllOutputBundle(t *testing.T) { manifest := activationManifest(t, "project-a", "generation-a") execution := dataframepublication.BundleExecution{ ID: "release-1", BundleIdentity: dataframepublication.BundleIdentity{Project: "project-a", DatasetGeneration: "generation-a", Name: "all"}, - State: dataframepublication.BundleReady, UpdatedAt: time.Now().UTC(), + State: dataframepublication.BundlePublished, UpdatedAt: time.Now().UTC(), Outputs: []dataframepublication.BundleOutputRecord{ - {Name: "Patient", State: dataframepublication.BundleReady}, - {Name: "Observation", State: dataframepublication.BundleReady}, + {Name: "Patient", State: dataframepublication.BundlePublished}, + {Name: "Observation", State: dataframepublication.BundlePublished}, }, } activator := &activationManifestStore{manifest: manifest} @@ -227,7 +227,7 @@ func TestActivateGenerationActivatesReadyAllOutputBundle(t *testing.T) { if activator.readCalls != 1 || activator.activateCalls != 1 || !calledSuccess { t.Fatalf("activation calls = read %d activate %d success %v", activator.readCalls, activator.activateCalls, calledSuccess) } - if activator.activated.Dataset != manifest.Dataset || !activator.activated.IsReady() { + if activator.activated.Dataset != manifest.Dataset || !activator.activated.IsStaged() { t.Fatalf("activated manifest = %#v", activator.activated) } } diff --git a/internal/api/graphql/graph/handler.go b/internal/api/graphql/graph/handler.go index 7a6fe94e..c2608b69 100644 --- a/internal/api/graphql/graph/handler.go +++ b/internal/api/graphql/graph/handler.go @@ -1,6 +1,7 @@ package graphqlapi import ( + "bytes" "context" "encoding/json" "errors" @@ -78,10 +79,85 @@ func NewHandler(root *resolver.Resolver, loggers ...*slog.Logger) http.Handler { r.Header.Set("X-Request-ID", requestID) } r = r.WithContext(httpapi.ContextWithRequestID(r.Context(), r.Header.Get("X-Request-ID"))) - server.ServeHTTP(w, r) + serveGraphQLResponse(w, r, server) }) } +type bufferedGraphQLResponse struct { + header http.Header + body bytes.Buffer + status int +} + +func (w *bufferedGraphQLResponse) Header() http.Header { return w.header } + +func (w *bufferedGraphQLResponse) WriteHeader(status int) { + if w.status == 0 { + w.status = status + } +} + +func (w *bufferedGraphQLResponse) Write(body []byte) (int, error) { + if w.status == 0 { + w.status = http.StatusOK + } + return w.body.Write(body) +} + +func (w *bufferedGraphQLResponse) Flush() {} + +func serveGraphQLResponse(destination http.ResponseWriter, request *http.Request, next http.Handler) { + captured := &bufferedGraphQLResponse{header: make(http.Header)} + next.ServeHTTP(captured, request) + status := captured.status + if status == 0 { + status = http.StatusOK + } + if status < http.StatusBadRequest { + if failureStatus := graphqlFailureStatus(captured.body.Bytes()); failureStatus != 0 { + status = failureStatus + } + } + for key, values := range captured.header { + for _, value := range values { + destination.Header().Add(key, value) + } + } + destination.WriteHeader(status) + _, _ = destination.Write(captured.body.Bytes()) +} + +func graphqlFailureStatus(body []byte) int { + var payload struct { + Data json.RawMessage `json:"data"` + Errors []struct { + Extensions map[string]any `json:"extensions"` + } `json:"errors"` + } + if json.Unmarshal(body, &payload) != nil || len(payload.Errors) == 0 { + return 0 + } + data := bytes.TrimSpace(payload.Data) + if len(data) > 0 && !bytes.Equal(data, []byte("null")) { + // GraphQL can legitimately return useful partial data alongside field + // errors. Keep HTTP 200 for that case; only failed operations are lifted + // into the HTTP error contract. + return 0 + } + status := http.StatusBadRequest + for _, graphErr := range payload.Errors { + code, _ := graphErr.Extensions["code"].(string) + candidate := httpapi.StatusForErrorCode(code) + if candidate >= http.StatusInternalServerError { + return candidate + } + if candidate > status { + status = candidate + } + } + return status +} + func errorChain(err error) string { if err == nil { return "" diff --git a/internal/api/graphql/graph/handler_test.go b/internal/api/graphql/graph/handler_test.go index 9b576bb2..ec232dbc 100644 --- a/internal/api/graphql/graph/handler_test.go +++ b/internal/api/graphql/graph/handler_test.go @@ -2,6 +2,8 @@ package graphqlapi import ( "errors" + "net/http" + "net/http/httptest" "strings" "testing" @@ -19,3 +21,36 @@ func TestErrorChainIncludesWrappedBackendCause(t *testing.T) { t.Fatalf("error chain omitted backend cause: %q", chain) } } + +func TestGraphQLBackendFailureUsesServiceUnavailable(t *testing.T) { + status := serveCapturedGraphQL(t, `{"errors":[{"extensions":{"code":"BACKEND_UNAVAILABLE","retryable":true}}],"data":null}`) + if status != http.StatusServiceUnavailable { + t.Fatalf("status = %d, want %d", status, http.StatusServiceUnavailable) + } +} + +func TestGraphQLValidationFailureUsesBadRequest(t *testing.T) { + status := serveCapturedGraphQL(t, `{"errors":[{"extensions":{"code":"GRAPHQL_VALIDATION_FAILED","retryable":false}}]}`) + if status != http.StatusBadRequest { + t.Fatalf("status = %d, want %d", status, http.StatusBadRequest) + } +} + +func TestGraphQLPartialDataKeepsSuccessfulTransportStatus(t *testing.T) { + status := serveCapturedGraphQL(t, `{"errors":[{"extensions":{"code":"DATASET_NOT_FOUND","retryable":false}}],"data":{"optionalDataset":null,"healthyField":"value"}}`) + if status != http.StatusOK { + t.Fatalf("status = %d, want %d", status, http.StatusOK) + } +} + +func serveCapturedGraphQL(t *testing.T, body string) int { + t.Helper() + next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(body)) + }) + recorder := httptest.NewRecorder() + serveGraphQLResponse(recorder, httptest.NewRequest(http.MethodPost, "/graphql/graph", nil), next) + return recorder.Code +} diff --git a/internal/api/graphql/graph/http_integration_test.go b/internal/api/graphql/graph/http_integration_test.go index 416dad9b..d46060e9 100644 --- a/internal/api/graphql/graph/http_integration_test.go +++ b/internal/api/graphql/graph/http_integration_test.go @@ -171,6 +171,42 @@ func TestGraphQLSchemaIntrospectionEndpoint(t *testing.T) { } } +func TestProjectDataframeDatasetsResolverIsWired(t *testing.T) { + graphResolver := graphresolver.NewResolver(graphresolver.ResolverConfig{}) + server, err := newGraphServer(graphResolver, authscope.StaticAuthenticator{Principal: authscope.Principal{Subject: "u1", Projects: []string{"P1"}}}) + if err != nil { + t.Fatal(err) + } + + req := httptest.NewRequest(http.MethodPost, "/graphql/graph", strings.NewReader(`{"query":"query { projectDataframeDatasets(projectId: \"P1\") { id } }"}`)) + req.Header.Set("Content-Type", "application/json") + resp, err := server.App().Test(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusServiceUnavailable { + t.Fatalf("status = %d, want %d", resp.StatusCode, http.StatusServiceUnavailable) + } + var payload struct { + Errors []struct { + Message string `json:"message"` + Extensions struct { + Code string `json:"code"` + } `json:"extensions"` + } `json:"errors"` + } + if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil { + t.Fatal(err) + } + if len(payload.Errors) != 1 || payload.Errors[0].Extensions.Code != "BACKEND_UNAVAILABLE" { + t.Fatalf("errors = %#v", payload.Errors) + } + if strings.Contains(payload.Errors[0].Message, "not implemented") { + t.Fatalf("resolver is not wired: %s", payload.Errors[0].Message) + } +} + func TestGraphQLRunDataframeMutation(t *testing.T) { dfService := runtime.NewService(runtime.ServiceConfig{ QueryRows: func(ctx context.Context, query string, _ int, bindVars map[string]any, visit func(map[string]any) error) error { diff --git a/internal/api/graphql/graph/resolver/schema.resolvers.go b/internal/api/graphql/graph/resolver/schema.resolvers.go index 2aea813b..8c8103af 100644 --- a/internal/api/graphql/graph/resolver/schema.resolvers.go +++ b/internal/api/graphql/graph/resolver/schema.resolvers.go @@ -277,7 +277,15 @@ func (r *queryResolver) DataframeDatasets(ctx context.Context) ([]*model.Datafra // ProjectDataframeDatasets is the resolver for the projectDataframeDatasets field. func (r *queryResolver) ProjectDataframeDatasets(ctx context.Context, projectID string) ([]*model.DataframeMaterialization, error) { - panic(fmt.Errorf("not implemented: ProjectDataframeDatasets - projectDataframeDatasets")) + values, err := r.materializations.ProjectDatasets(ctx, projectID) + if err != nil { + return nil, err + } + result := make([]*model.DataframeMaterialization, 0, len(values)) + for _, value := range values { + result = append(result, materializationapi.Model(value)) + } + return result, nil } // DataframeDataset is the resolver for the dataframeDataset field. diff --git a/internal/api/http/errors.go b/internal/api/http/errors.go index b3355dfe..669fe4eb 100644 --- a/internal/api/http/errors.go +++ b/internal/api/http/errors.go @@ -123,6 +123,12 @@ func MapDataframeError(err error, requestID string) MappedError { } } +// StatusForErrorCode exposes the same semantic HTTP classification used by +// REST handlers to transports that already have a stable Loom error code. +func StatusForErrorCode(code string) int { + return statusForCode(normalizeHTTPCode(code), 0) +} + func preflightDetails(err *ingest.PreflightError) map[string]any { if err == nil || len(err.Report.Issues) == 0 { return nil @@ -148,7 +154,7 @@ func normalizeHTTPCode(code string) string { code = strings.ToUpper(strings.TrimSpace(code)) code = strings.ReplaceAll(code, "-", "_") switch code { - case "PROJECT_REQUIRED", "ROOT_RESOURCE_TYPE_REQUIRED", "UNAUTHORIZED_PROJECT", "UNKNOWN_FIELD", "FIELD_NOT_POPULATED", "INVALID_TRAVERSAL", "UNSAFE_TRAVERSAL_ROUTE", "INVALID_FILTER", "UNBOUNDED_PIVOT", "INVALID_PIVOT_COLUMN", "INVALID_SLICE", "PLAN_TOO_EXPENSIVE", "INVALID_CURSOR", "STALE_CURSOR", "DATASET_GENERATION_CHANGED", "UNSUPPORTED_EXPORT_FORMAT", "CLIENT_CANCELED", "BACKEND_UNAVAILABLE", "DATASET_NOT_FOUND", "SCHEMA_CONFLICT", "INVALID_RESOURCE_TYPE", "NO_ACTIVE_GENERATION", "RESOURCE_DECODE_FAILED", "REFERENCE_NOT_RESOLVED", "QUERY_DEPTH_EXCEEDED", "INVALID_REQUEST", "INVALID_DATA", "UNAUTHENTICATED", "FORBIDDEN", "RECIPE_NOT_FOUND", "RECIPE_RESOLUTION_FAILED", "RECIPE_EXECUTION_NOT_FOUND", "EXPORT_LIMIT_EXCEEDED", "INGEST_PREFLIGHT_FAILED", "GENERATION_LOAD_INCOMPLETE", "GENERATION_ACTIVATION_UNKNOWN", "INVALID_GENERATION_FILE", "DUPLICATE_GENERATION_FILE", "PUBLICATION_IN_PROGRESS", "PUBLICATION_CONFLICT", "PUBLICATION_LEASE_LOST", "OUTPUT_ENCODING_FAILED", "NOT_FOUND", "METHOD_NOT_ALLOWED", "PAYLOAD_TOO_LARGE": + case "PROJECT_REQUIRED", "ROOT_RESOURCE_TYPE_REQUIRED", "UNAUTHORIZED_PROJECT", "UNKNOWN_FIELD", "FIELD_NOT_POPULATED", "INVALID_TRAVERSAL", "UNSAFE_TRAVERSAL_ROUTE", "INVALID_FILTER", "UNBOUNDED_PIVOT", "INVALID_PIVOT_COLUMN", "INVALID_SLICE", "PLAN_TOO_EXPENSIVE", "INVALID_CURSOR", "STALE_CURSOR", "DATASET_GENERATION_CHANGED", "UNSUPPORTED_EXPORT_FORMAT", "CLIENT_CANCELED", "BACKEND_UNAVAILABLE", "DATASET_NOT_FOUND", "SCHEMA_CONFLICT", "INVALID_RESOURCE_TYPE", "NO_ACTIVE_GENERATION", "RESOURCE_DECODE_FAILED", "REFERENCE_NOT_RESOLVED", "QUERY_DEPTH_EXCEEDED", "INVALID_REQUEST", "INVALID_DATA", "UNAUTHENTICATED", "FORBIDDEN", "RECIPE_NOT_FOUND", "RECIPE_RESOLUTION_FAILED", "RECIPE_EXECUTION_NOT_FOUND", "EXPORT_LIMIT_EXCEEDED", "INGEST_PREFLIGHT_FAILED", "GENERATION_LOAD_INCOMPLETE", "GENERATION_ACTIVATION_UNKNOWN", "INVALID_GENERATION_FILE", "DUPLICATE_GENERATION_FILE", "PUBLICATION_IN_PROGRESS", "PUBLICATION_CONFLICT", "PUBLICATION_LEASE_LOST", "OUTPUT_ENCODING_FAILED", "NOT_FOUND", "METHOD_NOT_ALLOWED", "PAYLOAD_TOO_LARGE", "GRAPHQL_VALIDATION_FAILED": return code default: return "INTERNAL_ERROR" diff --git a/internal/api/http/recipe_execution.go b/internal/api/http/recipe_execution.go index 1f6a7736..91a9f31e 100644 --- a/internal/api/http/recipe_execution.go +++ b/internal/api/http/recipe_execution.go @@ -49,12 +49,23 @@ func RegisterRecipeExecutionRoute(app *fiber.App, catalog publication.BundleCata } columns = append(columns, fiber.Map{"name": column.Name, "semanticPath": column.SemanticPath, "clickhouseType": column.ClickHouse, "logicalType": logical, "nullable": nullable, "repeated": repeated, "filterable": filterable, "sortable": sortable, "aggregatable": aggregatable}) } - outputs = append(outputs, fiber.Map{"name": output.Name, "dataType": output.Name, "state": string(output.State), "rowCount": output.RowCount, "columns": columns}) + outputs = append(outputs, fiber.Map{"name": output.Name, "dataType": output.Name, "state": recipeExecutionHTTPState(output.State), "rowCount": output.RowCount, "columns": columns}) } - return c.JSON(fiber.Map{"id": execution.ID, "projectId": execution.Project, "datasetGeneration": execution.DatasetGeneration, "recipeDigest": execution.RecipeDigest, "schemaDigest": execution.SchemaDigest, "resolvedSchemaDigest": execution.SchemaDigest, "state": string(execution.State), "outputs": outputs}) + return c.JSON(fiber.Map{"id": execution.ID, "projectId": execution.Project, "datasetGeneration": execution.DatasetGeneration, "recipeDigest": execution.RecipeDigest, "schemaDigest": execution.SchemaDigest, "resolvedSchemaDigest": execution.SchemaDigest, "state": recipeExecutionHTTPState(execution.State), "outputs": outputs}) }) } +// recipeExecutionHTTPState preserves the READY spelling used by the legacy +// Explorer integration. Internally, a successfully committed bundle is +// PUBLISHED; the HTTP execution contract historically exposed that same +// successful state as READY and Gecko still validates that spelling. +func recipeExecutionHTTPState(state publication.BundleState) string { + if state == publication.BundlePublished { + return string(publication.BundleReady) + } + return string(state) +} + func columnCapabilities(clickHouseType string) (logical string, nullable, repeated, filterable, sortable, aggregatable bool) { typ := clickHouseType if strings.HasPrefix(typ, "Nullable(") && strings.HasSuffix(typ, ")") { diff --git a/internal/api/http/recipe_execution_test.go b/internal/api/http/recipe_execution_test.go new file mode 100644 index 00000000..6838d3ae --- /dev/null +++ b/internal/api/http/recipe_execution_test.go @@ -0,0 +1,16 @@ +package httpapi + +import ( + "testing" + + "github.com/calypr/loom/internal/dataframe/publication" +) + +func TestRecipeExecutionHTTPStatePreservesExplorerReadyContract(t *testing.T) { + if got := recipeExecutionHTTPState(publication.BundlePublished); got != "READY" { + t.Fatalf("published HTTP state = %q, want READY", got) + } + if got := recipeExecutionHTTPState(publication.BundleRunning); got != "RUNNING" { + t.Fatalf("running HTTP state = %q, want RUNNING", got) + } +} diff --git a/internal/dataframe/compiler/lower/recipe_compile.go b/internal/dataframe/compiler/lower/recipe_compile.go index 39a196b3..dcd4a617 100644 --- a/internal/dataframe/compiler/lower/recipe_compile.go +++ b/internal/dataframe/compiler/lower/recipe_compile.go @@ -70,6 +70,7 @@ type CompiledOutputColumn struct { Nullable bool Internal bool Identity bool + Discovered bool } type DynamicColumnMetadata struct { @@ -79,6 +80,7 @@ type DynamicColumnMetadata struct { SourceKey string ValueType string AllowUnknownKeys bool + Discovered bool } // CompileResolvedRecipePlan lowers every resolved recipe output into the diff --git a/internal/dataframe/compiler/lower/recipe_dynamic_columns.go b/internal/dataframe/compiler/lower/recipe_dynamic_columns.go index 10b74f16..9a53b248 100644 --- a/internal/dataframe/compiler/lower/recipe_dynamic_columns.go +++ b/internal/dataframe/compiler/lower/recipe_dynamic_columns.go @@ -113,7 +113,7 @@ func appendRecipeDynamicColumns(plan *ir.PhysicalPlan, output semantic.OutputPla if column.Column.SourceKey != "" { semanticPath += "[" + column.Column.SourceKey + "]" } - entry := DynamicColumnMetadata{Name: outputName, SemanticPath: semanticPath, DynamicName: runtimeName, SourceKey: column.Column.SourceKey, ValueType: column.Column.ValueType, AllowUnknownKeys: dynamic.AllowUnknownKeys} + entry := DynamicColumnMetadata{Name: outputName, SemanticPath: semanticPath, DynamicName: runtimeName, SourceKey: column.Column.SourceKey, ValueType: column.Column.ValueType, AllowUnknownKeys: dynamic.AllowUnknownKeys, Discovered: dynamic.Discovered} if projectionIndex, exists := projectionIndexes[outputName]; exists { if output.Collision != "overwrite" { return nil, fmt.Errorf("dynamic column %q collides with another output column", outputName) diff --git a/internal/dataframe/compiler/lower/recipe_schema.go b/internal/dataframe/compiler/lower/recipe_schema.go index a34ed88b..ee492b87 100644 --- a/internal/dataframe/compiler/lower/recipe_schema.go +++ b/internal/dataframe/compiler/lower/recipe_schema.go @@ -56,18 +56,22 @@ func recipeOutputSchema(plan ir.PhysicalPlan, output semantic.OutputPlan, dynami if kind == "" || kind == "unknown" { kind = string(expression.KindString) } - logical[dynamic.Name] = CompiledOutputColumn{Name: dynamic.Name, SemanticPath: dynamic.SemanticPath, Kind: kind, Cardinality: string(expression.OptionalOne), Nullable: true} + logical[dynamic.Name] = CompiledOutputColumn{Name: dynamic.Name, SemanticPath: dynamic.SemanticPath, Kind: kind, Cardinality: string(expression.OptionalOne), Nullable: true, Discovered: dynamic.Discovered} } - addLogical := func(name, semanticPath, kind, cardinality string, nullable bool) { + addLogical := func(name, semanticPath, kind, cardinality string, nullable, discovered bool) { if strings.TrimSpace(name) == "" { return } - if _, exists := logical[name]; exists { + if existing, exists := logical[name]; exists { + // Explicit declarations win collisions under overwrite policies. + if existing.Discovered && !discovered { + logical[name] = CompiledOutputColumn{Name: name, SemanticPath: semanticPath, Kind: kind, Cardinality: cardinality, Nullable: nullable, Discovered: false} + } return } - logical[name] = CompiledOutputColumn{Name: name, SemanticPath: semanticPath, Kind: kind, Cardinality: cardinality, Nullable: nullable} + logical[name] = CompiledOutputColumn{Name: name, SemanticPath: semanticPath, Kind: kind, Cardinality: cardinality, Nullable: nullable, Discovered: discovered} } - addType := func(name, semanticPath string, typ expression.Type) { + addType := func(name, semanticPath string, typ expression.Type, discovered bool) { kind := string(typ.Kind) if kind == "" { kind = string(expression.KindString) @@ -76,23 +80,23 @@ func recipeOutputSchema(plan ir.PhysicalPlan, output semantic.OutputPlan, dynami if cardinality == "" { cardinality = string(expression.RequiredOne) } - addLogical(name, semanticPath, kind, cardinality, typ.Cardinality.Optional()) + addLogical(name, semanticPath, kind, cardinality, typ.Cardinality.Optional(), discovered) } for _, field := range output.Fields { - addType(field.Name, recipeSemanticPath(output.RootResourceType, output.RootResourceType, field.FieldRef, field.Expr.Expression), field.Expr.Type) + addType(field.Name, recipeSemanticPath(output.RootResourceType, output.RootResourceType, field.FieldRef, field.Expr.Expression), field.Expr.Type, field.Discovered) } var addNode func(semantic.SemanticNode, string) addNode = func(node semantic.SemanticNode, prefix string) { for _, field := range node.Fields { name := prefix + field.Name if field.Expr != nil { - addType(name, recipeSemanticPath(output.RootResourceType, node.ResourceType, field.FieldRef, *field.Expr), field.ExprType) + addType(name, recipeSemanticPath(output.RootResourceType, node.ResourceType, field.FieldRef, *field.Expr), field.ExprType, field.Discovered) } else { - addLogical(name, recipeSemanticPath(output.RootResourceType, node.ResourceType, field.FieldRef, expression.Expression{}), string(expression.KindString), string(expression.RequiredOne), true) + addLogical(name, recipeSemanticPath(output.RootResourceType, node.ResourceType, field.FieldRef, expression.Expression{}), string(expression.KindString), string(expression.RequiredOne), true, field.Discovered) } } for _, aggregate := range node.Aggregates { - addLogical(prefix+aggregate.Name, recipeSemanticPath(output.RootResourceType, node.ResourceType, aggregate.FieldRef, expression.Expression{}), string(expression.KindInteger), string(expression.RequiredOne), true) + addLogical(prefix+aggregate.Name, recipeSemanticPath(output.RootResourceType, node.ResourceType, aggregate.FieldRef, expression.Expression{}), string(expression.KindInteger), string(expression.RequiredOne), true, false) } for _, pivot := range node.Pivots { kind := pivot.ValueKind @@ -100,11 +104,11 @@ func recipeOutputSchema(plan ir.PhysicalPlan, output semantic.OutputPlan, dynami kind = expression.KindString } for _, column := range pivot.Columns { - addLogical(prefix+pivot.Name+"__"+sanitizeColumnName(column), recipeSemanticPath(output.RootResourceType, node.ResourceType, pivot.FieldRef, expression.Expression{})+"["+column+"]", string(kind), string(expression.RequiredOne), true) + addLogical(prefix+pivot.Name+"__"+sanitizeColumnName(column), recipeSemanticPath(output.RootResourceType, node.ResourceType, pivot.FieldRef, expression.Expression{})+"["+column+"]", string(kind), string(expression.RequiredOne), true, pivot.Discovered) } } for _, slice := range node.Slices { - addLogical(prefix+slice.Name, recipeSemanticPath(output.RootResourceType, node.ResourceType, "", expression.Expression{})+"."+slice.Name, string(expression.KindObject), string(expression.RequiredOne), true) + addLogical(prefix+slice.Name, recipeSemanticPath(output.RootResourceType, node.ResourceType, "", expression.Expression{})+"."+slice.Name, string(expression.KindObject), string(expression.RequiredOne), true, false) } for _, child := range node.Children { childPrefix := child.Alias diff --git a/internal/dataframe/publication/bundle.go b/internal/dataframe/publication/bundle.go index 4a6b3f1b..98561de2 100644 --- a/internal/dataframe/publication/bundle.go +++ b/internal/dataframe/publication/bundle.go @@ -23,6 +23,15 @@ type AtomicBundleTx interface { Rollback(context.Context) error } +// AtomicBundleSchemaFinalizer is the schema-aware publication extension used +// by targets that can physically drop unpopulated discovered columns before +// verification and pointer activation. +type AtomicBundleSchemaFinalizer interface { + AtomicBundleTx + FinalizeSchema(context.Context, []OutputSchema) error + SetFinalSchemaDigest(string) error +} + // BundleState is the durable lifecycle of a multi-output publication. The // physical ClickHouse tables are never reader-visible until the logical // pointer and PUBLISHED execution are committed atomically. @@ -117,12 +126,14 @@ func (o BundleOutputRecord) Queryable() bool { } type PhysicalColumn struct { - Name string `json:"name"` - SemanticPath string `json:"semanticPath,omitempty"` - ClickHouse string `json:"clickhouseType"` - LogicalType string `json:"logicalType,omitempty"` - Nullable bool `json:"nullable,omitempty"` - Repeated bool `json:"repeated,omitempty"` + Name string `json:"name"` + SemanticPath string `json:"semanticPath,omitempty"` + ClickHouse string `json:"clickhouseType"` + LogicalType string `json:"logicalType,omitempty"` + Nullable bool `json:"nullable,omitempty"` + Repeated bool `json:"repeated,omitempty"` + Provenance ColumnProvenance `json:"provenance,omitempty"` + LoomOwned bool `json:"loomOwned,omitempty"` } type BundleExecution struct { diff --git a/internal/dataframe/publication/clickhouse/bundle_store.go b/internal/dataframe/publication/clickhouse/bundle_store.go index 30b55136..4bc15deb 100644 --- a/internal/dataframe/publication/clickhouse/bundle_store.go +++ b/internal/dataframe/publication/clickhouse/bundle_store.go @@ -5,8 +5,8 @@ import ( "encoding/json" "errors" "fmt" + "log/slog" "regexp" - "sort" "strings" "sync" "time" @@ -51,6 +51,18 @@ type BundleClickHouseStore interface { DropTable(context.Context, string) error } +type bundleColumnDropper interface { + DropColumns(context.Context, string, []string) error +} + +// BundleClickHouseColumnStore is the schema-aware extension implemented by +// production ClickHouse clients. The base store remains compatible with +// lightweight readers/fakes that never request column pruning. +type BundleClickHouseColumnStore interface { + BundleClickHouseStore + DropColumns(context.Context, string, []string) error +} + func NewBundleStore(client BundleClickHouseStore, catalog publication.BundleCatalog) (*ClickHouseBundleStore, error) { if client == nil || catalog == nil { return nil, fmt.Errorf("ClickHouse client and bundle catalog are required") @@ -166,6 +178,16 @@ type clickHouseBundleTx struct { leaseStopErr error } +func (t *clickHouseBundleTx) Idempotent() bool { return t.idempotent } + +func (t *clickHouseBundleTx) ExistingPublishedOutputs() []publication.PublishedOutput { + result := make([]publication.PublishedOutput, 0, len(t.execution.Outputs)) + for _, output := range t.execution.Outputs { + result = append(result, publication.PublishedOutput{Name: output.Name, PhysicalName: output.PhysicalTable, RowCount: output.RowCount, ByteCount: output.ByteCount}) + } + return result +} + const bundleCleanupTimeout = 10 * time.Second func boundedBundleCleanupContext(parent context.Context) (context.Context, context.CancelFunc) { @@ -325,11 +347,89 @@ func (t *clickHouseBundleTx) SetOutputMetadata(name string, columns []publicatio column.LogicalType = logical.Kind column.Nullable = logical.Nullable column.Repeated = logical.Repeated + column.Provenance = logical.Provenance + column.LoomOwned = logical.LoomOwned || logical.IsIdentity || column.Name == "__loom_row_id" || column.Name == "auth_resource_path" || column.Name == "project_id" } } return t.save(context.Background()) } +// FinalizeSchema removes discovered columns that were never populated and +// persists the retained logical/physical schema before verification. +func (t *clickHouseBundleTx) FinalizeSchema(ctx context.Context, schemas []publication.OutputSchema) error { + if t.idempotent { + return nil + } + if t.closed { + return fmt.Errorf("bundle transaction is closed") + } + if err := t.ensureLease(); err != nil { + return err + } + for _, schema := range schemas { + idx := t.outputIndex(schema.Name) + if idx < 0 { + return fmt.Errorf("bundle output %q was not created", schema.Name) + } + record := &t.execution.Outputs[idx] + retained := make(map[string]publication.LogicalColumn, len(schema.Columns)) + for _, column := range schema.Columns { + retained[column.Name] = column + } + var dropped []string + seen := make(map[string]bool, len(record.Columns)) + kept := make([]publication.PhysicalColumn, 0, len(record.Columns)) + for _, column := range record.Columns { + logical, ok := retained[column.Name] + if !ok { + if column.Name == "__loom_row_id" || column.Name == "auth_resource_path" || column.Name == "project_id" || strings.HasPrefix(column.Name, "__loom_") { + seen[column.Name] = true + kept = append(kept, column) + } else if column.Provenance != publication.ColumnDiscovered { + return fmt.Errorf("output %q attempted to remove explicit column %q", schema.Name, column.Name) + } else { + dropped = append(dropped, column.Name) + } + continue + } + seen[column.Name] = true + column.SemanticPath, column.LogicalType = logical.SemanticPath, logical.Kind + column.Nullable, column.Repeated = logical.Nullable, logical.Repeated + column.Provenance, column.LoomOwned = logical.Provenance, logical.LoomOwned || logical.IsIdentity || strings.HasPrefix(column.Name, "__loom_") || column.Name == "auth_resource_path" || column.Name == "project_id" + kept = append(kept, column) + } + if len(dropped) > 0 { + dropper, ok := t.store.clickHouse.(bundleColumnDropper) + if !ok { + return fmt.Errorf("ClickHouse store cannot drop staging columns for output %q", schema.Name) + } + if err := dropper.DropColumns(ctx, record.PhysicalTable, dropped); err != nil { + return err + } + } + record.Columns = kept + for name := range retained { + if !seen[name] { + return fmt.Errorf("output %q retained unknown schema column %q", schema.Name, name) + } + } + } + identity := publication.PublicationIdentity{Name: t.execution.Name, TranslationVersion: t.execution.TranslationVersion, Project: t.execution.Project, DatasetGeneration: t.execution.DatasetGeneration, RecipeDigest: t.execution.RecipeDigest, ScopeDigest: t.execution.ScopeDigest, EngineVersion: t.execution.EngineVersion, AuthScopeMode: t.execution.AuthScopeMode, AuthResourcePaths: append([]string(nil), t.execution.AuthResourcePaths...)} + t.execution.SchemaDigest = publication.FinalSchemaDigest(identity, schemas) + return t.save(ctx) +} + +func (t *clickHouseBundleTx) SetFinalSchemaDigest(digest string) error { + if t.idempotent { + return nil + } + if strings.TrimSpace(digest) == "" { + return fmt.Errorf("final schema digest is required") + } + t.execution.SchemaDigest = digest + return nil +} + func (t *clickHouseBundleTx) InsertRows(ctx context.Context, name string, columns []clickhouse.Column, rows []map[string]any) error { if t.idempotent || len(rows) == 0 { return nil @@ -553,6 +653,7 @@ func (t *clickHouseBundleTx) fail(ctx context.Context, err error) error { } func (t *clickHouseBundleTx) failPhase(ctx context.Context, phase, output string, err error) error { + slog.Error("dataframe bundle publication failed", "phase", phase, "output", output, "error", err) normalized := dataframeerrors.Normalize(err) t.execution.State, t.execution.Error = publication.BundleFailed, err.Error() t.execution.PublishedAt = nil @@ -646,131 +747,3 @@ func (s *ClickHouseBundleStore) Reconcile(ctx context.Context, olderThan time.Ti } return nil } - -// RetentionCandidate describes a physical table that is eligible for cleanup. -// The planner is deliberately non-destructive: callers must perform the -// actual backend operation after applying their own cleanup scheduling and -// retry policy. Candidates are always derived from READY executions only. -type RetentionCandidate struct { - ExecutionID string - PointerName string - PhysicalTable string -} - -// PlanReadyCleanup returns old, unreferenced READY publication tables using -// pointer references as a conservative fallback. For generation-aware -// cleanup, use PlanReadyCleanupForActiveGenerations. -// -// No execution, pointer, lease, or physical table is changed by this method. -// Backend/catalog failures are retryable and return no partial plan. -func (s *ClickHouseBundleStore) PlanReadyCleanup(ctx context.Context) ([]RetentionCandidate, error) { - return s.planReadyCleanup(ctx, nil) -} - -// PlanReadyCleanupForActiveGenerations is the generation-aware retention -// planner. activeGenerations maps each project to the generation selected by -// the project-level release pointer. Because dataframe pointers are -// generation-scoped, callers must provide this map when historical generation -// pointers remain in the catalog; those historical pointers are rollback -// metadata, not currently visible releases. -func (s *ClickHouseBundleStore) PlanReadyCleanupForActiveGenerations(ctx context.Context, activeGenerations map[string]string) ([]RetentionCandidate, error) { - return s.planReadyCleanup(ctx, activeGenerations) -} - -func (s *ClickHouseBundleStore) planReadyCleanup(ctx context.Context, activeGenerations map[string]string) ([]RetentionCandidate, error) { - before := time.Now().UTC().Add(time.Second) - executions, err := s.catalog.ListExecutions(ctx, publication.BundleReady, before) - if err != nil { - return nil, dataframeerrors.Wrap(err, dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) - } - protected := make(map[string]struct{}, len(executions)) - for _, execution := range executions { - if activeGenerations != nil { - activeGeneration, ok := activeGenerations[execution.Project] - if !ok || execution.DatasetGeneration != activeGeneration { - continue - } - } - pointer, pointerErr := s.catalog.GetPointer(ctx, execution.PointerName()) - if pointerErr == nil { - if pointer.ExecutionID == execution.ID { - protected[execution.ID] = struct{}{} - } - continue - } - if !errors.Is(pointerErr, publication.ErrBundleNotFound) { - return nil, dataframeerrors.Wrap(pointerErr, dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) - } - } - - groups := make(map[string][]publication.BundleExecution) - for _, execution := range executions { - if activeGenerations != nil { - if _, ok := activeGenerations[execution.Project]; !ok { - // A partial map is intentionally safe for per-project cleanup: - // projects whose active release was not resolved are out of scope. - protected[execution.ID] = struct{}{} - continue - } - } - key := execution.Project + "\x00" + execution.Name - groups[key] = append(groups[key], execution) - } - for _, group := range groups { - sort.SliceStable(group, func(i, j int) bool { - return bundleCompletionTime(group[i]).After(bundleCompletionTime(group[j])) - }) - priorRetained := false - for _, execution := range group { - if activeGenerations != nil && execution.DatasetGeneration == activeGenerations[execution.Project] { - continue - } - if !completeBundleExecution(execution) || priorRetained { - continue - } - protected[execution.ID] = struct{}{} - priorRetained = true - } - } - - result := make([]RetentionCandidate, 0) - for _, execution := range executions { - if _, keep := protected[execution.ID]; keep { - continue - } - for _, output := range execution.Outputs { - // This is a hard guard against turning retention into a general - // purpose table deletion mechanism. - if strings.TrimSpace(output.PhysicalTable) == "" || !strings.HasPrefix(output.PhysicalTable, s.prefix+"_") { - continue - } - result = append(result, RetentionCandidate{ExecutionID: execution.ID, PointerName: execution.PointerName(), PhysicalTable: output.PhysicalTable}) - } - } - sort.Slice(result, func(i, j int) bool { - if result[i].ExecutionID != result[j].ExecutionID { - return result[i].ExecutionID < result[j].ExecutionID - } - return result[i].PhysicalTable < result[j].PhysicalTable - }) - return result, nil -} - -func completeBundleExecution(execution publication.BundleExecution) bool { - if execution.State != publication.BundleReady || len(execution.Outputs) == 0 { - return false - } - for _, output := range execution.Outputs { - if output.State != publication.BundleReady { - return false - } - } - return true -} - -func bundleCompletionTime(execution publication.BundleExecution) time.Time { - if execution.ReadyAt != nil { - return *execution.ReadyAt - } - return execution.UpdatedAt -} diff --git a/internal/dataframe/publication/clickhouse/clickhouse_bundle_test.go b/internal/dataframe/publication/clickhouse/clickhouse_bundle_test.go index 5010af0b..5df7b30c 100644 --- a/internal/dataframe/publication/clickhouse/clickhouse_bundle_test.go +++ b/internal/dataframe/publication/clickhouse/clickhouse_bundle_test.go @@ -401,73 +401,6 @@ func TestClickHouseBundleLeaseRenewalStopsWithTransactionCleanup(t *testing.T) { } } -func TestPlanReadyCleanupRetainsActiveAndPriorRelease(t *testing.T) { - catalog := newBundleCatalogFixture() - client := newBundleClickHouseFixture() - store, err := NewBundleStore(client, catalog) - if err != nil { - t.Fatal(err) - } - now := time.Now().UTC() - for i, generation := range []string{"g1", "g2", "g3"} { - readyAt := now.Add(-time.Duration(3-i) * time.Hour) - execution := publication.BundleExecution{ - ID: "execution-" + generation, - BundleIdentity: publication.BundleIdentity{Project: "project-a", DatasetGeneration: generation, Name: "Observation"}, - State: publication.BundleReady, ReadyAt: &readyAt, CreatedAt: readyAt, UpdatedAt: readyAt, - Outputs: []publication.BundleOutputRecord{{Name: "Observation", PhysicalTable: "loom_bundle_" + generation + "_Observation", State: publication.BundleReady}}, - } - catalog.executions[execution.ID] = execution - client.tables[execution.Outputs[0].PhysicalTable] = nil - } - // Every generation has its own dataframe pointer. Only g3 is the active - // project generation; g1/g2 pointers represent rollback metadata. - for _, id := range []string{"execution-g1", "execution-g2", "execution-g3"} { - execution := catalog.executions[id] - catalog.pointers[execution.PointerName()] = publication.BundlePointer{Name: execution.PointerName(), ExecutionID: execution.ID} - } - - plan, err := store.PlanReadyCleanupForActiveGenerations(context.Background(), map[string]string{"project-a": "g3"}) - if err != nil { - t.Fatal(err) - } - if len(plan) != 1 || plan[0].ExecutionID != "execution-g1" { - t.Fatalf("cleanup plan = %#v, want only execution-g1", plan) - } - if plan[0].PhysicalTable != "loom_bundle_g1_Observation" { - t.Fatalf("planned table = %q", plan[0].PhysicalTable) - } - if len(client.tables) != 3 { - t.Fatalf("planner changed physical tables: %#v", client.tables) - } -} - -func TestPlanReadyCleanupNeverPlansReferencedRollbackOrForeignTable(t *testing.T) { - catalog := newBundleCatalogFixture() - store, err := NewBundleStore(newBundleClickHouseFixture(), catalog) - if err != nil { - t.Fatal(err) - } - readyAt := time.Now().UTC().Add(-time.Hour) - execution := publication.BundleExecution{ - ID: "rollback", BundleIdentity: publication.BundleIdentity{Project: "project-a", DatasetGeneration: "rollback", Name: "Observation"}, - State: publication.BundleReady, ReadyAt: &readyAt, CreatedAt: readyAt, UpdatedAt: readyAt, - Outputs: []publication.BundleOutputRecord{ - {Name: "Observation", PhysicalTable: "loom_bundle_rollback_Observation", State: publication.BundleReady}, - {Name: "bad", PhysicalTable: "other_table", State: publication.BundleReady}, - }, - } - catalog.executions[execution.ID] = execution - catalog.pointers[execution.PointerName()] = publication.BundlePointer{Name: execution.PointerName(), ExecutionID: execution.ID} - plan, err := store.PlanReadyCleanup(context.Background()) - if err != nil { - t.Fatal(err) - } - if len(plan) != 0 { - t.Fatalf("cleanup plan = %#v, referenced/foreign tables must be protected", plan) - } -} - func TestClickHouseBundleCandidateIsInvisibleUntilReadyPointerCAS(t *testing.T) { catalog := newBundleCatalogFixture() client := newBundleClickHouseFixture() diff --git a/internal/dataframe/publication/clickhouse/target.go b/internal/dataframe/publication/clickhouse/target.go index db060859..3cdea381 100644 --- a/internal/dataframe/publication/clickhouse/target.go +++ b/internal/dataframe/publication/clickhouse/target.go @@ -84,6 +84,31 @@ type transaction struct { closed bool } +func (t *transaction) SetOutputMetadata(name string, columns []publication.LogicalColumn) error { + metadata, ok := t.tx.(interface { + SetOutputMetadata(string, []publication.LogicalColumn) error + }) + if !ok { + return nil + } + return metadata.SetOutputMetadata(name, columns) +} + +func (t *transaction) Idempotent() bool { + status, ok := t.tx.(interface{ Idempotent() bool }) + return ok && status.Idempotent() +} + +func (t *transaction) ExistingPublishedOutputs() []publication.PublishedOutput { + status, ok := t.tx.(interface { + ExistingPublishedOutputs() []publication.PublishedOutput + }) + if !ok { + return nil + } + return status.ExistingPublishedOutputs() +} + func (t *transaction) WriteBatch(ctx context.Context, output string, rows []map[string]any) error { if t.closed { return fmt.Errorf("ClickHouse publication transaction is closed") @@ -95,6 +120,31 @@ func (t *transaction) WriteBatch(ctx context.Context, output string, rows []map[ return t.tx.InsertRows(ctx, output, columns, rows) } +func (t *transaction) FinalizeSchema(ctx context.Context, schemas []publication.OutputSchema) error { + if t.closed { + return fmt.Errorf("ClickHouse publication transaction is closed") + } + if finalizer, ok := t.tx.(interface { + FinalizeSchema(context.Context, []publication.OutputSchema) error + }); ok { + return finalizer.FinalizeSchema(ctx, schemas) + } + for _, schema := range schemas { + columns, ok := t.columns[schema.Name] + if !ok || len(columns) != len(schema.Columns) { + return fmt.Errorf("ClickHouse transaction cannot finalize output %q schema", schema.Name) + } + } + return nil +} + +func (t *transaction) SetFinalSchemaDigest(digest string) error { + if setter, ok := t.tx.(interface{ SetFinalSchemaDigest(string) error }); ok { + return setter.SetFinalSchemaDigest(digest) + } + return nil +} + func (t *transaction) Commit(ctx context.Context) ([]publication.PublishedOutput, error) { if t.closed { return nil, fmt.Errorf("ClickHouse publication transaction is closed") diff --git a/internal/dataframe/publication/runner.go b/internal/dataframe/publication/runner.go index bde2355e..783523ee 100644 --- a/internal/dataframe/publication/runner.go +++ b/internal/dataframe/publication/runner.go @@ -35,6 +35,12 @@ func Publish(ctx context.Context, target Target, identity PublicationIdentity, o if err != nil { return Result{}, err } + if noop, ok := tx.(interface { + Idempotent() bool + ExistingPublishedOutputs() []PublishedOutput + }); ok && noop.Idempotent() { + return Result{Outputs: noop.ExistingPublishedOutputs()}, nil + } fail := func(cause error) (Result, error) { cleanupCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 10*time.Second) defer cancel() @@ -49,10 +55,12 @@ func Publish(ctx context.Context, target Target, identity PublicationIdentity, o return Result{}, errors.Join(cause, abortErr) } stats := make(map[string]PublishedOutput, len(normalizedOutputs)) + populated := make(map[string]map[string]bool, len(normalizedOutputs)) for _, output := range normalizedOutputs { stat := PublishedOutput{Name: output.Name} batch := make([]map[string]any, 0, limits.BatchRows) batchBytes := 0 + populated[output.Name] = make(map[string]bool) flush := func() error { if len(batch) == 0 { return nil @@ -71,6 +79,15 @@ func Publish(ctx context.Context, target Target, identity PublicationIdentity, o if err := validateRow(output.Columns, row); err != nil { return dataframeerrors.Wrap(err, dataframeerrors.CodeInvalidData, "") } + for _, column := range output.Columns { + if column.Provenance != ColumnDiscovered || column.LoomOwned || column.IsIdentity { + continue + } + value, ok := row[column.Name] + if ok && populatedValue(column, value) { + populated[output.Name][column.Name] = true + } + } encoded, err := json.Marshal(row) if err != nil { return dataframeerrors.Wrap(err, dataframeerrors.CodeOutputEncodingFailed, "") @@ -95,6 +112,36 @@ func Publish(ctx context.Context, target Target, identity PublicationIdentity, o } stats[output.Name] = stat } + retained := make([]OutputSchema, 0, len(normalizedOutputs)) + for _, output := range normalizedOutputs { + schema := OutputSchema{Name: output.Name} + for _, column := range output.Columns { + if column.Provenance == ColumnDiscovered && !column.LoomOwned && !column.IsIdentity && !populated[output.Name][column.Name] { + continue + } + schema.Columns = append(schema.Columns, column) + } + retained = append(retained, schema) + } + finalDigest := FinalSchemaDigest(identity, retained) + if finalizer, ok := tx.(interface { + FinalizeSchema(context.Context, []OutputSchema) error + }); ok { + if err := finalizer.FinalizeSchema(ctx, retained); err != nil { + return fail(fmt.Errorf("publication schema finalization: %w", err)) + } + } else { + for index := range retained { + if len(retained[index].Columns) != len(normalizedOutputs[index].Columns) { + return fail(fmt.Errorf("publication target cannot finalize pruned schema for output %q", retained[index].Name)) + } + } + } + if setter, ok := tx.(interface{ SetFinalSchemaDigest(string) error }); ok { + if err := setter.SetFinalSchemaDigest(finalDigest); err != nil { + return fail(fmt.Errorf("publication schema digest: %w", err)) + } + } published, err := tx.Commit(ctx) if err != nil { return fail(fmt.Errorf("publication commit: %w", err)) @@ -129,8 +176,8 @@ func injectPublicationMetadata(identity PublicationIdentity, outputs []OutputStr } copyOutput := output copyOutput.Columns = append([]LogicalColumn{ - {Name: "auth_resource_path", Kind: "string", Nullable: true}, - {Name: "project_id", Kind: "string"}, + {Name: "auth_resource_path", Kind: "string", Nullable: true, Provenance: ColumnExplicit, LoomOwned: true}, + {Name: "project_id", Kind: "string", Provenance: ColumnExplicit, LoomOwned: true}, }, columns...) originalStream := output.Stream copyOutput.Stream = func(ctx context.Context, visit func(map[string]any) error) error { @@ -204,6 +251,9 @@ func validateRow(columns []LogicalColumn, row map[string]any) error { known[column.Name] = column value, ok := row[column.Name] if !ok || value == nil { + if column.Provenance == ColumnDiscovered { + continue + } if !column.Nullable { return fmt.Errorf("required column %q is missing", column.Name) } @@ -221,6 +271,19 @@ func validateRow(columns []LogicalColumn, row map[string]any) error { return nil } +func populatedValue(column LogicalColumn, value any) bool { + if value == nil { + return false + } + if column.Repeated { + v := reflect.ValueOf(value) + if v.Kind() == reflect.Array || v.Kind() == reflect.Slice { + return v.Len() > 0 + } + } + return true +} + func validateValue(column LogicalColumn, value any) error { if column.Repeated { v := reflect.ValueOf(value) diff --git a/internal/dataframe/publication/runner_test.go b/internal/dataframe/publication/runner_test.go index d0e9256e..0fd92cbb 100644 --- a/internal/dataframe/publication/runner_test.go +++ b/internal/dataframe/publication/runner_test.go @@ -3,6 +3,7 @@ package publication import ( "context" "errors" + "fmt" "testing" ) @@ -27,6 +28,66 @@ type fakeTarget struct { schemas []OutputSchema } +type finalizingTx struct { + fakeTx + finalized []OutputSchema + digest string +} + +func (t *finalizingTx) FinalizeSchema(_ context.Context, schemas []OutputSchema) error { + t.finalized = append([]OutputSchema(nil), schemas...) + return nil +} + +func (t *finalizingTx) SetFinalSchemaDigest(digest string) error { + t.digest = digest + return nil +} + +type finalizingTarget struct{ tx *finalizingTx } + +func (t *finalizingTarget) Begin(_ context.Context, _ PublicationIdentity, _ []OutputSchema) (Transaction, error) { + t.tx = &finalizingTx{} + return t.tx, nil +} + +func TestPublishPrunesOnlyUnpopulatedDiscoveredColumns(t *testing.T) { + target := &finalizingTarget{} + columns := []LogicalColumn{ + {Name: "id", Kind: "string", Provenance: ColumnExplicit}, + {Name: "missing", Kind: "string", Nullable: true, Provenance: ColumnDiscovered}, + {Name: "nil_value", Kind: "string", Nullable: true, Provenance: ColumnDiscovered}, + {Name: "empty_array", Kind: "string", Repeated: true, Nullable: true, Provenance: ColumnDiscovered}, + {Name: "false_value", Kind: "boolean", Nullable: true, Provenance: ColumnDiscovered}, + {Name: "zero_value", Kind: "integer", Nullable: true, Provenance: ColumnDiscovered}, + {Name: "empty_string", Kind: "string", Nullable: true, Provenance: ColumnDiscovered}, + {Name: "nonempty_array", Kind: "string", Repeated: true, Nullable: true, Provenance: ColumnDiscovered}, + } + _, err := Publish(context.Background(), target, PublicationIdentity{Name: "r", Project: "p"}, []OutputStream{{ + Name: "rows", Columns: columns, + Stream: func(_ context.Context, visit func(map[string]any) error) error { + return visit(map[string]any{"id": "1", "nil_value": nil, "empty_array": []any{}, "false_value": false, "zero_value": 0, "empty_string": "", "nonempty_array": []any{"x"}}) + }, + }}, Limits{}) + if err != nil { + t.Fatal(err) + } + if len(target.tx.finalized) != 1 { + t.Fatalf("expected one finalized output, got %#v", target.tx.finalized) + } + got := make([]string, 0, len(target.tx.finalized[0].Columns)) + for _, column := range target.tx.finalized[0].Columns { + got = append(got, column.Name) + } + want := []string{"auth_resource_path", "project_id", "id", "false_value", "zero_value", "empty_string", "nonempty_array"} + if fmt.Sprint(got) != fmt.Sprint(want) { + t.Fatalf("retained columns = %v, want %v", got, want) + } + if target.tx.digest == "" { + t.Fatal("final schema digest was not set") + } +} + func (t *fakeTarget) Begin(_ context.Context, _ PublicationIdentity, schemas []OutputSchema) (Transaction, error) { t.schemas = schemas t.tx = &fakeTx{} diff --git a/internal/dataframe/publication/types.go b/internal/dataframe/publication/types.go index 5d03eae2..15e4c835 100644 --- a/internal/dataframe/publication/types.go +++ b/internal/dataframe/publication/types.go @@ -4,7 +4,19 @@ // lifecycle around that target. package publication -import "context" +import ( + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" +) + +type ColumnProvenance string + +const ( + ColumnExplicit ColumnProvenance = "EXPLICIT" + ColumnDiscovered ColumnProvenance = "DISCOVERED" +) // LogicalColumn is the backend-independent schema emitted by the compiler. // Kind is one of string, code, uuid, date, date-time, integer, decimal, @@ -19,6 +31,8 @@ type LogicalColumn struct { Repeated bool Nullable bool IsIdentity bool + Provenance ColumnProvenance + LoomOwned bool } type OutputSchema struct { @@ -65,6 +79,50 @@ type Transaction interface { Rollback(context.Context) error } +// SchemaFinalizer is implemented by publication targets that can remove +// unpopulated discovered columns from their private staging tables. The +// runner uses the optional interface so older non-ClickHouse test targets +// remain source-compatible while production publication requires it when a +// column must be dropped. +type SchemaFinalizer interface { + FinalizeSchema(context.Context, []OutputSchema) error +} + +// FinalSchemaDigest computes the versioned digest for the schema actually +// staged. Physical names and discovery provenance are deliberately excluded. +func FinalSchemaDigest(identity PublicationIdentity, schemas []OutputSchema) string { + type contract struct { + Name string `json:"name"` + Kind string `json:"kind"` + SemanticPath string `json:"semanticPath,omitempty"` + Repeated bool `json:"repeated,omitempty"` + Nullable bool `json:"nullable,omitempty"` + Identity bool `json:"identity,omitempty"` + } + type output struct { + Name string `json:"name"` + Columns []contract `json:"columns"` + } + ordered := make([]output, 0, len(schemas)) + for _, schema := range schemas { + item := output{Name: schema.Name, Columns: make([]contract, 0, len(schema.Columns))} + for _, column := range schema.Columns { + item.Columns = append(item.Columns, contract{Name: column.Name, Kind: column.Kind, SemanticPath: column.SemanticPath, Repeated: column.Repeated, Nullable: column.Nullable, Identity: column.IsIdentity}) + } + ordered = append(ordered, item) + } + payload := struct { + Version int `json:"version"` + RecipeDigest string `json:"recipeDigest"` + ScopeDigest string `json:"scopeDigest"` + DatasetGeneration string `json:"datasetGeneration"` + Outputs []output `json:"outputs"` + }{2, identity.RecipeDigest, identity.ScopeDigest, identity.DatasetGeneration, ordered} + b, _ := json.Marshal(payload) + sum := sha256.Sum256(b) + return hex.EncodeToString(sum[:]) +} + type Limits struct { BatchRows int BatchBytes int diff --git a/internal/dataframe/published/federation.go b/internal/dataframe/published/federation.go index 56d0d3ad..b01e159b 100644 --- a/internal/dataframe/published/federation.go +++ b/internal/dataframe/published/federation.go @@ -362,11 +362,19 @@ func (r *Reader) CurrentFederatedSources(ctx context.Context, projects []string, continue } } + // Output absence is a normal selector miss, not a catalog failure. In + // particular, a newer recipe version may replace Patient with + // ResearchSubject while both executions remain in publication history. + // Do not ask version-aware catalogs to resolve metadata for an output the + // execution never published. + if !hasOutputResourceType(execution, selector.Output) { + continue + } executionSelector, selectorErr := r.selectorForExecution(ctx, execution, selector.Output) if selectorErr != nil { return nil, selectorErr } - if executionSelector != selector || !hasOutputResourceType(execution, selector.Output) { + if executionSelector != selector { continue } if current, ok := selected[execution.Project]; ok && current.ID != execution.ID { diff --git a/internal/dataframe/published/federation_test.go b/internal/dataframe/published/federation_test.go index aab5b90d..0a6e81e7 100644 --- a/internal/dataframe/published/federation_test.go +++ b/internal/dataframe/published/federation_test.go @@ -123,6 +123,35 @@ func TestRecipeVersionsRemainIndependentlyQueryable(t *testing.T) { } } +func TestVersionedExecutionWithoutRequestedOutputIsSkipped(t *testing.T) { + now := time.Now().UTC() + execution := bundlepublication.BundleExecution{ + ID: "research-subject", BundleIdentity: bundlepublication.BundleIdentity{ + Name: "calypr-meta-default", TranslationVersion: "v2", Project: "p", DatasetGeneration: "g", + }, + State: bundlepublication.BundlePublished, UpdatedAt: now, + Outputs: []bundlepublication.BundleOutputRecord{{Name: "ResearchSubject", PhysicalTable: "research_subject"}}, + } + catalog := &missingOutputSelectorCatalog{federationCatalog: &federationCatalog{ + executions: []bundlepublication.BundleExecution{execution}, + pointers: map[string]bundlepublication.BundlePointer{execution.PointerName(): {ExecutionID: execution.ID}}, + }} + reader := Reader{Catalog: catalog} + + sources, err := reader.CurrentFederatedSources(context.Background(), []string{"p"}, DataframeSelector{ + Recipe: "calypr-meta-default", TranslationVersion: "v2", Output: "Patient", + }) + if err != nil { + t.Fatalf("CurrentFederatedSources() error = %v", err) + } + if len(sources) != 0 { + t.Fatalf("sources = %#v, want no Patient publication", sources) + } + if catalog.selectorCalls != 0 { + t.Fatalf("selector resolver called %d times for absent output", catalog.selectorCalls) + } +} + func TestFederatedUnionSynthesizesProjectIDForLegacySource(t *testing.T) { dataset := FederatedDataset{ Columns: []Column{{Name: "id", ClickHouse: "String"}, {Name: projectIDColumn, ClickHouse: "String"}}, @@ -158,6 +187,16 @@ type versionedFederationCatalog struct { selectors map[string]DataframeSelector } +type missingOutputSelectorCatalog struct { + *federationCatalog + selectorCalls int +} + +func (c *missingOutputSelectorCatalog) DataframeSelectorForExecution(context.Context, string, string) (DataframeSelector, error) { + c.selectorCalls++ + return DataframeSelector{}, bundlepublication.ErrBundleNotFound +} + type releaseExecutionFixture map[string]string func (f releaseExecutionFixture) ActiveReleaseExecutionIDs(context.Context, []string, DataframeSelector) (map[string]string, error) { diff --git a/internal/dataframe/recipe/document_types.go b/internal/dataframe/recipe/document_types.go index b3f725e5..1a21619b 100644 --- a/internal/dataframe/recipe/document_types.go +++ b/internal/dataframe/recipe/document_types.go @@ -50,11 +50,12 @@ type Output struct { // Field projects one named semantic value into an output row. type Field struct { - Name string `json:"name"` - FieldRef string `json:"fieldRef,omitempty"` - Expr Expression `json:"expr"` - Fallbacks []Expression `json:"fallbacks,omitempty"` - ValueMode ValueMode `json:"valueMode,omitempty"` + Name string `json:"name"` + FieldRef string `json:"fieldRef,omitempty"` + Expr Expression `json:"expr"` + Fallbacks []Expression `json:"fallbacks,omitempty"` + ValueMode ValueMode `json:"valueMode,omitempty"` + Discovered bool `json:"-"` } // ValueMode controls how a checked selector contributes values to one row. @@ -178,6 +179,7 @@ type Pivot struct { ItemResourceType string `json:"itemResourceType,omitempty"` Columns []string `json:"columns"` Discovery *PivotDiscovery `json:"discovery,omitempty"` + Discovered bool `json:"-"` } // MarshalJSON permits catalog-backed pivots to omit selectors in their stored @@ -337,6 +339,7 @@ type DynamicColumn struct { // keyed-map lookup key. Extension columns use this for parent__child names // while matching the leaf Extension.url segment inside its scoped source. ColumnSourceKeys map[string]string `json:"-"` + Discovered bool `json:"-"` } // ExtensionColumn is a bounded, URL-keyed projection of FHIR Extension @@ -348,6 +351,7 @@ type ExtensionColumn struct { ColumnPrefix *string `json:"columnPrefix,omitempty"` MaxColumns int `json:"maxColumns"` Columns []ExtensionColumnMapping `json:"columns,omitempty"` + Discovered bool `json:"-"` } // ExtensionColumnMapping is immutable schema-discovery output. Name is the diff --git a/internal/dataframe/recipe/exec/persistent.go b/internal/dataframe/recipe/exec/persistent.go index bfef7005..10adc45e 100644 --- a/internal/dataframe/recipe/exec/persistent.go +++ b/internal/dataframe/recipe/exec/persistent.go @@ -77,12 +77,6 @@ func (r PersistentRegistry) RegisterVersion(ctx context.Context, bundle recipe.B return entry, nil } -// RegisterDefault is retained as an additive compatibility alias. It no -// longer replaces name-only rows: the bundle's translationVersion is exact. -func (r PersistentRegistry) RegisterDefault(ctx context.Context, bundle recipe.Bundle) (Entry, error) { - return r.RegisterVersion(ctx, bundle) -} - func (r PersistentRegistry) LoadVersion(ctx context.Context, name, translationVersion string) (Entry, error) { store, ok := r.Store.(VersionedStore) if !ok { diff --git a/internal/dataframe/recipe/exec/persistent_test.go b/internal/dataframe/recipe/exec/persistent_test.go index c59efa3c..92e80468 100644 --- a/internal/dataframe/recipe/exec/persistent_test.go +++ b/internal/dataframe/recipe/exec/persistent_test.go @@ -55,12 +55,12 @@ func TestPersistentRegistryRetainsVersions(t *testing.T) { store := &memoryRecipeStore{} registry := PersistentRegistry{Store: store} bundle := recipe.Bundle{RecipeSchemaVersion: 1, Name: "default", TranslationVersion: "v", Outputs: []recipe.Output{{Name: "Patient", RootResourceType: "Patient", RowGrain: "patient"}}} - first, err := registry.RegisterDefault(context.Background(), bundle) + first, err := registry.RegisterVersion(context.Background(), bundle) if err != nil { t.Fatal(err) } bundle.TranslationVersion = "changed" - second, err := registry.RegisterDefault(context.Background(), bundle) + second, err := registry.RegisterVersion(context.Background(), bundle) if err != nil { t.Fatal(err) } diff --git a/internal/dataframe/recipe/schema/discovery.go b/internal/dataframe/recipe/schema/discovery.go index 4be60b03..648a9ef5 100644 --- a/internal/dataframe/recipe/schema/discovery.go +++ b/internal/dataframe/recipe/schema/discovery.go @@ -45,7 +45,7 @@ func resolveProjectionSets(ctx context.Context, scope Scope, discovery Discovery } else { selectPath = "root." + selectPath } - fields = append(fields, recipe.Field{Name: name, FieldRef: candidate.Path, ValueMode: set.ValueMode, Expr: recipe.Expression{Select: selectPath}}) + fields = append(fields, recipe.Field{Name: name, FieldRef: candidate.Path, ValueMode: set.ValueMode, Expr: recipe.Expression{Select: selectPath}, Discovered: true}) } } return fields, nil @@ -162,6 +162,7 @@ func resolvePivots(ctx context.Context, scope Scope, discovery Discovery, resour } pivot.ValueExpr = recipe.Expression{Select: qualifyDiscoveredSelector(alias, valueSelect)} } + pivot.Discovered = true pivot.Discovery = nil resolved = append(resolved, *pivot) } @@ -189,6 +190,7 @@ func relativePivotPath(itemSource, selector string) string { func resolveDynamicColumns(ctx context.Context, scope Scope, discovery Discovery, resourceType, alias string, dynamics []recipe.DynamicColumn) error { for index := range dynamics { dynamic := &dynamics[index] + wasUnresolved := len(dynamic.Columns) == 0 if len(dynamic.Columns) > 0 { continue } @@ -229,6 +231,9 @@ func resolveDynamicColumns(ctx context.Context, scope Scope, discovery Discovery return fmt.Errorf("dynamic column %q discovery found %d columns, exceeding maxColumns %d", dynamic.Name, len(values), dynamic.MaxColumns) } dynamic.Columns = sortedValues(values) + if wasUnresolved { + dynamic.Discovered = true + } // A keyed family is optional: a valid FHIR dataset may have no values // for an extension/identifier family at all. Keep the declaration with // an empty frozen column set so resolution remains schema-stable and the diff --git a/internal/dataframe/recipe/schema/extension_columns.go b/internal/dataframe/recipe/schema/extension_columns.go index e6986243..c39181bb 100644 --- a/internal/dataframe/recipe/schema/extension_columns.go +++ b/internal/dataframe/recipe/schema/extension_columns.go @@ -17,6 +17,7 @@ import ( func resolveExtensionColumns(ctx context.Context, scope Scope, discovery Discovery, resourceType, alias string, items []recipe.ExtensionColumn) error { for index := range items { item := &items[index] + item.Discovered = true selector := strings.TrimSpace(item.Source.Select) if selector == "" { return fmt.Errorf("extension column %q source must be a selector", item.Name) diff --git a/internal/dataframe/semantic/recipe_plan_output.go b/internal/dataframe/semantic/recipe_plan_output.go index af4cd5ff..176372e2 100644 --- a/internal/dataframe/semantic/recipe_plan_output.go +++ b/internal/dataframe/semantic/recipe_plan_output.go @@ -260,6 +260,7 @@ func buildRecipeExtensionMaps(items []recipe.ExtensionColumn, scope scopeFrame, Name: item.Name + "__" + mapping.Name, ColumnPrefix: item.ColumnPrefix, Source: sourceExpr, Key: &key, Value: &value, Columns: []string{mapping.Name}, MaxColumns: item.MaxColumns, ColumnTypes: map[string]string{mapping.Name: mapping.ValueType}, ColumnSourceKeys: map[string]string{mapping.Name: sourceKey}, + Discovered: true, } maps, err := buildRecipeDynamicMaps([]recipe.DynamicColumn{dynamic}, scope, path, scopeAlias, resourceType) if err != nil { @@ -286,7 +287,7 @@ func buildRecipeDynamicMaps(items []recipe.DynamicColumn, scope scopeFrame, path // to mark an optional family as resolved with zero discovered keys. columns = append([]string{}, dynamic.Columns...) } - item := SemanticDynamicMap{Name: dynamic.Name, ScopeAlias: scopeAlias, ResourceType: resourceType, Columns: columns, MaxColumns: dynamic.MaxColumns, ColumnTypes: dynamic.ColumnTypes, ColumnSourceKeys: dynamic.ColumnSourceKeys} + item := SemanticDynamicMap{Name: dynamic.Name, ScopeAlias: scopeAlias, ResourceType: resourceType, Columns: columns, MaxColumns: dynamic.MaxColumns, ColumnTypes: dynamic.ColumnTypes, ColumnSourceKeys: dynamic.ColumnSourceKeys, Discovered: dynamic.Discovered} if dynamic.ColumnPrefix != nil { prefix := *dynamic.ColumnPrefix item.ColumnPrefix = &prefix diff --git a/internal/dataframe/semantic/recipe_plan_types.go b/internal/dataframe/semantic/recipe_plan_types.go index 254283fa..8fdbc72a 100644 --- a/internal/dataframe/semantic/recipe_plan_types.go +++ b/internal/dataframe/semantic/recipe_plan_types.go @@ -57,10 +57,11 @@ type SemanticExpression struct { } type SemanticProjection struct { - Name string - FieldRef string - ValueMode string - Expr SemanticExpression + Name string + FieldRef string + ValueMode string + Expr SemanticExpression + Discovered bool } // UnnestJoinMode makes null/empty collection behavior explicit at the @@ -134,6 +135,7 @@ type SemanticDynamicMap struct { // siblings, not schema drift; frozen matching keys still receive type checks. AllowUnknownKeys bool MaxColumns int + Discovered bool } // RecipePlanExplanation is stable diagnostic output and contains only logical diff --git a/internal/dataframe/semantic/recipe_projection.go b/internal/dataframe/semantic/recipe_projection.go index 5b80da02..2ed5883d 100644 --- a/internal/dataframe/semantic/recipe_projection.go +++ b/internal/dataframe/semantic/recipe_projection.go @@ -72,7 +72,7 @@ func normalizeRecipeProjection(field recipe.Field, scope scopeFrame, path string fieldSemantic := SemanticField{ Name: field.Name, FieldRef: field.FieldRef, Selector: selector, Fallbacks: fallbackSelectors, ValueMode: string(field.ValueMode), - Expr: &primary.Expression, ExprType: primary.Type, SourcePath: primary.SourcePath, + Expr: &primary.Expression, ExprType: primary.Type, SourcePath: primary.SourcePath, Discovered: field.Discovered, } if err := validateRecipeProjectionTypes(primary.Type, fallbacks); err != nil { return normalizedRecipeProjection{}, fmt.Errorf("%s: %w", path, err) @@ -101,7 +101,7 @@ func normalizeRecipeProjection(field recipe.Field, scope scopeFrame, path string } fieldSemantic.ExprType = projected.Type return normalizedRecipeProjection{projection: SemanticProjection{ - Name: field.Name, FieldRef: field.FieldRef, ValueMode: string(field.ValueMode), Expr: projected, + Name: field.Name, FieldRef: field.FieldRef, ValueMode: string(field.ValueMode), Expr: projected, Discovered: field.Discovered, }, field: fieldSemantic}, nil } @@ -113,7 +113,7 @@ func normalizeRecipeProjection(field recipe.Field, scope scopeFrame, path string return normalizedRecipeProjection{}, fmt.Errorf("%s: %w", path, err) } return normalizedRecipeProjection{projection: SemanticProjection{Name: field.Name, FieldRef: field.FieldRef, ValueMode: string(field.ValueMode), Expr: projected}, field: SemanticField{ - Name: field.Name, FieldRef: field.FieldRef, ValueMode: string(field.ValueMode), Expr: &projected.Expression, ExprType: projected.Type, SourcePath: projected.SourcePath, + Name: field.Name, FieldRef: field.FieldRef, ValueMode: string(field.ValueMode), Expr: &projected.Expression, ExprType: projected.Type, SourcePath: projected.SourcePath, Discovered: field.Discovered, }}, nil } diff --git a/internal/dataframe/semantic/recipe_rich_shaping.go b/internal/dataframe/semantic/recipe_rich_shaping.go index 7f69b453..2df2577f 100644 --- a/internal/dataframe/semantic/recipe_rich_shaping.go +++ b/internal/dataframe/semantic/recipe_rich_shaping.go @@ -163,6 +163,7 @@ func lowerRecipePivots(resourceType, alias string, scope scopeFrame, pivots []re ItemResourceType: itemResourceType, Columns: columns, Family: pivotSpec.Family, + Discovered: input.Discovered, }) } return out, nil diff --git a/internal/dataframe/semantic/semantic_plan.go b/internal/dataframe/semantic/semantic_plan.go index 659f36cb..dba76395 100644 --- a/internal/dataframe/semantic/semantic_plan.go +++ b/internal/dataframe/semantic/semantic_plan.go @@ -44,6 +44,7 @@ type SemanticField struct { Expr *expression.Expression ExprType expression.Type SourcePath string + Discovered bool } type SemanticPivot struct { @@ -58,6 +59,7 @@ type SemanticPivot struct { ItemResourceType string Columns []string Family string + Discovered bool } type SemanticAggregate struct { diff --git a/internal/dataset/active_resolver.go b/internal/dataset/active_resolver.go index 9ed15901..14c74b86 100644 --- a/internal/dataset/active_resolver.go +++ b/internal/dataset/active_resolver.go @@ -30,7 +30,7 @@ func ResolveActive(ctx context.Context, resolver ActiveResolver, project string) if manifest.Dataset.Project != project { return Manifest{}, fmt.Errorf("%w: resolver returned project %q for requested project %q", ErrInvalidActiveGeneration, manifest.Dataset.Project, project) } - if !manifest.IsReady() { + if !manifest.IsStaged() { return Manifest{}, fmt.Errorf("%w: %s is %s", ErrGenerationNotReady, manifest.Dataset.Generation, manifest.State) } return manifest, nil diff --git a/internal/dataset/arango/document_codec.go b/internal/dataset/arango/document_codec.go index 31f5b163..15b7f20b 100644 --- a/internal/dataset/arango/document_codec.go +++ b/internal/dataset/arango/document_codec.go @@ -52,6 +52,10 @@ func lifecycleBindVars(project string) map[string]any { } } +func lifecycleCollectionBindVars() map[string]any { + return map[string]any{"@lifecycle_collection": LifecycleCollection} +} + func validateProject(project string) error { _, err := publication.NewRef(project, "generation-project-validation") return err diff --git a/internal/dataset/arango/manifest_lifecycle.go b/internal/dataset/arango/manifest_lifecycle.go index d14a8610..b828add5 100644 --- a/internal/dataset/arango/manifest_lifecycle.go +++ b/internal/dataset/arango/manifest_lifecycle.go @@ -178,14 +178,14 @@ func (s *Store) ResolveActiveManifest(ctx context.Context, project string) (publ if len(rows) == 0 { return publication.Manifest{}, fmt.Errorf("%w: %s", publication.ErrNoActiveGeneration, project) } - if rows[0].Dataset.Project != project || !rows[0].IsReady() { + if rows[0].Dataset.Project != project || !rows[0].IsStaged() { return publication.Manifest{}, fmt.Errorf("%w: active pointer and staged manifest are inconsistent", ErrUnexpectedStoreResult) } return rows[0], nil } func (s *Store) Activate(ctx context.Context, candidate publication.Manifest) error { - if !candidate.IsReady() { + if !candidate.IsStaged() { if err := candidate.Validate(); err != nil { return fmt.Errorf("activate generation: %w", err) } @@ -194,6 +194,18 @@ func (s *Store) Activate(ctx context.Context, candidate publication.Manifest) er if err := s.validate(); err != nil { return err } + // Activation is intentionally idempotent. Gecko may retry a publish after + // the active-generation pointer was already switched; doing another + // compare-and-swap update in that case creates an unnecessary revision race + // and can surface PUBLICATION_CONFLICT even though the requested generation + // is already active. + if active, err := s.ResolveActiveManifest(ctx, candidate.Dataset.Project); err == nil { + if manifestIdentityEqual(active, candidate) { + return nil + } + } else if !errors.Is(err, publication.ErrNoActiveGeneration) { + return fmt.Errorf("inspect active generation before activation: %w", err) + } schemaIdentity, err := schemaIdentityBindValue(candidate.SchemaIdentity) if err != nil { return err diff --git a/internal/dataset/arango/snapshot_release_store.go b/internal/dataset/arango/snapshot_release_store.go index 8a6c08a2..1264eccd 100644 --- a/internal/dataset/arango/snapshot_release_store.go +++ b/internal/dataset/arango/snapshot_release_store.go @@ -21,7 +21,7 @@ func (s *Store) CreateOrResumeSnapshot(ctx context.Context, candidate dataset.Sn document["_key"] = snapshotDocumentKey(candidate.Dataset) document["recordType"] = snapshotRecordType document["project"] = candidate.Dataset.Project - binds := lifecycleBindVars(candidate.Dataset.Project) + binds := lifecycleCollectionBindVars() binds["key"], binds["candidate"] = document["_key"], document rows, err := s.snapshotRows(ctx, createOrResumeSnapshotAQL, binds) if err != nil { @@ -37,7 +37,8 @@ func (s *Store) ReadSnapshot(ctx context.Context, ref dataset.Ref) (dataset.Snap if err := ref.Validate(); err != nil { return dataset.SnapshotGeneration{}, err } - binds := lifecycleBindVars(ref.Project) + binds := lifecycleCollectionBindVars() + binds["project"] = ref.Project binds["key"], binds["generation"] = snapshotDocumentKey(ref), ref.Generation rows, err := s.snapshotRows(ctx, readSnapshotAQL, binds) if err != nil { @@ -50,7 +51,8 @@ func (s *Store) ReadSnapshot(ctx context.Context, ref dataset.Ref) (dataset.Snap } func (s *Store) RecordSnapshotUpload(ctx context.Context, ref dataset.Ref, upload dataset.ResourceUpload) (dataset.SnapshotGeneration, error) { - binds := lifecycleBindVars(ref.Project) + binds := lifecycleCollectionBindVars() + binds["project"] = ref.Project binds["key"], binds["generation"], binds["upload"] = snapshotDocumentKey(ref), ref.Generation, upload binds["loading_state"] = string(dataset.StateLoading) rows, err := s.snapshotRows(ctx, recordSnapshotUploadAQL, binds) @@ -71,7 +73,8 @@ func (s *Store) RecordSnapshotUpload(ctx context.Context, ref dataset.Ref, uploa } func (s *Store) TransitionSnapshot(ctx context.Context, ref dataset.Ref, expected, next dataset.State, now time.Time) (dataset.SnapshotGeneration, error) { - binds := lifecycleBindVars(ref.Project) + binds := lifecycleCollectionBindVars() + binds["project"] = ref.Project binds["key"], binds["generation"] = snapshotDocumentKey(ref), ref.Generation binds["expected"], binds["next"], binds["updated_at"] = string(expected), string(next), now.UTC() rows, err := s.snapshotRows(ctx, transitionSnapshotAQL, binds) @@ -99,7 +102,7 @@ func (s *Store) SaveRelease(ctx context.Context, release dataset.ProjectRelease) } document["_key"] = releaseDocumentKey(release.ID) document["recordType"] = releaseRecordType - binds := lifecycleBindVars(release.Project) + binds := lifecycleCollectionBindVars() binds["key"], binds["candidate"] = document["_key"], document binds["active_release_key"] = activeReleaseDocumentKey(release.Project) binds["active_release_placeholder"] = activeReleasePlaceholderDocument(release.Project) @@ -122,7 +125,8 @@ func (s *Store) SaveRelease(ctx context.Context, release dataset.ProjectRelease) } func (s *Store) ReadRelease(ctx context.Context, project, releaseID string) (dataset.ProjectRelease, error) { - binds := lifecycleBindVars(project) + binds := lifecycleCollectionBindVars() + binds["project"] = project binds["key"], binds["release_id"] = releaseDocumentKey(releaseID), releaseID var release *dataset.ProjectRelease err := s.client.QueryRows(ctx, readReleaseAQL, metadataBatchSize, binds, func(row map[string]any) error { @@ -143,7 +147,7 @@ func (s *Store) ReadRelease(ctx context.Context, project, releaseID string) (dat } func (s *Store) ReadActiveRelease(ctx context.Context, project string) (dataset.ActiveRelease, error) { - binds := lifecycleBindVars(project) + binds := lifecycleCollectionBindVars() binds["key"] = activeReleaseDocumentKey(project) var active *dataset.ActiveRelease err := s.client.QueryRows(ctx, readActiveReleaseAQL, metadataBatchSize, binds, func(row map[string]any) error { @@ -170,7 +174,8 @@ func (s *Store) CompareAndSwapActivateRelease(ctx context.Context, release datas } releaseDocument["_key"] = releaseDocumentKey(release.ID) releaseDocument["recordType"] = releaseRecordType - binds := lifecycleBindVars(release.Project) + binds := lifecycleCollectionBindVars() + binds["project"] = release.Project binds["release"] = releaseDocument binds["release_key"] = releaseDocument["_key"] binds["release_id"] = release.ID @@ -212,7 +217,6 @@ func (s *Store) ListRetentionGenerations(ctx context.Context) ([]dataset.Retenti "snapshot_record_type": snapshotRecordType, "active_record_type": activeRecordType, "active_release_record_type": activeReleaseRecordType, - "release_record_type": releaseRecordType, "in_flight_states": []string{"QUEUED", "RUNNING", "VALIDATING", "PENDING", "PREFLIGHT", "LOADING"}, } err := s.client.QueryRows(ctx, listRetentionGenerationsAQL, metadataBatchSize, binds, func(row map[string]any) error { diff --git a/internal/dataset/arango/store_test.go b/internal/dataset/arango/store_test.go index 3000a284..1dce7b85 100644 --- a/internal/dataset/arango/store_test.go +++ b/internal/dataset/arango/store_test.go @@ -62,12 +62,17 @@ func TestTransitionAndResolveManifest(t *testing.T) { func TestActivateOnlyRevisionChecksActivePointer(t *testing.T) { ready := fixtureManifest(t, "project-a", "generation-a", publication.StateReady) - fake := &fakeQueryClient{responses: [][]map[string]any{{{"dataset": jsonObject(t, ready.Dataset)}}}} + // The first query is the idempotency read. An empty result means there is + // no active manifest, so activation proceeds to the compare-and-swap query. + fake := &fakeQueryClient{responses: [][]map[string]any{{}, {{"dataset": jsonObject(t, ready.Dataset)}}}} store := mustStore(t, fake) if err := store.Activate(context.Background(), ready); err != nil { t.Fatal(err) } - call := fake.onlyCall(t) + if len(fake.calls) != 2 { + t.Fatalf("activation calls = %d, want 2", len(fake.calls)) + } + call := fake.calls[1] for _, required := range []string{"manifest.state == @ready_state", "manifest.schemaIdentity == @schema_identity", "UPDATE active WITH", "ignoreRevs: false", "manifestKey: candidate._key"} { if !strings.Contains(call.query, required) { t.Fatalf("activation query missing %q:\n%s", required, call.query) @@ -80,6 +85,22 @@ func TestActivateOnlyRevisionChecksActivePointer(t *testing.T) { } } +func TestActivateIsIdempotentWhenCandidateIsAlreadyActive(t *testing.T) { + ready := fixtureManifest(t, "project-a", "generation-a", publication.StateReady) + fake := &fakeQueryClient{responses: [][]map[string]any{{{ + "dataset": jsonObject(t, ready.Dataset), + "state": string(publication.StateReady), + "schemaIdentity": jsonObject(t, ready.SchemaIdentity), + }}}} + store := mustStore(t, fake) + if err := store.Activate(context.Background(), ready); err != nil { + t.Fatal(err) + } + if len(fake.calls) != 1 { + t.Fatalf("activation calls = %d, want only idempotency read", len(fake.calls)) + } +} + func TestActivateRejectsNonReadyMissingAndConflictingCandidates(t *testing.T) { loading := fixtureManifest(t, "project-a", "generation-a", publication.StateLoading) fake := &fakeQueryClient{} @@ -203,6 +224,33 @@ func TestReleaseActivationEmptyCASResultIsConflict(t *testing.T) { } } +func TestListRetentionGenerationsPassesOnlyDeclaredBindVariables(t *testing.T) { + fake := &fakeQueryClient{} + store := mustStore(t, fake) + if _, err := store.ListRetentionGenerations(context.Background()); err != nil { + t.Fatal(err) + } + assertOnlyDeclaredBindVariables(t, fake.onlyCall(t)) +} + +func TestReadActiveReleasePassesOnlyDeclaredBindVariables(t *testing.T) { + fake := &fakeQueryClient{} + store := mustStore(t, fake) + if _, err := store.ReadActiveRelease(context.Background(), "project-a"); !errors.Is(err, publication.ErrNoActiveRelease) { + t.Fatalf("ReadActiveRelease() error = %v, want no active release", err) + } + assertOnlyDeclaredBindVariables(t, fake.onlyCall(t)) +} + +func assertOnlyDeclaredBindVariables(t *testing.T, call queryCall) { + t.Helper() + for name := range call.bindVars { + if !strings.Contains(call.query, "@"+name) { + t.Errorf("bind variable %q is not declared in query", name) + } + } +} + func fixtureManifest(t *testing.T, project, id string, state publication.State) publication.Manifest { t.Helper() ref, err := publication.NewRef(project, id) diff --git a/internal/dataset/manifest.go b/internal/dataset/manifest.go index 769a1eaa..cf1b4755 100644 --- a/internal/dataset/manifest.go +++ b/internal/dataset/manifest.go @@ -57,6 +57,3 @@ func (m Manifest) Transition(next State) (Manifest, error) { func (m Manifest) IsStaged() bool { return m.Validate() == nil && (m.State == StateStaged || m.State == StateReady) } - -// IsReady remains as a compatibility alias for existing readers. -func (m Manifest) IsReady() bool { return m.IsStaged() } diff --git a/internal/server/recipe_publication.go b/internal/server/recipe_publication.go index 27b4969a..9076314b 100644 --- a/internal/server/recipe_publication.go +++ b/internal/server/recipe_publication.go @@ -40,13 +40,13 @@ func recipeOutputLogicalColumns(plan engine.Resolved, outputName string) []publi identityAdded := false for _, column := range output.OutputSchema { if column.Identity && column.Name == "__loom_row_id" { - columns = append(columns, publication.LogicalColumn{Name: column.Name, SemanticPath: "loom:row_id", Kind: "string", IsIdentity: true}) + columns = append(columns, publication.LogicalColumn{Name: column.Name, SemanticPath: "loom:row_id", Kind: "string", IsIdentity: true, LoomOwned: true, Provenance: publication.ColumnExplicit}) identityAdded = true break } } if !identityAdded { - columns = append(columns, publication.LogicalColumn{Name: "__loom_row_id", SemanticPath: "loom:row_id", Kind: "string", IsIdentity: true}) + columns = append(columns, publication.LogicalColumn{Name: "__loom_row_id", SemanticPath: "loom:row_id", Kind: "string", IsIdentity: true, LoomOwned: true, Provenance: publication.ColumnExplicit}) } for _, column := range output.OutputSchema { if column.Internal { @@ -63,7 +63,11 @@ func recipeOutputLogicalColumns(plan engine.Resolved, outputName string) []publi if semanticPath == "" { semanticPath = output.RootResourceType + "." + column.Name } - columns = append(columns, publication.LogicalColumn{Name: publication.FlatColumnName(output.RootResourceType, column.Name), SemanticPath: semanticPath, Kind: kind, Repeated: column.Cardinality == "many", Nullable: column.Nullable}) + provenance := publication.ColumnExplicit + if column.Discovered { + provenance = publication.ColumnDiscovered + } + columns = append(columns, publication.LogicalColumn{Name: publication.FlatColumnName(output.RootResourceType, column.Name), SemanticPath: semanticPath, Kind: kind, Repeated: column.Cardinality == "many", Nullable: column.Nullable, Provenance: provenance}) } return columns } @@ -190,7 +194,7 @@ func recipeMaterializer(recipeEngine *engine.Engine, bundleTarget publication.Ta Columns: append([]publication.PhysicalColumn(nil), output.Columns...), }) } - return graphresolver.RecipeExecution{ID: published.ID, Name: name, RecipeDigest: identity.RecipeDigest, ResolvedSchemaDigest: identity.SchemaDigest, SourceGeneration: identity.DatasetGeneration, State: string(published.State.Canonical()), Outputs: outputs}, nil + return graphresolver.RecipeExecution{ID: published.ID, Name: name, RecipeDigest: published.RecipeDigest, ResolvedSchemaDigest: published.SchemaDigest, SourceGeneration: published.DatasetGeneration, State: string(published.State.Canonical()), Outputs: outputs}, nil } } diff --git a/internal/server/server.go b/internal/server/server.go index a909ddbf..b31f5e4f 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -113,7 +113,7 @@ func run(ctx context.Context, serverConfig Config) error { if err != nil { return fmt.Errorf("parse dataframer recipe %q: %w", serverConfig.Server.Dataframer.Recipe, err) } - if _, err := (exec.PersistentRegistry{Store: recipeRegistry}).RegisterDefault(ctx, defaultBundle); err != nil { + if _, err := (exec.PersistentRegistry{Store: recipeRegistry}).RegisterVersion(ctx, defaultBundle); err != nil { degradation = recordDegradation(logger, degradation, "register default dataframe recipe", err) } if initialRecipe == "" && initialVersion == "" { diff --git a/internal/store/clickhouse/client.go b/internal/store/clickhouse/client.go index 1a929930..08568432 100644 --- a/internal/store/clickhouse/client.go +++ b/internal/store/clickhouse/client.go @@ -7,8 +7,10 @@ import ( "context" "encoding/json" "fmt" + "math" "reflect" "regexp" + "strconv" "strings" "time" @@ -132,6 +134,24 @@ func (c *Client) DropTable(ctx context.Context, table string) error { return c.conn.Exec(ctx, fmt.Sprintf("DROP TABLE IF EXISTS `%s`", table)) } +// DropColumns removes validated staging columns in one ALTER TABLE operation. +func (c *Client) DropColumns(ctx context.Context, table string, columns []string) error { + if err := validateIdentifier(table); err != nil { + return err + } + if len(columns) == 0 { + return nil + } + parts := make([]string, 0, len(columns)) + for _, column := range columns { + if err := validateIdentifier(column); err != nil { + return err + } + parts = append(parts, fmt.Sprintf("DROP COLUMN IF EXISTS `%s`", column)) + } + return c.conn.Exec(ctx, fmt.Sprintf("ALTER TABLE `%s` %s", table, strings.Join(parts, ", "))) +} + // VerifyOutput confirms that a staged publication table is readable, has the // expected physical columns, and contains exactly the rows acknowledged by // the publisher before any visibility pointer is advanced. @@ -175,6 +195,20 @@ func integerValue(value any) (int64, bool) { if typed <= uint64(^uint64(0)>>1) { return int64(typed), true } + case float64: + if typed == math.Trunc(typed) && typed >= math.MinInt64 && typed <= math.MaxInt64 { + return int64(typed), true + } + case json.Number: + parsed, err := typed.Int64() + if err == nil { + return parsed, true + } + case string: + parsed, err := strconv.ParseInt(typed, 10, 64) + if err == nil { + return parsed, true + } } return 0, false } diff --git a/internal/store/clickhouse/integration_test.go b/internal/store/clickhouse/integration_test.go index ba7d1fae..6fbd0555 100644 --- a/internal/store/clickhouse/integration_test.go +++ b/internal/store/clickhouse/integration_test.go @@ -57,6 +57,12 @@ func TestClickHouseNativeRoundTrip(t *testing.T) { }, []map[string]any{{"__loom_row_id": uint64(1), "name": "alice", "score": 2.5, "tags": []string{"a", "b"}}}); err != nil { t.Fatal(err) } + columns := []Column{ + {Name: "__loom_row_id", Type: "UInt64"}, + {Name: "name", Type: "Nullable(String)"}, + {Name: "score", Type: "Nullable(Float64)"}, + {Name: "tags", Type: "Array(String)"}, + } rows, err := client.QueryRowsArgs(ctx, "SELECT `name`, `score`, `tags` FROM `"+table+"`", []string{"name", "score", "tags"}) if err != nil { t.Fatal(err) @@ -64,4 +70,17 @@ func TestClickHouseNativeRoundTrip(t *testing.T) { if len(rows) != 1 || rows[0]["name"] != "alice" { t.Fatalf("round-trip rows = %#v", rows) } + if err := client.VerifyOutput(ctx, table, columns, 1); err != nil { + t.Fatalf("verify before pruning: %v", err) + } + if err := client.DropColumns(ctx, table, []string{"score"}); err != nil { + t.Fatalf("drop discovered column: %v", err) + } + if err := client.VerifyOutput(ctx, table, []Column{ + {Name: "__loom_row_id", Type: "UInt64"}, + {Name: "name", Type: "Nullable(String)"}, + {Name: "tags", Type: "Array(String)"}, + }, 1); err != nil { + t.Fatalf("verify after pruning: %v", err) + } } From 0554165c2d6c2a624fa675d4f7576ad889b1fb08 Mon Sep 17 00:00:00 2001 From: matthewpeterkort Date: Mon, 17 Aug 2026 17:43:03 -0700 Subject: [PATCH 03/15] update loom api to be more data specific --- README.md | 34 +- docs/DATAFRAMER_RECIPES.md | 70 +- docs/DATAFRAME_FEDERATION.md | 27 +- docs/DEVELOPER_ARCHITECTURE.md | 5 + docs/FRONTEND_EXPLORER_V2_MIGRATION.md | 453 + docs/GRAPHQL_API.md | 84 +- docs/QUICKSTART.md | 85 +- docs/loom-reliability-contract.md | 35 +- .../graphql/graph/executor/root_.generated.go | 743 +- .../graph/executor/schema.generated.go | 8057 ++++++----------- generated/graphql/graph/model/models.go | 206 +- .../api/bulk/dump/dataframe_export_route.go | 3 +- .../bulk/dump/dataframe_export_route_test.go | 12 +- internal/api/graphql/errors.go | 4 +- internal/api/graphql/graph/handler.go | 4 - .../graphql/graph/http_integration_test.go | 103 +- .../graphql/graph/materialization/export.go | 2 +- .../graphql/graph/materialization/output.go | 7 +- .../graph/materialization/output_test.go | 4 +- .../graphql/graph/materialization/service.go | 157 +- .../graph/materialization/service_test.go | 36 +- .../graph/resolver/graphql_output_helpers.go | 22 + .../graphql/graph/resolver/output_mapping.go | 149 - .../graph/resolver/recipe_control_test.go | 18 - .../api/graphql/graph/resolver/resolver.go | 35 +- .../graph/resolver/schema.resolvers.go | 60 - .../api/graphql/graph/schema/schema.graphqls | 110 +- internal/api/http/errors.go | 4 +- internal/api/http/recipe_execution.go | 2 +- internal/dataframe/errors/errors.go | 2 +- .../clickhouse/clickhouse_bundle_test.go | 6 +- internal/dataframe/published/export.go | 1 - internal/dataframe/published/federation.go | 52 +- .../dataframe/published/federation_test.go | 108 +- internal/dataframe/published/read.go | 277 +- internal/dataframe/published/types.go | 47 +- internal/dataframe/recipe/engine/engine.go | 36 + internal/dataset/arango/document_codec.go | 6 + internal/explorer/arango/collections.go | 21 + internal/explorer/arango/collections_test.go | 18 + internal/explorer/arango/store.go | 470 + internal/explorer/arango/store_test.go | 138 + internal/explorer/catalog.go | 87 + internal/explorer/catalog_test.go | 22 + internal/explorer/compilation.go | 28 + internal/explorer/config_v2.go | 190 + internal/explorer/config_v2_test.go | 48 + internal/explorer/identity.go | 34 + internal/explorer/memory_store.go | 232 + internal/explorer/service.go | 223 + internal/explorer/store.go | 38 + internal/explorer/types.go | 159 + internal/explorer/v2_lifecycle_test.go | 46 + internal/server/config_test.go | 4 +- internal/server/dataframe_contract.go | 107 - internal/server/dataframe_contract_test.go | 33 - internal/server/explorer_config_route.go | 134 + internal/server/explorer_config_route_test.go | 73 + internal/server/explorer_publication.go | 42 + internal/server/explorer_v2_engine.go | 127 + internal/server/explorer_v2_engine_test.go | 75 + internal/server/explorer_v2_lifecycle.go | 733 ++ internal/server/explorer_v2_lifecycle_test.go | 263 + internal/server/explorer_wiring.go | 111 + internal/server/options.go | 14 - internal/server/server.go | 71 +- internal/store/arango/client.go | 39 +- 67 files changed, 7186 insertions(+), 7460 deletions(-) create mode 100644 docs/FRONTEND_EXPLORER_V2_MIGRATION.md create mode 100644 internal/api/graphql/graph/resolver/graphql_output_helpers.go delete mode 100644 internal/api/graphql/graph/resolver/output_mapping.go create mode 100644 internal/explorer/arango/collections.go create mode 100644 internal/explorer/arango/collections_test.go create mode 100644 internal/explorer/arango/store.go create mode 100644 internal/explorer/arango/store_test.go create mode 100644 internal/explorer/catalog.go create mode 100644 internal/explorer/catalog_test.go create mode 100644 internal/explorer/compilation.go create mode 100644 internal/explorer/config_v2.go create mode 100644 internal/explorer/config_v2_test.go create mode 100644 internal/explorer/identity.go create mode 100644 internal/explorer/memory_store.go create mode 100644 internal/explorer/service.go create mode 100644 internal/explorer/store.go create mode 100644 internal/explorer/types.go create mode 100644 internal/explorer/v2_lifecycle_test.go delete mode 100644 internal/server/dataframe_contract.go delete mode 100644 internal/server/dataframe_contract_test.go create mode 100644 internal/server/explorer_config_route.go create mode 100644 internal/server/explorer_config_route_test.go create mode 100644 internal/server/explorer_publication.go create mode 100644 internal/server/explorer_v2_engine.go create mode 100644 internal/server/explorer_v2_engine_test.go create mode 100644 internal/server/explorer_v2_lifecycle.go create mode 100644 internal/server/explorer_v2_lifecycle_test.go create mode 100644 internal/server/explorer_wiring.go diff --git a/README.md b/README.md index e4e2e42a..e48ee12b 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ flowchart LR Publish --> ClickHouse["Versioned flat tables"] Publish --> Catalog["Arango publication catalog"] Catalog["Arango publication catalog"] --> Graph["POST /graphql/graph"] - ClickHouse --> Flat + ClickHouse --> Graph Arango --> Graph["POST /graphql/graph"] Arango --> Dataframe["POST /graphql/dataframe"] Compile --> Graph @@ -39,13 +39,13 @@ flowchart LR - Populated-field, reference, traversal, and pivot discovery. - Strict, versioned dataframe recipes and compiler-backed AQL execution. - Scoped publication of recipe outputs into ClickHouse. -- A durable Arango catalog that maps logical dataframe names to current READY - ClickHouse outputs. +- A durable Arango catalog that maps exact dataframe selectors to current + published outputs. - Multi-project, `project_id`-identifiable and `auth_resource_path`-scoped flat-data reads. Loom does **not** expose arbitrary ClickHouse tables, arbitrary SQL, or an -Elasticsearch/Guppy fallback. A logical `dataType` is a catalog alias, never a -browser-supplied physical table name. +Elasticsearch/Guppy fallback. Published dataframe reads require an exact +recipe, translation-version, and output selector. ## Runtime surfaces @@ -53,10 +53,9 @@ browser-supplied physical table name. | --- | --- | | `arango-fhir-proto` | Operator CLI for loading data, loading immutable generations, catalog discovery, and local dataframe materialization. | | `arango-fhir-server` | HTTP server for graph compilation/control and flat dataframe reads. | -| `POST /graphql/graph` | Arango graph and recipe control plane: explicit graph traversal, typed FHIR reads, builder introspection, recipe validation, preview, execution, and publication. | +| `POST /graphql/graph` | Arango graph and recipe control plane: explicit graph traversal, typed FHIR reads, recipe validation, preview, execution, publication reads, and recipe control. | | `POST /graphql/dataframe` | Arango-backed FHIR dataframe compiler and executor (`runFhirDataframe`). | -| `POST /graphql/graph` | Graph and published-dataframe API: graph reads, recipe control, and ClickHouse publication reads. | -| `POST /graphql/flat` | Compatibility alias for `/graphql/graph` published-dataframe queries. | +| `POST /api/v1/projects/:project/explorers/...` | REST V2 Explorer lifecycle used by the Builder. | | `PUT /api/v1/projects/:project/resources/:resourceType` | Primary multipart NDJSON resource loader. | `GET /graphql/graph` serves GraphQL Playground for the graph API. `GET /apollo` @@ -148,7 +147,7 @@ Useful local URLs: - [Graph Playground](http://127.0.0.1:8080/graphql/graph) - [Apollo Sandbox](http://127.0.0.1:8080/apollo) - FHIR dataframe: `http://127.0.0.1:8080/graphql/dataframe` -- Published dataframe reader: `http://127.0.0.1:8080/graphql/graph` (legacy alias: `/graphql/flat`) +- Published dataframe reader: `http://127.0.0.1:8080/graphql/graph` - [Health summary](http://127.0.0.1:8080/health) - [Process liveness](http://127.0.0.1:8080/livez) - [Dependency readiness](http://127.0.0.1:8080/readyz) @@ -223,19 +222,22 @@ query ExplorerRows($input: DataframeRowsInput!) { ```json { "input": { - "dataType": "cases", + "selector": { + "recipe": "documents", + "translationVersion": "v2", + "output": "DocumentReference" + }, "first": 100, "sort": { "column": "case_id" } } } ``` -The preferred reader input is the exact selector `(recipe, -translationVersion, output)`. The deprecated `dataType` form remains -available through the configured default recipe and translation version. Loom -derives the authorized project set from the principal, selects each project's -active pointer-backed publication, reconciles compatible outputs, and -federates them into one logical dataframe. Every row exposes `project_id`, +The reader requires the exact selector `(recipe, translationVersion, output)`. +There is no server-side default recipe or `dataType` alias. Loom derives the +authorized project set from the principal, selects each project's active +pointer-backed publication, reconciles compatible outputs, and federates them +into one logical dataframe. Every row exposes `project_id`, derived from the publication project identity (for example, `HTAN_INT-BForePC`), and it is filterable and sortable like other scalar columns. Rows remain permissive JSON; columns and capabilities are discovered diff --git a/docs/DATAFRAMER_RECIPES.md b/docs/DATAFRAMER_RECIPES.md index 1c8b2f5e..14e805fe 100644 --- a/docs/DATAFRAMER_RECIPES.md +++ b/docs/DATAFRAMER_RECIPES.md @@ -133,7 +133,8 @@ grain: These names are public API: -- `outputs[].name` becomes the flat API `dataType`. +- `outputs[].name` becomes the `output` component of the exact dataframe + selector `(recipe, translationVersion, output)`. - `fields[].name`, pivot names, and dynamic-column names contribute public column names. - A traversal `alias` namespaces fields from the related resource. @@ -148,68 +149,23 @@ must deliberately produce multiple rows. ## Step 2: discover the graph that is actually loaded -Run `dataframeBuilderIntrospection` against the project and proposed root. -This reports populated fields, pivot candidates, and valid outbound -relationships. Do not infer relationship labels from FHIR property names. +Use the REST V2 authoring compiler and its server-owned catalog discovery. It +reports populated fields, pivot candidates, and valid outbound relationships +for the selected generation. Do not infer relationship labels from FHIR +property names or manufacture browser selector IDs. See +[`FRONTEND_EXPLORER_V2_MIGRATION.md`](FRONTEND_EXPLORER_V2_MIGRATION.md). -```graphql -query RecipeDiscovery($input: DataframeBuilderIntrospectionInput!) { - dataframeBuilderIntrospection(input: $input) { - rootResourceType - root { - fields { - fieldRef - path - } - pivotFields { - fieldRef - path - pivotFamily - pivotColumns - } - traversals { - fromType - label - toType - edgeCount - } - } - relatedResources { - viaLabel - edgeCount - target { - resourceType - fields { - fieldRef - path - } - } - } - } -} -``` - -```json -{ - "input": { - "project": "HTAN_INT-BForePC", - "rootResourceType": "DocumentReference", - "includePivotOnlyFields": true - } -} -``` - -For a second hop, rerun introspection with the first-hop target as the root. -For example: +For a second hop, select the first-hop target in the authoring request. For +example: ```text DocumentReference --subject_Specimen--> Specimen Specimen --subject_Patient----> Patient ``` -Both labels and target types must be confirmed by introspection. A relationship -with `edgeCount: 0` is not useful for that project even if the FHIR schema -allows it. +Both labels and target types must be confirmed by the catalog. A relationship +with no discovered candidates is not useful for that project even if the FHIR +schema allows it. ## Step 3: prototype before persisting @@ -232,7 +188,7 @@ The GraphQL input and persistent recipe use the same concepts: | `project`, `limit`, authorization | Runtime bindings; never stored | The copy-paste GraphQL examples in -[the Quickstart](QUICKSTART.md#5-run-a-builder-introspection-query) cover +[the Quickstart](QUICKSTART.md#6-run-a-sample-dataframe-query) cover introspection and dataframe execution. ## Minimal recipe diff --git a/docs/DATAFRAME_FEDERATION.md b/docs/DATAFRAME_FEDERATION.md index 76825dcf..7349967e 100644 --- a/docs/DATAFRAME_FEDERATION.md +++ b/docs/DATAFRAME_FEDERATION.md @@ -88,10 +88,9 @@ query Rows($input: DataframeRowsInput!) { } ``` -The deprecated `dataType` input remains available during migration. It is -resolved through `LOOM_DEFAULT_RECIPE` and -`LOOM_DEFAULT_TRANSLATION_VERSION`; clients must not provide `selector` and -`dataType` together. New clients should use selectors explicitly. +The selector is mandatory. Loom does not resolve a server-side default recipe, +accept a `dataType` alias, or infer a translation version. This keeps a read +bound to the exact recipe contract that produced its publication. ## How sources are selected @@ -127,9 +126,9 @@ QUEUED -> RUNNING -> VALIDATING -> PUBLISHED Physical ClickHouse tables are written and verified before the catalog pointer is advanced. A reader therefore sees either the prior pointer or the new -verified publication, not a partially written bundle. Legacy stored `READY` -values remain readable and are interpreted as successful publications; new -workflows do not write `READY`. +verified publication, not a partially written bundle. New workflows use +`PUBLISHED`; storage adapters may normalize historical persisted states while +those records are being retired, but no new API accepts or emits them. Project releases add another visibility boundary. A staged generation and its verified exact-selector publications become active together through the active @@ -200,9 +199,8 @@ The same federated source set is used by: - `dataframeAggregate` and `dataframeAggregations` for aggregates; - the dataframe export route for CSV, TSV, JSON, and JSONL streaming. -The legacy `materializationId` input remains a direct single-publication path -for compatibility. It is not the federation path and should not be used for -new multi-project clients. +There is no materialization-ID or physical-table read path. All reads use the +exact selector and resolve the active publication through the catalog. ## Operational setup @@ -220,13 +218,6 @@ For a new recipe version, publish and verify it first, then promote or select that exact version. Do not rely on “latest” behavior to switch a production reader between versions. -Recommended configuration for legacy callers: - -```text -LOOM_DEFAULT_RECIPE=documents -LOOM_DEFAULT_TRANSLATION_VERSION=v2 -``` - Recommended configuration for release verification is a list of exact selectors, not output names alone. See `LOOM_REQUIRED_DATAFRAME_SELECTORS` and the release contract documentation. @@ -235,7 +226,7 @@ selectors, not output names alone. See | Symptom | Likely cause | | --- | --- | -| `INVALID_SELECTOR` | Selector is incomplete, both selector and `dataType` were supplied, or legacy defaults are not configured. | +| `INVALID_SELECTOR` | Selector is missing or incomplete. | | `UNAVAILABLE` / `DATASET_NOT_FOUND` | No pointer-backed exact publication is active or authorized. | | `DEGRADED` | One or more expected projects are missing, stale, failed, building, or excluded. | | `FEDERATION_INCOMPATIBLE` | Same logical column has incompatible ClickHouse types across selected sources. | diff --git a/docs/DEVELOPER_ARCHITECTURE.md b/docs/DEVELOPER_ARCHITECTURE.md index db9252be..06995b7c 100644 --- a/docs/DEVELOPER_ARCHITECTURE.md +++ b/docs/DEVELOPER_ARCHITECTURE.md @@ -30,6 +30,11 @@ they do not live in `generated/`. ## Runtime surfaces +The Builder integration contract is documented in +[`FRONTEND_EXPLORER_V2_MIGRATION.md`](FRONTEND_EXPLORER_V2_MIGRATION.md). +The Builder uses the REST Explorer lifecycle. GraphQL does not expose Explorer +lifecycle or authoring types; REST V2 is the only Explorer contract. + Ownership map: `dataset` owns immutable FHIR generation lifecycle; `catalog` owns persistence-neutral observed facts; `catalog/arango` owns catalog persistence; `dataframe/publication` owns dataframe publishing contracts and diff --git a/docs/FRONTEND_EXPLORER_V2_MIGRATION.md b/docs/FRONTEND_EXPLORER_V2_MIGRATION.md new file mode 100644 index 00000000..de681ee6 --- /dev/null +++ b/docs/FRONTEND_EXPLORER_V2_MIGRATION.md @@ -0,0 +1,453 @@ +# Frontend Explorer V2 Migration + +This guide describes the frontend contract for Loom's REST Explorer lifecycle. +The Builder should use these REST routes for Explorer management and authoring. +It should not depend on the legacy GraphQL Explorer mutations or on generated +GraphQL candidate-input types. + +## The important model change + +Loom now has two Explorer ownership modes: + +| Explorer | Owner | Config returned by Loom | Frontend behavior | +| --- | --- | --- | --- | +| `default` | Repository / ETL | `baselineConfig` contains the recipe/schema baseline; `activeConfig` may contain the complete ETL-authored packet | Render `activeConfig` when present, otherwise build the layout from live dataset metadata. | +| Custom ID | User / Builder | `draftConfig` and, after publication, `activeConfig` contain the complete V2 packet | Render and edit the lossless presentation config. | + +Repository packets may be baseline-only or may include a complete presentation +layer. When ETL includes `views`, filters, charts, shared filters, or file +actions, Loom preserves them losslessly and exposes the published packet as +`default.activeConfig`. `default.baselineConfig` remains presentation-free. + +The default Explorer response is still useful for readiness and publication +state. Its `dataset.outputs[].columns` and `emittedColumns` describe the live +materialization. The frontend should derive the default table from those +columns and apply local presentation hints such as labels and ordering. + +Custom packets may contain all V2 presentation fields, but Loom remains +authoritative for schema, readiness, publication state, and materialization +metadata. Treat a custom config as invalid or stale when its referenced output +or column is not present in the live dataset. + +## API base URL + +The routes are rooted at: + +```text +/api/v1/projects/:project/explorers +``` + +In the deployed Calypr frontend this is normally reached through the Loom +reverse-proxy prefix, for example: + +```text +/loom/api/v1/projects/HTAN_INT-BForePC/explorers +``` + +Keep the prefix configurable. Do not hard-code the training host or a port +forward into frontend code. + +All requests use the application's existing authenticated session. Preserve +cookies, bearer headers, and the project authorization context used by the +rest of the frontend. + +## Explorer state + +The frontend should model the response as server state, not as a GraphQL model: + +```ts +type ExplorerManagement = "REPOSITORY" | "INTERACTIVE"; + +interface ExplorerState { + project: string; + explorerId: string; + management: ExplorerManagement; + + // Present for the repository default. It is always the presentation-free + // recipe/schema baseline. + baselineConfig?: ExplorerConfigV2; + + // The published packet is renderable but not editable. It may be present + // for the repository default and is present after custom publication. + activeConfig?: ExplorerConfigV2; + + // Present for custom Explorers only. The default is read-only and does not + // require an editable draft. + draftConfig?: ExplorerConfigV2; + + draftVersion: number; + draftDigest: string; + activeRevisionId?: string; + recipeDigest?: string; + resolvedSchemaDigest?: string; + sourceGeneration?: string; + emittedColumns?: EmittedColumn[]; + materializations?: Materialization[]; + dataset?: DatasetMetadata; + publication?: PublicationMetadata; + diagnostics?: Diagnostic[]; + publicationState?: string; + activeUrl: string; + updatedBy?: string; + updatedAt: string; +} + +interface DatasetMetadata { + generation?: string; + schemaDigest?: string; + outputs: DatasetOutput[]; +} + +interface DatasetOutput { + name: string; + state: string; + queryable: boolean; + columns?: PhysicalColumn[]; +} + +interface PublicationMetadata { + state: string; + generation?: string; + executionId?: string; + revisionId?: string; + updatedAt?: string; +} + +interface Diagnostic { + severity: string; + code: string; + fieldPath?: string; + message: string; + retryable?: boolean; + requestId?: string; +} +``` + +`activeUrl` is Loom's resource URL for the Explorer lifecycle record. It is +not necessarily the browser route used to render the Builder page. + +## REST lifecycle + +### Read the Explorer list + +```http +GET /api/v1/projects/:project/explorers +``` + +Returns an array of `ExplorerState` values. The default is ordered first, +followed by custom IDs. Use this route for the Explorer picker and then fetch +the selected detail record. + +### Read one Explorer + +```http +GET /api/v1/projects/:project/explorers/:explorerId +``` + +For `default`, this is read-only but fully inspectable. Do not expect a +`draftConfig`; the repository default has no editable draft. Render +`activeConfig` when it contains a complete packet. If it is absent or has no +views, use `baselineConfig` and derive the layout from `dataset`. + +### Create a custom Explorer + +```http +POST /api/v1/projects/:project/explorers +Content-Type: application/json + +{ + "name": "Cohort Explorer", + "title": "Cohort Explorer", + "source": "default" +} +``` + +The server derives the stable ID (`cohort-explorer`) from the name. The ID is +durable and becomes part of the URL. Do not generate a random browser ID or +send a client-selected ID as the identity source. + +To create an empty custom packet instead: + +```json +{ + "name": "Scratch Explorer", + "blank": true +} +``` + +Creation saves a draft only. It does not compile, materialize, or publish. +The response is the new `ExplorerState`. + +### Save a draft + +```http +PUT /api/v1/projects/:project/explorers/:explorerId/draft +Content-Type: application/json + +{ + "config": { "...complete ExplorerConfig V2...": "..." }, + "expectedDraftVersion": 3, + "expectedDraftDigest": "sha256:..." +} +``` + +This endpoint validates and canonicalizes the packet, computes its digest, and +saves only the draft. It does not compile, materialize, or change the active +revision. `expectedDraftVersion` is required; send `expectedDraftDigest` when +available. + +On conflict, Loom returns HTTP 409: + +```json +{ + "error": { + "code": "DRAFT_CONFLICT", + "message": "Explorer draft changed; refresh before saving", + "currentVersion": 4, + "currentDigest": "sha256:...", + "updatedAt": "2026-08-17T19:00:00Z" + } +} +``` + +The frontend must refresh and reconcile the user's edits. Do not silently +overwrite, retry with the new version, or attempt a client-side merge unless +the user explicitly confirms it. + +### Compile authoring selections + +```http +POST /api/v1/projects/:project/explorers/:explorerId/authoring/compile +Content-Type: application/json + +{ + "output": "DocumentReference", + "config": { "...complete ExplorerConfig V2...": "..." }, + "snapshotToken": "loom:generation-token", + "selectedCandidateIdsByNode": { + "root": ["opaque-candidate-id"] + }, + "expectedDraftVersion": 3 +} +``` + +The response contains: + +```json +{ + "project": "HTAN_INT-BForePC", + "explorerId": "cohort-explorer", + "config": { "...canonical V2 packet...": "..." }, + "draftDigest": "sha256:...", + "snapshotToken": "loom:generation-token", + "recipeDigest": "sha256:...", + "resolvedSchemaDigest": "sha256:...", + "sourceGeneration": "generation-id", + "emittedColumns": [], + "diagnostics": [] +} +``` + +Compile is a validation/authoring operation. It does not save the draft or +publish data. The server resolves opaque candidate IDs through Loom's catalog; +the browser must not send AST nodes, physical table names, or browser-generated +selector IDs. + +The snapshot token and expected draft version protect against compiling against +a stale dataset or stale draft. Refresh the Explorer and discovery state when +Loom returns a conflict or an incomplete/unresolved catalog diagnostic. + +### Preview without publication + +```http +POST /api/v1/projects/:project/explorers/:explorerId/preview +Content-Type: application/json + +{ + "config": { "...complete ExplorerConfig V2...": "..." }, + "output": "DocumentReference", + "limit": 25, + "draftDigest": "sha256:..." +} +``` + +A successful response is shaped like: + +```json +{ + "project": "HTAN_INT-BForePC", + "explorerId": "cohort-explorer", + "output": "DocumentReference", + "columns": ["id", "subject_id"], + "rows": [{"id": "...", "subject_id": "..."}], + "rowCount": 1, + "digest": "sha256:...", + "diagnostics": [] +} +``` + +`limit` defaults to 25 and must be between 1 and 1000. Preview is scoped to +the requested output and never changes draft, revision, materialization, or +active-pointer state. + +Preview failures are terminal responses, not an indefinite loading state. They +return HTTP 422 with empty `columns`/`rows` and a diagnostic such as +`PREVIEW_FAILED`: + +```json +{ + "columns": [], + "rows": [], + "rowCount": 0, + "digest": "sha256:...", + "diagnostics": [{ + "severity": "ERROR", + "code": "PREVIEW_FAILED", + "message": "..." + }] +} +``` + +### Publish a custom Explorer + +```http +POST /api/v1/projects/:project/explorers/:explorerId/publish +Content-Type: application/json + +{ + "expectedDraftVersion": 3, + "expectedDraftDigest": "sha256:..." +} +``` + +Publish reads the server-owned draft. The frontend does not send a config in +this request. Loom recompiles the draft, materializes every referenced output, +checks that every output is queryable, inserts an immutable revision, and then +activates it. A failed publication leaves the previous active revision in +place and records diagnostics on the failed revision. + +On success, update the local store from the returned `state` rather than +manually inferring active metadata: + +```json +{ + "project": "HTAN_INT-BForePC", + "explorerId": "cohort-explorer", + "publicationId": "interactive_...", + "activeUrl": "/api/v1/projects/HTAN_INT-BForePC/explorers/cohort-explorer", + "state": { "...ExplorerState...": "..." }, + "materializations": [], + "diagnostics": [] +} +``` + +## ExplorerConfig V2 rules + +Every config sent to a custom Explorer endpoint must be a complete packet: + +```json +{ + "apiVersion": "loom.calypr.org/explorer-config/v2", + "kind": "ExplorerConfig", + "project": "HTAN_INT-BForePC", + "explorer": { + "id": "cohort-explorer", + "title": "Cohort Explorer", + "management": "interactive" + }, + "recipe": { "...valid Loom recipe bundle...": "..." }, + "views": [ + { + "id": "document-reference", + "title": "DocumentReference", + "output": "DocumentReference", + "table": { + "columns": [ + {"column": "id", "label": "ID", "visible": true} + ] + } + } + ] +} +``` + +The `project`, `explorer.id`, and `explorer.management` values must match the +URL and operation. Interactive packets require at least one view. View output +names must exist in the recipe, and each view must have table columns. +Unknown fields are rejected. + +The recipe is executable data, not a frontend AST. Presentation fields are +losslessly retained in the packet but are not reconstructed from the recipe. +Keep them in the config object when editing; do not rebuild a config from +`recipe` alone. + +## Recommended frontend structure + +Split the implementation into three layers: + +1. `explorerApi` — typed REST calls and error decoding. +2. `explorerStore` — the selected project/Explorer, draft version/digest, + active revision, and request status. +3. Presenters: + - `DefaultExplorerPresenter`: renders `activeConfig` when present and + derives views from `dataset.outputs` and `columns` otherwise. + - `InteractiveExplorerPresenter`: renders `draftConfig.views` and validates + referenced outputs/columns against live metadata. + +The default presenter should tolerate missing optional presentation hints and +should drop a hint for a column that is no longer emitted. A stale custom +config should produce an actionable validation diagnostic and allow the user +to repair it; it should not be treated as the repository default. + +The minimum request flow is: + +```text +GET explorers + -> GET selected Explorer + -> custom: edit draft and PUT /draft + -> POST /authoring/compile when discovery changes + -> POST /preview for the selected output + -> POST /publish after explicit user confirmation + -> replace local state with returned state +``` + +Do not route normal Builder operations through `/graphql/graph`. In particular, +remove dependencies on legacy types such as +`DataframeRecipeColumnCandidatesInput`; candidate discovery and compilation for +the Builder belong behind the REST lifecycle contract. + +## Error handling checklist + +- `400`: malformed request, missing expected version, unsupported limit, or + missing required header/input. Show a request correction message. +- `403`: authorization failure or an attempted write to `default`. +- `404`: the custom Explorer does not exist. Refresh the Explorer list. +- `409` with `DRAFT_CONFLICT`: refresh server state and reconcile edits. +- `409` during publication/activation: keep the current active Explorer and + show the returned diagnostic; do not claim publication succeeded. +- `422`: invalid V2 config, unresolved/incomplete catalog, unsupported output, + materialization failure, or preview failure. Render diagnostics as terminal + Builder feedback. +- `503`: publication capability is temporarily unavailable. Keep the draft + local/server state intact and allow retry. + +Never leave the UI in `Preparing preview` or `Publishing` after a terminal +HTTP response. Clear the pending state in both success and failure handlers. + +## Migration checklist + +- [ ] Add a configurable Loom REST base path. +- [ ] Replace GraphQL Explorer list/detail reads with the REST list/detail routes. +- [ ] Never require `default.draftConfig` for rendering. +- [ ] Render `default.activeConfig` when ETL supplied a complete packet. +- [ ] Generate the default layout from `dataset.outputs[].columns` when no + complete `activeConfig` is available. +- [ ] Preserve complete custom V2 packets, including presentation fields. +- [ ] Send `expectedDraftVersion` on every draft/compile/publish mutation. +- [ ] Send the latest `expectedDraftDigest` when available. +- [ ] Handle `DRAFT_CONFLICT` by refreshing and reconciling, never overwriting. +- [ ] Replace GraphQL candidate input types with opaque REST candidate IDs. +- [ ] Use the REST compile result as the source of emitted columns and digests. +- [ ] Scope preview to one output and clear loading state on 4xx/5xx responses. +- [ ] Publish only after explicit confirmation and consume the returned state. +- [ ] Keep repository default read-only in the frontend. diff --git a/docs/GRAPHQL_API.md b/docs/GRAPHQL_API.md index e8c7a929..046c070e 100644 --- a/docs/GRAPHQL_API.md +++ b/docs/GRAPHQL_API.md @@ -6,7 +6,6 @@ Loom has two GraphQL routes with different responsibilities: - `/graphql/dataframe` compiles and executes FHIR dataframe requests against the authorized Arango graph. - `/graphql/graph` also reads published dataframe outputs from ClickHouse. -- `/graphql/flat` remains as a compatibility alias for published-dataframe queries. All surfaces are authorization-aware. Clients provide logical names and FHIR fields; they do not provide AQL, SQL, physical collection names, or physical @@ -20,7 +19,6 @@ The useful development URLs are: ```text GraphQL graph: http://127.0.0.1:8080/graphql/graph GraphQL dataframe: http://127.0.0.1:8080/graphql/dataframe -GraphQL flat (compatibility alias): http://127.0.0.1:8080/graphql/flat Playground: http://127.0.0.1:8080/graphql/graph Apollo: http://127.0.0.1:8080/apollo ``` @@ -33,44 +31,13 @@ pasted into Apollo Sandbox or sent as a normal GraphQL HTTP POST. The graph endpoint is the Arango/compiler surface for explicit graph traversal, typed FHIR reads, discovery, and recipe control operations. -### Discover populated fields and routes +### Explorer authoring and catalog discovery -Use builder introspection before constructing a dataframe query. It reports -populated field references and generated traversal routes for the selected -project and root resource. - -```graphql -query Builder($input: DataframeBuilderIntrospectionInput!) { - dataframeBuilderIntrospection(input: $input) { - project - rootResourceType - authResourcePaths - root { - resourceType - fields { fieldRef label path } - traversals { fromType label toType edgeCount } - } - relatedResources { - viaLabel - edgeCount - target { resourceType fields { fieldRef label path } } - } - } -} -``` - -```json -{ - "input": { - "project": "ARANGODB_PROTO", - "rootResourceType": "Patient" - } -} -``` - -Field references are resolved against the active READY generation and the -caller's authorization scope. Do not assume that a syntactically valid FHIR -field is populated in every project. +The Builder uses the REST V2 Explorer lifecycle documented in +[`FRONTEND_EXPLORER_V2_MIGRATION.md`](FRONTEND_EXPLORER_V2_MIGRATION.md). +GraphQL Explorer lifecycle and Builder-introspection fields are not part of +the current contract; the REST authoring compiler resolves catalog selections +and the active dataset generation through one server-owned path. ### FHIR dataframe compilation @@ -299,9 +266,9 @@ returned through this API. ## Published dataframe API -The published-dataframe fields read only published, READY outputs from ClickHouse. -The client supplies the logical `dataType`; Loom resolves the authorized -project set and current READY publication from the catalog. +The published-dataframe fields read only published outputs from ClickHouse. +The client supplies the exact selector; Loom resolves the authorized project +set and current publication from the catalog. ### Discover datasets and columns @@ -341,11 +308,20 @@ query Dataset($input: DataframeDatasetInput!) { ``` ```json -{ "input": { "dataType": "cases" } } +{ + "input": { + "selector": { + "recipe": "documents", + "translationVersion": "v2", + "output": "DocumentReference" + } + } +} ``` Use the returned column metadata to choose valid projection, filter, sort, and -aggregation fields. A logical `dataType` is not a physical table name. +aggregation fields. The selector is the logical identity; it is not a physical +table name. ### Read rows @@ -364,7 +340,11 @@ query Rows($input: DataframeRowsInput!) { ```json { "input": { - "dataType": "cases", + "selector": { + "recipe": "documents", + "translationVersion": "v2", + "output": "DocumentReference" + }, "columns": ["case_id", "status", "amount"], "filters": [ { "column": "status", "op": "EQ", "value": "open" }, @@ -417,7 +397,11 @@ query Aggregate($input: DataframeAggregateInput!) { ```json { "input": { - "dataType": "cases", + "selector": { + "recipe": "documents", + "translationVersion": "v2", + "output": "DocumentReference" + }, "groupBy": ["status"], "filters": [{ "column": "amount", "op": "GTE", "value": 100 }], "operation": "COUNT", @@ -432,10 +416,10 @@ Supported aggregate operations are `COUNT`, `COUNT_DISTINCT`, `SUM`, `AVG`, ## Authorization and generations -Graph reads resolve the active READY dataset generation for the requested -project. Flat reads resolve authorized current READY publications for the -logical `dataType`. Clients should not send generation IDs or physical table -names as query selectors. +Graph reads resolve the active dataset generation for the requested project. +Flat reads resolve authorized current publications for the exact selector. +Clients should not send generation IDs or physical table names as query +selectors. `authResourcePaths` on graph requests is a narrowing request. It cannot widen the principal's authorized scope. Flat reads apply authorization to each diff --git a/docs/QUICKSTART.md b/docs/QUICKSTART.md index 5cfdecad..ef9b7a53 100644 --- a/docs/QUICKSTART.md +++ b/docs/QUICKSTART.md @@ -96,86 +96,17 @@ On macOS you can jump straight to Apollo with: open http://127.0.0.1:8080/apollo ``` -## 5. Run a builder introspection query +## 5. Inspect and author an Explorer -Use this first. It tells you what traversals and fields are actually populated -for the chosen root resource type. +Explorer authoring is a REST V2 workflow. Start with the project Explorer +list/detail routes, then use the server-owned catalog compiler and preview +endpoints. The frontend migration guide has the request and response shapes: -To promote a proven interactive query into the server's persistent default, -follow the [dataframer recipe authoring guide](DATAFRAMER_RECIPES.md). +[`FRONTEND_EXPLORER_V2_MIGRATION.md`](FRONTEND_EXPLORER_V2_MIGRATION.md) -### Query - -```graphql -query BuilderIntrospection($input: DataframeBuilderIntrospectionInput!) { - dataframeBuilderIntrospection(input: $input) { - project - rootResourceType - authResourcePaths - root { - resourceType - fields { - fieldRef - label - path - selector { - sourcePath - valuePath - where { - path - op - value - } - } - } - pivotFields { - fieldRef - label - pivotFamily - pivotColumns - defaultPivotColumnSelector { - sourcePath - valuePath - } - defaultPivotValueSelector { - sourcePath - valuePath - } - } - traversals { - fromType - label - toType - edgeCount - } - } - relatedResources { - viaLabel - edgeCount - target { - resourceType - fields { - fieldRef - label - path - } - } - } - } -} -``` - -### Variables - -```json -{ - "input": { - "project": "ARANGODB_PROTO", - "rootResourceType": "Patient", - "includePivotOnlyFields": true - } -} -``` +The workflow is deliberately not a GraphQL introspection query: Loom validates +catalog selections, dataset generation, recipe compilation, preview, and +publication through the same REST capability path. ## 6. Run a sample dataframe query diff --git a/docs/loom-reliability-contract.md b/docs/loom-reliability-contract.md index 27bb619e..72ef4cb3 100644 --- a/docs/loom-reliability-contract.md +++ b/docs/loom-reliability-contract.md @@ -2,8 +2,8 @@ This document freezes the compatibility contract for versioned dataframe publication, immutable ingest, project releases, federation, and ETL. New code -must use these identities and states. Legacy readers remain additive during the -compatibility window described below. +must use these identities and states. The public APIs have no name-only or +default-contract compatibility path. ## Canonical identities @@ -30,8 +30,8 @@ resourceType)`, and its checksum is part of the idempotency contract. - Authorized project state: `CURRENT`, `STALE`, `BUILDING`, `FAILED`, `MISSING`, `EXCLUDED`. -Legacy `READY` values remain readable and map to the appropriate successful -state, but new workflows never write `READY`. +Historical storage rows may be normalized by the storage adapters while they +are retired, but new workflows use only `PUBLISHED`. ## Project release @@ -58,10 +58,9 @@ input DataframeSelectorInput { } ``` -Dataset discovery, rows, aggregate, aggregations, and export accept exactly one -of `selector` or deprecated `dataType`. Passing both is an input error. -`dataType` resolves through the configured default recipe and active promoted -contract version. +Dataset discovery, rows, aggregate, aggregations, and export require a +complete `selector`. No `dataType`, materialization-ID, or default recipe +resolution is accepted. Dataset metadata exposes the exact selector, active contract version, availability, completeness, included and expected project counts, and an @@ -74,10 +73,7 @@ Operator operations support: 1. starting an asynchronous exact-version materialization; 2. polling its durable execution; 3. activating a completed project release; and -4. explicitly promoting a recipe version as the default federation contract. - -The first registered contract may initialize the default automatically. Every -later version requires explicit promotion. +4. activating a project release containing the exact published selectors. ## Snapshot HTTP API @@ -106,8 +102,7 @@ Public structured errors use stable codes: queryable for the staged generation; - `RELEASE_ACTIVATION_CONFLICT`: compare-and-swap observed a newer active release; and -- `INVALID_SELECTOR`: selector/dataType inputs are absent, ambiguous, or - mutually supplied. +- `INVALID_SELECTOR`: the selector is absent or incomplete. Every structured failure may include phase, output, details, retryability, and the Loom request ID. Retryability is explicit; clients do not infer it from an @@ -115,8 +110,6 @@ HTTP status or message. ## Configuration -- `LOOM_DEFAULT_RECIPE`: recipe used to resolve deprecated `dataType`. -- `LOOM_DEFAULT_TRANSLATION_VERSION`: promoted default contract version. - `LOOM_REQUIRED_DATAFRAME_SELECTORS`: JSON array of exact selectors required for release activation. - `LOOM_PUBLICATION_WORKER_LEASE`: publication worker lease duration. @@ -130,12 +123,10 @@ names and meanings remain stable. ## Migration rules -The rollout is additive. Existing name-only recipes, direct materialization-ID -reads, deprecated `dataType`, and stored `READY` states remain readable for one -compatibility window. Legacy recipe rows are interpreted at the configured -default translation version. Legacy executions retain their IDs and acquire -selector fields when resolvable; unresolved legacy rows are readable but never -chosen by exact-selector federation. +The rollout is selector-first. Existing persisted publication rows may be +read by storage migration code, but they are never selected through a name-only +or default contract and no new request can address them without an exact +selector. New writes always use exact recipe versions, immutable generation keys, durable publication states, and release-controlled visibility. No migration step moves diff --git a/generated/graphql/graph/executor/root_.generated.go b/generated/graphql/graph/executor/root_.generated.go index 46da61b0..a86af822 100644 --- a/generated/graphql/graph/executor/root_.generated.go +++ b/generated/graphql/graph/executor/root_.generated.go @@ -582,17 +582,6 @@ type ComplexityRoot struct { Materialization func(childComplexity int) int } - DataframeBuilderIntrospection struct { - AuthResourcePaths func(childComplexity int) int - Fields func(childComplexity int) int - PivotFields func(childComplexity int) int - Project func(childComplexity int) int - RelatedResources func(childComplexity int) int - Root func(childComplexity int) int - RootResourceType func(childComplexity int) int - Traversals func(childComplexity int) int - } - DataframeColumn struct { Aggregatable func(childComplexity int) int ClickhouseType func(childComplexity int) int @@ -617,64 +606,26 @@ type ComplexityRoot struct { TraversalSets func(childComplexity int) int } - DataframeContract struct { - PromotedAt func(childComplexity int) int - Recipe func(childComplexity int) int - TranslationVersion func(childComplexity int) int - } - - DataframeFieldHint struct { - DefaultPivotColumnSelector func(childComplexity int) int - DefaultPivotValueSelector func(childComplexity int) int - DistinctTruncated func(childComplexity int) int - DistinctValues func(childComplexity int) int - DocCount func(childComplexity int) int - FieldRef func(childComplexity int) int - Kind func(childComplexity int) int - Label func(childComplexity int) int - Path func(childComplexity int) int - PivotCandidate func(childComplexity int) int - PivotColumns func(childComplexity int) int - PivotFamily func(childComplexity int) int - PivotKind func(childComplexity int) int - ResourceType func(childComplexity int) int - SampleCount func(childComplexity int) int - Selector func(childComplexity int) int - } - - DataframeFieldPredicate struct { - Op func(childComplexity int) int - Path func(childComplexity int) int - Value func(childComplexity int) int - } - - DataframeFieldSelector struct { - SourcePath func(childComplexity int) int - ValuePath func(childComplexity int) int - Where func(childComplexity int) int - } - DataframeMaterialization struct { - ActiveContractVersion func(childComplexity int) int - Availability func(childComplexity int) int - Columns func(childComplexity int) int - Completeness func(childComplexity int) int - CreatedAt func(childComplexity int) int - DatasetGeneration func(childComplexity int) int - Error func(childComplexity int) int - ErrorCode func(childComplexity int) int - ErrorRetryable func(childComplexity int) int - ExpectedProjectCount func(childComplexity int) int - ID func(childComplexity int) int - IncludedProjectCount func(childComplexity int) int - Name func(childComplexity int) int - ProjectID func(childComplexity int) int - ProjectStatuses func(childComplexity int) int - ReadyAt func(childComplexity int) int - Revision func(childComplexity int) int - RowCount func(childComplexity int) int - Selector func(childComplexity int) int - State func(childComplexity int) int + Availability func(childComplexity int) int + Columns func(childComplexity int) int + Completeness func(childComplexity int) int + CreatedAt func(childComplexity int) int + DatasetGeneration func(childComplexity int) int + Error func(childComplexity int) int + ErrorCode func(childComplexity int) int + ErrorRetryable func(childComplexity int) int + ExpectedProjectCount func(childComplexity int) int + ID func(childComplexity int) int + IncludedProjectCount func(childComplexity int) int + Name func(childComplexity int) int + ProjectID func(childComplexity int) int + ProjectStatuses func(childComplexity int) int + ReadyAt func(childComplexity int) int + Revision func(childComplexity int) int + RowCount func(childComplexity int) int + Selector func(childComplexity int) int + State func(childComplexity int) int } DataframeOptimizationDecision struct { @@ -936,19 +887,6 @@ type ComplexityRoot struct { TranslationVersion func(childComplexity int) int } - DataframeRelatedResourceHints struct { - EdgeCount func(childComplexity int) int - Target func(childComplexity int) int - ViaLabel func(childComplexity int) int - } - - DataframeResourceHints struct { - Fields func(childComplexity int) int - PivotFields func(childComplexity int) int - ResourceType func(childComplexity int) int - Traversals func(childComplexity int) int - } - DataframeRichSourceReuse struct { AggregateConsumers func(childComplexity int) int PivotConsumers func(childComplexity int) int @@ -971,13 +909,6 @@ type ComplexityRoot struct { TranslationVersion func(childComplexity int) int } - DataframeTraversalHint struct { - EdgeCount func(childComplexity int) int - FromType func(childComplexity int) int - Label func(childComplexity int) int - ToType func(childComplexity int) int - } - DiagnosticReport struct { BasedOn func(childComplexity int) int Category func(childComplexity int) int @@ -1940,7 +1871,6 @@ type ComplexityRoot struct { ActivateProjectRelease func(childComplexity int, input model.ActivateProjectReleaseInput) int MaterializeDataframeRecipeBundle func(childComplexity int, input model.MaterializeDataframeRecipeInput) int PreviewDataframeRecipe func(childComplexity int, input model.PreviewDataframeRecipeInput) int - PromoteDataframeContract func(childComplexity int, input model.PromoteDataframeContractInput) int RegisterDataframeRecipeRevision func(childComplexity int, input model.RegisterDataframeRecipeRevisionInput) int RunDataframeRecipe func(childComplexity int, input model.RunDataframeRecipeInput) int RunFhirDataframe func(childComplexity int, input model.FhirDataframeInput, limit *int) int @@ -2426,44 +2356,42 @@ type ComplexityRoot struct { } Query struct { - BodyStructure func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - Condition func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - DataframeAggregate func(childComplexity int, input model.DataframeAggregateInput) int - DataframeAggregations func(childComplexity int, input model.DataframeAggregationsInput) int - DataframeBuilderIntrospection func(childComplexity int, input model.DataframeBuilderIntrospectionInput) int - DataframeDataset func(childComplexity int, input model.DataframeDatasetInput) int - DataframeDatasets func(childComplexity int) int - DataframeMaterialization func(childComplexity int, id string) int - DataframeRecipeExecution func(childComplexity int, id string) int - DataframeRecipeRevision func(childComplexity int, projectID string, name string, digest string) int - DataframeRecipeRevisions func(childComplexity int, projectID string, name string) int - DataframeRows func(childComplexity int, input model.DataframeRowsInput) int - DiagnosticReport func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - DocumentReference func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - ExplainDataframeRecipe func(childComplexity int, input model.ExplainDataframeRecipeInput) int - ExplainFhirGraph func(childComplexity int, input model.FhirGraphQueryInput, live *bool) int - FamilyMemberHistory func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - FhirGraph func(childComplexity int, input model.FhirGraphQueryInput) int - Group func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - ImagingStudy func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - Medication func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - MedicationAdministration func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - MedicationRequest func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - MedicationStatement func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - Observation func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - Organization func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - Patient func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - Practitioner func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - PractitionerRole func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - PreflightDataframeRecipe func(childComplexity int, input model.PreflightDataframeRecipeInput) int - Procedure func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - ProjectDataframeDatasets func(childComplexity int, projectID string) int - ResearchStudy func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - ResearchSubject func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - Specimen func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - Substance func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - SubstanceDefinition func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int - Task func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + BodyStructure func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + Condition func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + DataframeAggregate func(childComplexity int, input model.DataframeAggregateInput) int + DataframeAggregations func(childComplexity int, input model.DataframeAggregationsInput) int + DataframeDataset func(childComplexity int, input model.DataframeDatasetInput) int + DataframeDatasets func(childComplexity int) int + DataframeRecipeExecution func(childComplexity int, id string) int + DataframeRecipeRevision func(childComplexity int, projectID string, name string, digest string) int + DataframeRecipeRevisions func(childComplexity int, projectID string, name string) int + DataframeRows func(childComplexity int, input model.DataframeRowsInput) int + DiagnosticReport func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + DocumentReference func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + ExplainDataframeRecipe func(childComplexity int, input model.ExplainDataframeRecipeInput) int + ExplainFhirGraph func(childComplexity int, input model.FhirGraphQueryInput, live *bool) int + FamilyMemberHistory func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + FhirGraph func(childComplexity int, input model.FhirGraphQueryInput) int + Group func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + ImagingStudy func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + Medication func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + MedicationAdministration func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + MedicationRequest func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + MedicationStatement func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + Observation func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + Organization func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + Patient func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + Practitioner func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + PractitionerRole func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + PreflightDataframeRecipe func(childComplexity int, input model.PreflightDataframeRecipeInput) int + Procedure func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + ProjectDataframeDatasets func(childComplexity int, projectID string) int + ResearchStudy func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + ResearchSubject func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + Specimen func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + Substance func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + SubstanceDefinition func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int + Task func(childComplexity int, project string, filters []*model.FhirFilterInput, limit *int) int } Range struct { @@ -5511,55 +5439,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.ComplexityRoot.DataframeAggregationsResult.Materialization(childComplexity), true - case "DataframeBuilderIntrospection.authResourcePaths": - if e.ComplexityRoot.DataframeBuilderIntrospection.AuthResourcePaths == nil { - break - } - - return e.ComplexityRoot.DataframeBuilderIntrospection.AuthResourcePaths(childComplexity), true - case "DataframeBuilderIntrospection.fields": - if e.ComplexityRoot.DataframeBuilderIntrospection.Fields == nil { - break - } - - return e.ComplexityRoot.DataframeBuilderIntrospection.Fields(childComplexity), true - case "DataframeBuilderIntrospection.pivotFields": - if e.ComplexityRoot.DataframeBuilderIntrospection.PivotFields == nil { - break - } - - return e.ComplexityRoot.DataframeBuilderIntrospection.PivotFields(childComplexity), true - case "DataframeBuilderIntrospection.project": - if e.ComplexityRoot.DataframeBuilderIntrospection.Project == nil { - break - } - - return e.ComplexityRoot.DataframeBuilderIntrospection.Project(childComplexity), true - case "DataframeBuilderIntrospection.relatedResources": - if e.ComplexityRoot.DataframeBuilderIntrospection.RelatedResources == nil { - break - } - - return e.ComplexityRoot.DataframeBuilderIntrospection.RelatedResources(childComplexity), true - case "DataframeBuilderIntrospection.root": - if e.ComplexityRoot.DataframeBuilderIntrospection.Root == nil { - break - } - - return e.ComplexityRoot.DataframeBuilderIntrospection.Root(childComplexity), true - case "DataframeBuilderIntrospection.rootResourceType": - if e.ComplexityRoot.DataframeBuilderIntrospection.RootResourceType == nil { - break - } - - return e.ComplexityRoot.DataframeBuilderIntrospection.RootResourceType(childComplexity), true - case "DataframeBuilderIntrospection.traversals": - if e.ComplexityRoot.DataframeBuilderIntrospection.Traversals == nil { - break - } - - return e.ComplexityRoot.DataframeBuilderIntrospection.Traversals(childComplexity), true - case "DataframeColumn.aggregatable": if e.ComplexityRoot.DataframeColumn.Aggregatable == nil { break @@ -5670,166 +5549,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.ComplexityRoot.DataframeCompilerPlanDiagnostics.TraversalSets(childComplexity), true - case "DataframeContract.promotedAt": - if e.ComplexityRoot.DataframeContract.PromotedAt == nil { - break - } - - return e.ComplexityRoot.DataframeContract.PromotedAt(childComplexity), true - case "DataframeContract.recipe": - if e.ComplexityRoot.DataframeContract.Recipe == nil { - break - } - - return e.ComplexityRoot.DataframeContract.Recipe(childComplexity), true - case "DataframeContract.translationVersion": - if e.ComplexityRoot.DataframeContract.TranslationVersion == nil { - break - } - - return e.ComplexityRoot.DataframeContract.TranslationVersion(childComplexity), true - - case "DataframeFieldHint.defaultPivotColumnSelector": - if e.ComplexityRoot.DataframeFieldHint.DefaultPivotColumnSelector == nil { - break - } - - return e.ComplexityRoot.DataframeFieldHint.DefaultPivotColumnSelector(childComplexity), true - case "DataframeFieldHint.defaultPivotValueSelector": - if e.ComplexityRoot.DataframeFieldHint.DefaultPivotValueSelector == nil { - break - } - - return e.ComplexityRoot.DataframeFieldHint.DefaultPivotValueSelector(childComplexity), true - case "DataframeFieldHint.distinctTruncated": - if e.ComplexityRoot.DataframeFieldHint.DistinctTruncated == nil { - break - } - - return e.ComplexityRoot.DataframeFieldHint.DistinctTruncated(childComplexity), true - case "DataframeFieldHint.distinctValues": - if e.ComplexityRoot.DataframeFieldHint.DistinctValues == nil { - break - } - - return e.ComplexityRoot.DataframeFieldHint.DistinctValues(childComplexity), true - case "DataframeFieldHint.docCount": - if e.ComplexityRoot.DataframeFieldHint.DocCount == nil { - break - } - - return e.ComplexityRoot.DataframeFieldHint.DocCount(childComplexity), true - case "DataframeFieldHint.fieldRef": - if e.ComplexityRoot.DataframeFieldHint.FieldRef == nil { - break - } - - return e.ComplexityRoot.DataframeFieldHint.FieldRef(childComplexity), true - case "DataframeFieldHint.kind": - if e.ComplexityRoot.DataframeFieldHint.Kind == nil { - break - } - - return e.ComplexityRoot.DataframeFieldHint.Kind(childComplexity), true - case "DataframeFieldHint.label": - if e.ComplexityRoot.DataframeFieldHint.Label == nil { - break - } - - return e.ComplexityRoot.DataframeFieldHint.Label(childComplexity), true - case "DataframeFieldHint.path": - if e.ComplexityRoot.DataframeFieldHint.Path == nil { - break - } - - return e.ComplexityRoot.DataframeFieldHint.Path(childComplexity), true - case "DataframeFieldHint.pivotCandidate": - if e.ComplexityRoot.DataframeFieldHint.PivotCandidate == nil { - break - } - - return e.ComplexityRoot.DataframeFieldHint.PivotCandidate(childComplexity), true - case "DataframeFieldHint.pivotColumns": - if e.ComplexityRoot.DataframeFieldHint.PivotColumns == nil { - break - } - - return e.ComplexityRoot.DataframeFieldHint.PivotColumns(childComplexity), true - case "DataframeFieldHint.pivotFamily": - if e.ComplexityRoot.DataframeFieldHint.PivotFamily == nil { - break - } - - return e.ComplexityRoot.DataframeFieldHint.PivotFamily(childComplexity), true - case "DataframeFieldHint.pivotKind": - if e.ComplexityRoot.DataframeFieldHint.PivotKind == nil { - break - } - - return e.ComplexityRoot.DataframeFieldHint.PivotKind(childComplexity), true - case "DataframeFieldHint.resourceType": - if e.ComplexityRoot.DataframeFieldHint.ResourceType == nil { - break - } - - return e.ComplexityRoot.DataframeFieldHint.ResourceType(childComplexity), true - case "DataframeFieldHint.sampleCount": - if e.ComplexityRoot.DataframeFieldHint.SampleCount == nil { - break - } - - return e.ComplexityRoot.DataframeFieldHint.SampleCount(childComplexity), true - case "DataframeFieldHint.selector": - if e.ComplexityRoot.DataframeFieldHint.Selector == nil { - break - } - - return e.ComplexityRoot.DataframeFieldHint.Selector(childComplexity), true - - case "DataframeFieldPredicate.op": - if e.ComplexityRoot.DataframeFieldPredicate.Op == nil { - break - } - - return e.ComplexityRoot.DataframeFieldPredicate.Op(childComplexity), true - case "DataframeFieldPredicate.path": - if e.ComplexityRoot.DataframeFieldPredicate.Path == nil { - break - } - - return e.ComplexityRoot.DataframeFieldPredicate.Path(childComplexity), true - case "DataframeFieldPredicate.value": - if e.ComplexityRoot.DataframeFieldPredicate.Value == nil { - break - } - - return e.ComplexityRoot.DataframeFieldPredicate.Value(childComplexity), true - - case "DataframeFieldSelector.sourcePath": - if e.ComplexityRoot.DataframeFieldSelector.SourcePath == nil { - break - } - - return e.ComplexityRoot.DataframeFieldSelector.SourcePath(childComplexity), true - case "DataframeFieldSelector.valuePath": - if e.ComplexityRoot.DataframeFieldSelector.ValuePath == nil { - break - } - - return e.ComplexityRoot.DataframeFieldSelector.ValuePath(childComplexity), true - case "DataframeFieldSelector.where": - if e.ComplexityRoot.DataframeFieldSelector.Where == nil { - break - } - - return e.ComplexityRoot.DataframeFieldSelector.Where(childComplexity), true - - case "DataframeMaterialization.activeContractVersion": - if e.ComplexityRoot.DataframeMaterialization.ActiveContractVersion == nil { - break - } - - return e.ComplexityRoot.DataframeMaterialization.ActiveContractVersion(childComplexity), true case "DataframeMaterialization.availability": if e.ComplexityRoot.DataframeMaterialization.Availability == nil { break @@ -6972,50 +6691,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.ComplexityRoot.DataframeRecipeValidation.TranslationVersion(childComplexity), true - case "DataframeRelatedResourceHints.edgeCount": - if e.ComplexityRoot.DataframeRelatedResourceHints.EdgeCount == nil { - break - } - - return e.ComplexityRoot.DataframeRelatedResourceHints.EdgeCount(childComplexity), true - case "DataframeRelatedResourceHints.target": - if e.ComplexityRoot.DataframeRelatedResourceHints.Target == nil { - break - } - - return e.ComplexityRoot.DataframeRelatedResourceHints.Target(childComplexity), true - case "DataframeRelatedResourceHints.viaLabel": - if e.ComplexityRoot.DataframeRelatedResourceHints.ViaLabel == nil { - break - } - - return e.ComplexityRoot.DataframeRelatedResourceHints.ViaLabel(childComplexity), true - - case "DataframeResourceHints.fields": - if e.ComplexityRoot.DataframeResourceHints.Fields == nil { - break - } - - return e.ComplexityRoot.DataframeResourceHints.Fields(childComplexity), true - case "DataframeResourceHints.pivotFields": - if e.ComplexityRoot.DataframeResourceHints.PivotFields == nil { - break - } - - return e.ComplexityRoot.DataframeResourceHints.PivotFields(childComplexity), true - case "DataframeResourceHints.resourceType": - if e.ComplexityRoot.DataframeResourceHints.ResourceType == nil { - break - } - - return e.ComplexityRoot.DataframeResourceHints.ResourceType(childComplexity), true - case "DataframeResourceHints.traversals": - if e.ComplexityRoot.DataframeResourceHints.Traversals == nil { - break - } - - return e.ComplexityRoot.DataframeResourceHints.Traversals(childComplexity), true - case "DataframeRichSourceReuse.aggregateConsumers": if e.ComplexityRoot.DataframeRichSourceReuse.AggregateConsumers == nil { break @@ -7097,31 +6772,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.ComplexityRoot.DataframeSelector.TranslationVersion(childComplexity), true - case "DataframeTraversalHint.edgeCount": - if e.ComplexityRoot.DataframeTraversalHint.EdgeCount == nil { - break - } - - return e.ComplexityRoot.DataframeTraversalHint.EdgeCount(childComplexity), true - case "DataframeTraversalHint.fromType": - if e.ComplexityRoot.DataframeTraversalHint.FromType == nil { - break - } - - return e.ComplexityRoot.DataframeTraversalHint.FromType(childComplexity), true - case "DataframeTraversalHint.label": - if e.ComplexityRoot.DataframeTraversalHint.Label == nil { - break - } - - return e.ComplexityRoot.DataframeTraversalHint.Label(childComplexity), true - case "DataframeTraversalHint.toType": - if e.ComplexityRoot.DataframeTraversalHint.ToType == nil { - break - } - - return e.ComplexityRoot.DataframeTraversalHint.ToType(childComplexity), true - case "DiagnosticReport.basedOn": if e.ComplexityRoot.DiagnosticReport.BasedOn == nil { break @@ -12036,17 +11686,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.ComplexityRoot.Mutation.PreviewDataframeRecipe(childComplexity, args["input"].(model.PreviewDataframeRecipeInput)), true - case "Mutation.promoteDataframeContract": - if e.ComplexityRoot.Mutation.PromoteDataframeContract == nil { - break - } - - args, err := ec.field_Mutation_promoteDataframeContract_args(ctx, rawArgs) - if err != nil { - return 0, false - } - - return e.ComplexityRoot.Mutation.PromoteDataframeContract(childComplexity, args["input"].(model.PromoteDataframeContractInput)), true case "Mutation.registerDataframeRecipeRevision": if e.ComplexityRoot.Mutation.RegisterDataframeRecipeRevision == nil { break @@ -14635,17 +14274,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.ComplexityRoot.Query.DataframeAggregations(childComplexity, args["input"].(model.DataframeAggregationsInput)), true - case "Query.dataframeBuilderIntrospection": - if e.ComplexityRoot.Query.DataframeBuilderIntrospection == nil { - break - } - - args, err := ec.field_Query_dataframeBuilderIntrospection_args(ctx, rawArgs) - if err != nil { - return 0, false - } - - return e.ComplexityRoot.Query.DataframeBuilderIntrospection(childComplexity, args["input"].(model.DataframeBuilderIntrospectionInput)), true case "Query.dataframeDataset": if e.ComplexityRoot.Query.DataframeDataset == nil { break @@ -14663,17 +14291,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.ComplexityRoot.Query.DataframeDatasets(childComplexity), true - case "Query.dataframeMaterialization": - if e.ComplexityRoot.Query.DataframeMaterialization == nil { - break - } - - args, err := ec.field_Query_dataframeMaterialization_args(ctx, rawArgs) - if err != nil { - return 0, false - } - - return e.ComplexityRoot.Query.DataframeMaterialization(childComplexity, args["id"].(string)), true case "Query.dataframeRecipeExecution": if e.ComplexityRoot.Query.DataframeRecipeExecution == nil { break @@ -20163,7 +19780,6 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputDataframeAggregateInput, ec.unmarshalInputDataframeAggregationSpecInput, ec.unmarshalInputDataframeAggregationsInput, - ec.unmarshalInputDataframeBuilderIntrospectionInput, ec.unmarshalInputDataframeDatasetInput, ec.unmarshalInputDataframeFilterInput, ec.unmarshalInputDataframeRecipeBindingsInput, @@ -20189,7 +19805,6 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputMaterializeDataframeRecipeInput, ec.unmarshalInputPreflightDataframeRecipeInput, ec.unmarshalInputPreviewDataframeRecipeInput, - ec.unmarshalInputPromoteDataframeContractInput, ec.unmarshalInputRegisterDataframeRecipeRevisionInput, ec.unmarshalInputRunDataframeRecipeInput, ec.unmarshalInputStartDataframeMaterializationInput, @@ -20270,11 +19885,6 @@ func newExecutionContext( var sources = []*ast.Source{ {Name: "../../../../internal/api/graphql/graph/schema/schema.graphqls", Input: `type Query { - dataframeBuilderIntrospection( - input: DataframeBuilderIntrospectionInput! - ): DataframeBuilderIntrospection! - - dataframeMaterialization(id: ID!): DataframeMaterialization dataframeDatasets: [DataframeMaterialization!]! projectDataframeDatasets(projectId: String!): [DataframeMaterialization!]! dataframeDataset(input: DataframeDatasetInput!): DataframeMaterialization @@ -20303,7 +19913,6 @@ type Mutation { materializeDataframeRecipeBundle(input: MaterializeDataframeRecipeInput!): DataframeRecipeExecution! startDataframeMaterialization(input: StartDataframeMaterializationInput!): DataframeRecipeExecution! activateProjectRelease(input: ActivateProjectReleaseInput!): ProjectRelease! - promoteDataframeContract(input: PromoteDataframeContractInput!): DataframeContract! registerDataframeRecipeRevision(input: RegisterDataframeRecipeRevisionInput!): DataframeRecipeRevision! } @@ -20329,17 +19938,6 @@ type ProjectRelease { enum ProjectReleaseState { ACTIVE } -input PromoteDataframeContractInput { - recipe: String! - translationVersion: String! -} - -type DataframeContract { - recipe: String! - translationVersion: String! - promotedAt: String! -} - input RegisterDataframeRecipeRevisionInput { projectId: String! name: String! @@ -20648,7 +20246,6 @@ type DataframeMaterialization { errorCode: String errorRetryable: Boolean selector: DataframeSelector - activeContractVersion: String availability: DataframeAvailability completeness: Float includedProjectCount: Int @@ -20695,8 +20292,7 @@ type DataframeProjectStatus { } input DataframeDatasetInput { - selector: DataframeSelectorInput - dataType: String @deprecated(reason: "Use selector") + selector: DataframeSelectorInput! } input DataframeFilterInput { @@ -20711,11 +20307,7 @@ input DataframeSortInput { } input DataframeRowsInput { - # Legacy callers may target one published physical materialization directly. - # When omitted, the request uses the project-federated dataframe. - materializationId: ID - selector: DataframeSelectorInput - dataType: String @deprecated(reason: "Use selector") + selector: DataframeSelectorInput! columns: [String!] filters: [DataframeFilterInput!] sort: DataframeSortInput @@ -20737,11 +20329,7 @@ type DataframeRowConnection { } input DataframeAggregateInput { - # Legacy callers may target one published physical materialization directly. - # When omitted, the request uses the project-federated dataframe. - materializationId: ID - selector: DataframeSelectorInput - dataType: String @deprecated(reason: "Use selector") + selector: DataframeSelectorInput! groupBy: [String!] filters: [DataframeFilterInput!] operation: String! @@ -20765,8 +20353,7 @@ input DataframeAggregationSpecInput { } input DataframeAggregationsInput { - selector: DataframeSelectorInput - dataType: String @deprecated(reason: "Use selector") + selector: DataframeSelectorInput! filters: [DataframeFilterInput!] specs: [DataframeAggregationSpecInput!]! } @@ -20776,80 +20363,6 @@ type DataframeAggregationsResult { aggregations: JSON! } -input DataframeBuilderIntrospectionInput { - project: String! - rootResourceType: String! - authResourcePaths: [String!] - includePivotOnlyFields: Boolean = true -} - -type DataframeBuilderIntrospection { - project: String! - rootResourceType: String! - authResourcePaths: [String!]! - root: DataframeResourceHints! - relatedResources: [DataframeRelatedResourceHints!]! - traversals: [DataframeTraversalHint!]! - fields: [DataframeFieldHint!]! - pivotFields: [DataframeFieldHint!]! -} - -type DataframeResourceHints { - resourceType: String! - fields: [DataframeFieldHint!]! - pivotFields: [DataframeFieldHint!]! - traversals: [DataframeTraversalHint!]! -} - -type DataframeRelatedResourceHints { - viaLabel: String! - edgeCount: Int! - target: DataframeResourceHints! -} - -type DataframeTraversalHint { - fromType: String! - label: String! - toType: String! - edgeCount: Int! -} - -type DataframeFieldHint { - resourceType: String! - fieldRef: String! - label: String! - path: String! - selector: DataframeFieldSelector! - kind: String! - docCount: Int! - sampleCount: Int! - distinctValues: [String!]! - distinctTruncated: Boolean! - pivotCandidate: Boolean! - pivotKind: String - pivotColumns: [String!]! - pivotFamily: FhirPivotFamily - defaultPivotColumnSelector: DataframeFieldSelector - defaultPivotValueSelector: DataframeFieldSelector -} - -type DataframeFieldSelector { - sourcePath: String - where: DataframeFieldPredicate - valuePath: String! -} - -type DataframeFieldPredicate { - path: String! - op: FhirFieldPredicateOperation! - value: String! -} - -enum FhirPivotFamily { - CODEABLE_CONCEPT - OBSERVATION_CODE_VALUE -} - input FhirFieldSelectInput { name: String! fieldRef: String @@ -24836,28 +24349,6 @@ func (ec *executionContext) childFields_DataframeAggregationsResult(ctx context. return nil, fmt.Errorf("no field named %q was found under type DataframeAggregationsResult", field.Name) } -func (ec *executionContext) childFields_DataframeBuilderIntrospection(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "project": - return ec.fieldContext_DataframeBuilderIntrospection_project(ctx, field) - case "rootResourceType": - return ec.fieldContext_DataframeBuilderIntrospection_rootResourceType(ctx, field) - case "authResourcePaths": - return ec.fieldContext_DataframeBuilderIntrospection_authResourcePaths(ctx, field) - case "root": - return ec.fieldContext_DataframeBuilderIntrospection_root(ctx, field) - case "relatedResources": - return ec.fieldContext_DataframeBuilderIntrospection_relatedResources(ctx, field) - case "traversals": - return ec.fieldContext_DataframeBuilderIntrospection_traversals(ctx, field) - case "fields": - return ec.fieldContext_DataframeBuilderIntrospection_fields(ctx, field) - case "pivotFields": - return ec.fieldContext_DataframeBuilderIntrospection_pivotFields(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type DataframeBuilderIntrospection", field.Name) -} - func (ec *executionContext) childFields_DataframeColumn(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "semanticPath": @@ -24906,80 +24397,6 @@ func (ec *executionContext) childFields_DataframeCompilerPlanDiagnostics(ctx con return nil, fmt.Errorf("no field named %q was found under type DataframeCompilerPlanDiagnostics", field.Name) } -func (ec *executionContext) childFields_DataframeContract(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "recipe": - return ec.fieldContext_DataframeContract_recipe(ctx, field) - case "translationVersion": - return ec.fieldContext_DataframeContract_translationVersion(ctx, field) - case "promotedAt": - return ec.fieldContext_DataframeContract_promotedAt(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type DataframeContract", field.Name) -} - -func (ec *executionContext) childFields_DataframeFieldHint(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "resourceType": - return ec.fieldContext_DataframeFieldHint_resourceType(ctx, field) - case "fieldRef": - return ec.fieldContext_DataframeFieldHint_fieldRef(ctx, field) - case "label": - return ec.fieldContext_DataframeFieldHint_label(ctx, field) - case "path": - return ec.fieldContext_DataframeFieldHint_path(ctx, field) - case "selector": - return ec.fieldContext_DataframeFieldHint_selector(ctx, field) - case "kind": - return ec.fieldContext_DataframeFieldHint_kind(ctx, field) - case "docCount": - return ec.fieldContext_DataframeFieldHint_docCount(ctx, field) - case "sampleCount": - return ec.fieldContext_DataframeFieldHint_sampleCount(ctx, field) - case "distinctValues": - return ec.fieldContext_DataframeFieldHint_distinctValues(ctx, field) - case "distinctTruncated": - return ec.fieldContext_DataframeFieldHint_distinctTruncated(ctx, field) - case "pivotCandidate": - return ec.fieldContext_DataframeFieldHint_pivotCandidate(ctx, field) - case "pivotKind": - return ec.fieldContext_DataframeFieldHint_pivotKind(ctx, field) - case "pivotColumns": - return ec.fieldContext_DataframeFieldHint_pivotColumns(ctx, field) - case "pivotFamily": - return ec.fieldContext_DataframeFieldHint_pivotFamily(ctx, field) - case "defaultPivotColumnSelector": - return ec.fieldContext_DataframeFieldHint_defaultPivotColumnSelector(ctx, field) - case "defaultPivotValueSelector": - return ec.fieldContext_DataframeFieldHint_defaultPivotValueSelector(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type DataframeFieldHint", field.Name) -} - -func (ec *executionContext) childFields_DataframeFieldPredicate(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "path": - return ec.fieldContext_DataframeFieldPredicate_path(ctx, field) - case "op": - return ec.fieldContext_DataframeFieldPredicate_op(ctx, field) - case "value": - return ec.fieldContext_DataframeFieldPredicate_value(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type DataframeFieldPredicate", field.Name) -} - -func (ec *executionContext) childFields_DataframeFieldSelector(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "sourcePath": - return ec.fieldContext_DataframeFieldSelector_sourcePath(ctx, field) - case "where": - return ec.fieldContext_DataframeFieldSelector_where(ctx, field) - case "valuePath": - return ec.fieldContext_DataframeFieldSelector_valuePath(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type DataframeFieldSelector", field.Name) -} - func (ec *executionContext) childFields_DataframeMaterialization(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": @@ -25010,8 +24427,6 @@ func (ec *executionContext) childFields_DataframeMaterialization(ctx context.Con return ec.fieldContext_DataframeMaterialization_errorRetryable(ctx, field) case "selector": return ec.fieldContext_DataframeMaterialization_selector(ctx, field) - case "activeContractVersion": - return ec.fieldContext_DataframeMaterialization_activeContractVersion(ctx, field) case "availability": return ec.fieldContext_DataframeMaterialization_availability(ctx, field) case "completeness": @@ -25544,32 +24959,6 @@ func (ec *executionContext) childFields_DataframeRecipeValidation(ctx context.Co return nil, fmt.Errorf("no field named %q was found under type DataframeRecipeValidation", field.Name) } -func (ec *executionContext) childFields_DataframeRelatedResourceHints(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "viaLabel": - return ec.fieldContext_DataframeRelatedResourceHints_viaLabel(ctx, field) - case "edgeCount": - return ec.fieldContext_DataframeRelatedResourceHints_edgeCount(ctx, field) - case "target": - return ec.fieldContext_DataframeRelatedResourceHints_target(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type DataframeRelatedResourceHints", field.Name) -} - -func (ec *executionContext) childFields_DataframeResourceHints(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "resourceType": - return ec.fieldContext_DataframeResourceHints_resourceType(ctx, field) - case "fields": - return ec.fieldContext_DataframeResourceHints_fields(ctx, field) - case "pivotFields": - return ec.fieldContext_DataframeResourceHints_pivotFields(ctx, field) - case "traversals": - return ec.fieldContext_DataframeResourceHints_traversals(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type DataframeResourceHints", field.Name) -} - func (ec *executionContext) childFields_DataframeRichSourceReuse(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "sourceSet": @@ -25614,20 +25003,6 @@ func (ec *executionContext) childFields_DataframeSelector(ctx context.Context, f return nil, fmt.Errorf("no field named %q was found under type DataframeSelector", field.Name) } -func (ec *executionContext) childFields_DataframeTraversalHint(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "fromType": - return ec.fieldContext_DataframeTraversalHint_fromType(ctx, field) - case "label": - return ec.fieldContext_DataframeTraversalHint_label(ctx, field) - case "toType": - return ec.fieldContext_DataframeTraversalHint_toType(ctx, field) - case "edgeCount": - return ec.fieldContext_DataframeTraversalHint_edgeCount(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type DataframeTraversalHint", field.Name) -} - func (ec *executionContext) childFields_DiagnosticReport(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "_conclusion": diff --git a/generated/graphql/graph/executor/schema.generated.go b/generated/graphql/graph/executor/schema.generated.go index 88f737cd..3362e1e1 100644 --- a/generated/graphql/graph/executor/schema.generated.go +++ b/generated/graphql/graph/executor/schema.generated.go @@ -27,12 +27,9 @@ type MutationResolver interface { MaterializeDataframeRecipeBundle(ctx context.Context, input model.MaterializeDataframeRecipeInput) (*model.DataframeRecipeExecution, error) StartDataframeMaterialization(ctx context.Context, input model.StartDataframeMaterializationInput) (*model.DataframeRecipeExecution, error) ActivateProjectRelease(ctx context.Context, input model.ActivateProjectReleaseInput) (*model.ProjectRelease, error) - PromoteDataframeContract(ctx context.Context, input model.PromoteDataframeContractInput) (*model.DataframeContract, error) RegisterDataframeRecipeRevision(ctx context.Context, input model.RegisterDataframeRecipeRevisionInput) (*model.DataframeRecipeRevision, error) } type QueryResolver interface { - DataframeBuilderIntrospection(ctx context.Context, input model.DataframeBuilderIntrospectionInput) (*model.DataframeBuilderIntrospection, error) - DataframeMaterialization(ctx context.Context, id string) (*model.DataframeMaterialization, error) DataframeDatasets(ctx context.Context) ([]*model.DataframeMaterialization, error) ProjectDataframeDatasets(ctx context.Context, projectID string) ([]*model.DataframeMaterialization, error) DataframeDataset(ctx context.Context, input model.DataframeDatasetInput) (*model.DataframeMaterialization, error) @@ -117,20 +114,6 @@ func (ec *executionContext) field_Mutation_previewDataframeRecipe_args(ctx conte return args, nil } -func (ec *executionContext) field_Mutation_promoteDataframeContract_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { - var err error - args := map[string]any{} - arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", - func(ctx context.Context, v any) (model.PromoteDataframeContractInput, error) { - return ec.unmarshalNPromoteDataframeContractInput2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐPromoteDataframeContractInput(ctx, v) - }) - if err != nil { - return nil, err - } - args["input"] = arg0 - return args, nil -} - func (ec *executionContext) field_Mutation_registerDataframeRecipeRevision_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -941,20 +924,6 @@ func (ec *executionContext) field_Query_dataframeAggregations_args(ctx context.C return args, nil } -func (ec *executionContext) field_Query_dataframeBuilderIntrospection_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { - var err error - args := map[string]any{} - arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", - func(ctx context.Context, v any) (model.DataframeBuilderIntrospectionInput, error) { - return ec.unmarshalNDataframeBuilderIntrospectionInput2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeBuilderIntrospectionInput(ctx, v) - }) - if err != nil { - return nil, err - } - args["input"] = arg0 - return args, nil -} - func (ec *executionContext) field_Query_dataframeDataset_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -969,20 +938,6 @@ func (ec *executionContext) field_Query_dataframeDataset_args(ctx context.Contex return args, nil } -func (ec *executionContext) field_Query_dataframeMaterialization_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { - var err error - args := map[string]any{} - arg0, err := graphql.ProcessArgField(ctx, rawArgs, "id", - func(ctx context.Context, v any) (string, error) { - return ec.unmarshalNID2string(ctx, v) - }) - if err != nil { - return nil, err - } - args["id"] = arg0 - return args, nil -} - func (ec *executionContext) field_Query_dataframeRecipeExecution_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -1278,235 +1233,6 @@ func (ec *executionContext) fieldContext_DataframeAggregationsResult_aggregation return graphql.NewScalarFieldContext("DataframeAggregationsResult", field, false, false, errors.New("field of type JSON does not have child fields")) } -func (ec *executionContext) _DataframeBuilderIntrospection_project(ctx context.Context, field graphql.CollectedField, obj *model.DataframeBuilderIntrospection) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeBuilderIntrospection_project(ctx, field) - }, - func(ctx context.Context) (any, error) { - return obj.Project, nil - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_DataframeBuilderIntrospection_project(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeBuilderIntrospection", field, false, false, errors.New("field of type String does not have child fields")) -} - -func (ec *executionContext) _DataframeBuilderIntrospection_rootResourceType(ctx context.Context, field graphql.CollectedField, obj *model.DataframeBuilderIntrospection) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeBuilderIntrospection_rootResourceType(ctx, field) - }, - func(ctx context.Context) (any, error) { - return obj.RootResourceType, nil - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_DataframeBuilderIntrospection_rootResourceType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeBuilderIntrospection", field, false, false, errors.New("field of type String does not have child fields")) -} - -func (ec *executionContext) _DataframeBuilderIntrospection_authResourcePaths(ctx context.Context, field graphql.CollectedField, obj *model.DataframeBuilderIntrospection) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeBuilderIntrospection_authResourcePaths(ctx, field) - }, - func(ctx context.Context) (any, error) { - return obj.AuthResourcePaths, nil - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { - return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_DataframeBuilderIntrospection_authResourcePaths(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeBuilderIntrospection", field, false, false, errors.New("field of type String does not have child fields")) -} - -func (ec *executionContext) _DataframeBuilderIntrospection_root(ctx context.Context, field graphql.CollectedField, obj *model.DataframeBuilderIntrospection) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeBuilderIntrospection_root(ctx, field) - }, - func(ctx context.Context) (any, error) { - return obj.Root, nil - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeResourceHints) graphql.Marshaler { - return ec.marshalNDataframeResourceHints2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeResourceHints(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_DataframeBuilderIntrospection_root(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeBuilderIntrospection", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeResourceHints(ctx, field) - }, - } - return fc, nil -} - -func (ec *executionContext) _DataframeBuilderIntrospection_relatedResources(ctx context.Context, field graphql.CollectedField, obj *model.DataframeBuilderIntrospection) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeBuilderIntrospection_relatedResources(ctx, field) - }, - func(ctx context.Context) (any, error) { - return obj.RelatedResources, nil - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRelatedResourceHints) graphql.Marshaler { - return ec.marshalNDataframeRelatedResourceHints2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRelatedResourceHintsᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_DataframeBuilderIntrospection_relatedResources(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeBuilderIntrospection", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRelatedResourceHints(ctx, field) - }, - } - return fc, nil -} - -func (ec *executionContext) _DataframeBuilderIntrospection_traversals(ctx context.Context, field graphql.CollectedField, obj *model.DataframeBuilderIntrospection) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeBuilderIntrospection_traversals(ctx, field) - }, - func(ctx context.Context) (any, error) { - return obj.Traversals, nil - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeTraversalHint) graphql.Marshaler { - return ec.marshalNDataframeTraversalHint2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeTraversalHintᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_DataframeBuilderIntrospection_traversals(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeBuilderIntrospection", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeTraversalHint(ctx, field) - }, - } - return fc, nil -} - -func (ec *executionContext) _DataframeBuilderIntrospection_fields(ctx context.Context, field graphql.CollectedField, obj *model.DataframeBuilderIntrospection) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeBuilderIntrospection_fields(ctx, field) - }, - func(ctx context.Context) (any, error) { - return obj.Fields, nil - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeFieldHint) graphql.Marshaler { - return ec.marshalNDataframeFieldHint2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeFieldHintᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_DataframeBuilderIntrospection_fields(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeBuilderIntrospection", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeFieldHint(ctx, field) - }, - } - return fc, nil -} - -func (ec *executionContext) _DataframeBuilderIntrospection_pivotFields(ctx context.Context, field graphql.CollectedField, obj *model.DataframeBuilderIntrospection) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeBuilderIntrospection_pivotFields(ctx, field) - }, - func(ctx context.Context) (any, error) { - return obj.PivotFields, nil - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeFieldHint) graphql.Marshaler { - return ec.marshalNDataframeFieldHint2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeFieldHintᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_DataframeBuilderIntrospection_pivotFields(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeBuilderIntrospection", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeFieldHint(ctx, field) - }, - } - return fc, nil -} - func (ec *executionContext) _DataframeColumn_semanticPath(ctx context.Context, field graphql.CollectedField, obj *model.DataframeColumn) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -1939,39 +1665,39 @@ func (ec *executionContext) fieldContext_DataframeCompilerPlanDiagnostics_richSo return fc, nil } -func (ec *executionContext) _DataframeContract_recipe(ctx context.Context, field graphql.CollectedField, obj *model.DataframeContract) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_id(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeContract_recipe(ctx, field) + return ec.fieldContext_DataframeMaterialization_id(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Recipe, nil + return obj.ID, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + return ec.marshalNID2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeContract_recipe(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeContract", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeMaterialization_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type ID does not have child fields")) } -func (ec *executionContext) _DataframeContract_translationVersion(ctx context.Context, field graphql.CollectedField, obj *model.DataframeContract) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeContract_translationVersion(ctx, field) + return ec.fieldContext_DataframeMaterialization_name(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.TranslationVersion, nil + return obj.Name, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -1981,20 +1707,20 @@ func (ec *executionContext) _DataframeContract_translationVersion(ctx context.Co true, ) } -func (ec *executionContext) fieldContext_DataframeContract_translationVersion(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeContract", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeMaterialization_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeContract_promotedAt(ctx context.Context, field graphql.CollectedField, obj *model.DataframeContract) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_revision(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeContract_promotedAt(ctx, field) + return ec.fieldContext_DataframeMaterialization_revision(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.PromotedAt, nil + return obj.Revision, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -2004,20 +1730,20 @@ func (ec *executionContext) _DataframeContract_promotedAt(ctx context.Context, f true, ) } -func (ec *executionContext) fieldContext_DataframeContract_promotedAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeContract", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeMaterialization_revision(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeFieldHint_resourceType(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldHint) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_projectId(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldHint_resourceType(ctx, field) + return ec.fieldContext_DataframeMaterialization_projectId(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ResourceType, nil + return obj.ProjectID, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -2027,20 +1753,20 @@ func (ec *executionContext) _DataframeFieldHint_resourceType(ctx context.Context true, ) } -func (ec *executionContext) fieldContext_DataframeFieldHint_resourceType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeFieldHint", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeMaterialization_projectId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeFieldHint_fieldRef(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldHint) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_datasetGeneration(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldHint_fieldRef(ctx, field) + return ec.fieldContext_DataframeMaterialization_datasetGeneration(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.FieldRef, nil + return obj.DatasetGeneration, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -2050,98 +1776,98 @@ func (ec *executionContext) _DataframeFieldHint_fieldRef(ctx context.Context, fi true, ) } -func (ec *executionContext) fieldContext_DataframeFieldHint_fieldRef(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeFieldHint", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeMaterialization_datasetGeneration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeFieldHint_label(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldHint) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_state(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldHint_label(ctx, field) + return ec.fieldContext_DataframeMaterialization_state(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Label, nil + return obj.State, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v model.DataframeMaterializationState) graphql.Marshaler { + return ec.marshalNDataframeMaterializationState2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeMaterializationState(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeFieldHint_label(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeFieldHint", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeMaterialization_state(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type DataframeMaterializationState does not have child fields")) } -func (ec *executionContext) _DataframeFieldHint_path(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldHint) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_columns(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldHint_path(ctx, field) + return ec.fieldContext_DataframeMaterialization_columns(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Path, nil + return obj.Columns, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeColumn) graphql.Marshaler { + return ec.marshalNDataframeColumn2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeColumnᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeFieldHint_path(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeFieldHint", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeMaterialization_columns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DataframeMaterialization", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeColumn(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeFieldHint_selector(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldHint) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_rowCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldHint_selector(ctx, field) + return ec.fieldContext_DataframeMaterialization_rowCount(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Selector, nil + return obj.RowCount, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeFieldSelector) graphql.Marshaler { - return ec.marshalNDataframeFieldSelector2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeFieldSelector(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *int) graphql.Marshaler { + return ec.marshalOInt2ᚖint(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeFieldHint_selector(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeFieldHint", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeFieldSelector(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_DataframeMaterialization_rowCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeFieldHint_kind(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldHint) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_createdAt(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldHint_kind(ctx, field) + return ec.fieldContext_DataframeMaterialization_createdAt(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Kind, nil + return obj.CreatedAt, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -2151,268 +1877,268 @@ func (ec *executionContext) _DataframeFieldHint_kind(ctx context.Context, field true, ) } -func (ec *executionContext) fieldContext_DataframeFieldHint_kind(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeFieldHint", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeMaterialization_createdAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeFieldHint_docCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldHint) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_readyAt(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldHint_docCount(ctx, field) + return ec.fieldContext_DataframeMaterialization_readyAt(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.DocCount, nil + return obj.ReadyAt, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { + return ec.marshalOString2ᚖstring(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeFieldHint_docCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeFieldHint", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeMaterialization_readyAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeFieldHint_sampleCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldHint) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_error(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldHint_sampleCount(ctx, field) + return ec.fieldContext_DataframeMaterialization_error(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.SampleCount, nil + return obj.Error, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { + return ec.marshalOString2ᚖstring(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeFieldHint_sampleCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeFieldHint", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeMaterialization_error(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeFieldHint_distinctValues(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldHint) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_errorCode(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldHint_distinctValues(ctx, field) + return ec.fieldContext_DataframeMaterialization_errorCode(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.DistinctValues, nil + return obj.ErrorCode, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { - return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { + return ec.marshalOString2ᚖstring(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeFieldHint_distinctValues(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeFieldHint", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeMaterialization_errorCode(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeFieldHint_distinctTruncated(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldHint) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_errorRetryable(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldHint_distinctTruncated(ctx, field) + return ec.fieldContext_DataframeMaterialization_errorRetryable(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.DistinctTruncated, nil + return obj.ErrorRetryable, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { - return ec.marshalNBoolean2bool(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *bool) graphql.Marshaler { + return ec.marshalOBoolean2ᚖbool(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeFieldHint_distinctTruncated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeFieldHint", field, false, false, errors.New("field of type Boolean does not have child fields")) +func (ec *executionContext) fieldContext_DataframeMaterialization_errorRetryable(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type Boolean does not have child fields")) } -func (ec *executionContext) _DataframeFieldHint_pivotCandidate(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldHint) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_selector(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldHint_pivotCandidate(ctx, field) + return ec.fieldContext_DataframeMaterialization_selector(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.PivotCandidate, nil + return obj.Selector, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { - return ec.marshalNBoolean2bool(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeSelector) graphql.Marshaler { + return ec.marshalODataframeSelector2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeSelector(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeFieldHint_pivotCandidate(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeFieldHint", field, false, false, errors.New("field of type Boolean does not have child fields")) +func (ec *executionContext) fieldContext_DataframeMaterialization_selector(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DataframeMaterialization", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeSelector(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeFieldHint_pivotKind(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldHint) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_availability(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldHint_pivotKind(ctx, field) + return ec.fieldContext_DataframeMaterialization_availability(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.PivotKind, nil + return obj.Availability, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeAvailability) graphql.Marshaler { + return ec.marshalODataframeAvailability2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeAvailability(ctx, selections, v) }, true, false, ) } -func (ec *executionContext) fieldContext_DataframeFieldHint_pivotKind(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeFieldHint", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeMaterialization_availability(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type DataframeAvailability does not have child fields")) } -func (ec *executionContext) _DataframeFieldHint_pivotColumns(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldHint) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_completeness(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldHint_pivotColumns(ctx, field) + return ec.fieldContext_DataframeMaterialization_completeness(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.PivotColumns, nil + return obj.Completeness, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { - return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *float64) graphql.Marshaler { + return ec.marshalOFloat2ᚖfloat64(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeFieldHint_pivotColumns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeFieldHint", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeMaterialization_completeness(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type Float does not have child fields")) } -func (ec *executionContext) _DataframeFieldHint_pivotFamily(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldHint) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_includedProjectCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldHint_pivotFamily(ctx, field) + return ec.fieldContext_DataframeMaterialization_includedProjectCount(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.PivotFamily, nil + return obj.IncludedProjectCount, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.FhirPivotFamily) graphql.Marshaler { - return ec.marshalOFhirPivotFamily2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirPivotFamily(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *int) graphql.Marshaler { + return ec.marshalOInt2ᚖint(ctx, selections, v) }, true, false, ) } -func (ec *executionContext) fieldContext_DataframeFieldHint_pivotFamily(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeFieldHint", field, false, false, errors.New("field of type FhirPivotFamily does not have child fields")) +func (ec *executionContext) fieldContext_DataframeMaterialization_includedProjectCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeFieldHint_defaultPivotColumnSelector(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldHint) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_expectedProjectCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldHint_defaultPivotColumnSelector(ctx, field) + return ec.fieldContext_DataframeMaterialization_expectedProjectCount(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.DefaultPivotColumnSelector, nil + return obj.ExpectedProjectCount, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeFieldSelector) graphql.Marshaler { - return ec.marshalODataframeFieldSelector2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeFieldSelector(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *int) graphql.Marshaler { + return ec.marshalOInt2ᚖint(ctx, selections, v) }, true, false, ) } -func (ec *executionContext) fieldContext_DataframeFieldHint_defaultPivotColumnSelector(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeFieldHint", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeFieldSelector(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_DataframeMaterialization_expectedProjectCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeFieldHint_defaultPivotValueSelector(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldHint) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeMaterialization_projectStatuses(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldHint_defaultPivotValueSelector(ctx, field) + return ec.fieldContext_DataframeMaterialization_projectStatuses(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.DefaultPivotValueSelector, nil + return obj.ProjectStatuses, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeFieldSelector) graphql.Marshaler { - return ec.marshalODataframeFieldSelector2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeFieldSelector(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeProjectStatus) graphql.Marshaler { + return ec.marshalNDataframeProjectStatus2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeProjectStatusᚄ(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeFieldHint_defaultPivotValueSelector(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_DataframeMaterialization_projectStatuses(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "DataframeFieldHint", + Object: "DataframeMaterialization", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeFieldSelector(ctx, field) + return ec.childFields_DataframeProjectStatus(ctx, field) }, } return fc, nil } -func (ec *executionContext) _DataframeFieldPredicate_path(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldPredicate) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeOptimizationDecision_rule(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationDecision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldPredicate_path(ctx, field) + return ec.fieldContext_DataframeOptimizationDecision_rule(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Path, nil + return obj.Rule, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -2422,164 +2148,155 @@ func (ec *executionContext) _DataframeFieldPredicate_path(ctx context.Context, f true, ) } -func (ec *executionContext) fieldContext_DataframeFieldPredicate_path(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeFieldPredicate", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeOptimizationDecision_rule(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeOptimizationDecision", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeFieldPredicate_op(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldPredicate) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeOptimizationDecision_enabled(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationDecision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldPredicate_op(ctx, field) + return ec.fieldContext_DataframeOptimizationDecision_enabled(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Op, nil + return obj.Enabled, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v model.FhirFieldPredicateOperation) graphql.Marshaler { - return ec.marshalNFhirFieldPredicateOperation2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirFieldPredicateOperation(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { + return ec.marshalNBoolean2bool(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeFieldPredicate_op(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeFieldPredicate", field, false, false, errors.New("field of type FhirFieldPredicateOperation does not have child fields")) +func (ec *executionContext) fieldContext_DataframeOptimizationDecision_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeOptimizationDecision", field, false, false, errors.New("field of type Boolean does not have child fields")) } -func (ec *executionContext) _DataframeFieldPredicate_value(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldPredicate) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeOptimizationDecision_candidateSets(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationDecision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldPredicate_value(ctx, field) + return ec.fieldContext_DataframeOptimizationDecision_candidateSets(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Value, nil + return obj.CandidateSets, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeFieldPredicate_value(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeFieldPredicate", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeOptimizationDecision_candidateSets(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeOptimizationDecision", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeFieldSelector_sourcePath(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldSelector) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeOptimizationDecision_estimatedBaselineWork(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationDecision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldSelector_sourcePath(ctx, field) + return ec.fieldContext_DataframeOptimizationDecision_estimatedBaselineWork(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.SourcePath, nil + return obj.EstimatedBaselineWork, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeFieldSelector_sourcePath(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeFieldSelector", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeOptimizationDecision_estimatedBaselineWork(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeOptimizationDecision", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeFieldSelector_where(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldSelector) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeOptimizationDecision_estimatedOptimizedWork(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationDecision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldSelector_where(ctx, field) + return ec.fieldContext_DataframeOptimizationDecision_estimatedOptimizedWork(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Where, nil + return obj.EstimatedOptimizedWork, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeFieldPredicate) graphql.Marshaler { - return ec.marshalODataframeFieldPredicate2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeFieldPredicate(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeFieldSelector_where(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeFieldSelector", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeFieldPredicate(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_DataframeOptimizationDecision_estimatedOptimizedWork(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeOptimizationDecision", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeFieldSelector_valuePath(ctx context.Context, field graphql.CollectedField, obj *model.DataframeFieldSelector) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeOptimizationDecision_estimatedSavings(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationDecision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeFieldSelector_valuePath(ctx, field) + return ec.fieldContext_DataframeOptimizationDecision_estimatedSavings(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ValuePath, nil + return obj.EstimatedSavings, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeFieldSelector_valuePath(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeFieldSelector", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeOptimizationDecision_estimatedSavings(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeOptimizationDecision", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_id(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeOptimizationDecision_reason(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationDecision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_id(ctx, field) + return ec.fieldContext_DataframeOptimizationDecision_reason(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ID, nil + return obj.Reason, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNID2string(ctx, selections, v) + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type ID does not have child fields")) +func (ec *executionContext) fieldContext_DataframeOptimizationDecision_reason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeOptimizationDecision", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeOptimizationPolicy_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationPolicy) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_name(ctx, field) + return ec.fieldContext_DataframeOptimizationPolicy_name(ctx, field) }, func(ctx context.Context) (any, error) { return obj.Name, nil @@ -2592,190 +2309,190 @@ func (ec *executionContext) _DataframeMaterialization_name(ctx context.Context, true, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeOptimizationPolicy_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeOptimizationPolicy", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_revision(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeOptimizationPolicy_enabled(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationPolicy) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_revision(ctx, field) + return ec.fieldContext_DataframeOptimizationPolicy_enabled(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Revision, nil + return obj.Enabled, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { + return ec.marshalNBoolean2bool(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_revision(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeOptimizationPolicy_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeOptimizationPolicy", field, false, false, errors.New("field of type Boolean does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_projectId(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeOptimizationPolicy_minimumSavings(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationPolicy) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_projectId(ctx, field) + return ec.fieldContext_DataframeOptimizationPolicy_minimumSavings(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ProjectID, nil + return obj.MinimumSavings, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) - }, + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) + }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_projectId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeOptimizationPolicy_minimumSavings(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeOptimizationPolicy", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_datasetGeneration(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeOptimizationPolicy_decisions(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationPolicy) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_datasetGeneration(ctx, field) + return ec.fieldContext_DataframeOptimizationPolicy_decisions(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.DatasetGeneration, nil + return obj.Decisions, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeOptimizationDecision) graphql.Marshaler { + return ec.marshalNDataframeOptimizationDecision2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeOptimizationDecisionᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_datasetGeneration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeOptimizationPolicy_decisions(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DataframeOptimizationPolicy", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeOptimizationDecision(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeMaterialization_state(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframePageInfo_hasNextPage(ctx context.Context, field graphql.CollectedField, obj *model.DataframePageInfo) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_state(ctx, field) + return ec.fieldContext_DataframePageInfo_hasNextPage(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.State, nil + return obj.HasNextPage, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v model.DataframeMaterializationState) graphql.Marshaler { - return ec.marshalNDataframeMaterializationState2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeMaterializationState(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { + return ec.marshalNBoolean2bool(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_state(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type DataframeMaterializationState does not have child fields")) +func (ec *executionContext) fieldContext_DataframePageInfo_hasNextPage(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframePageInfo", field, false, false, errors.New("field of type Boolean does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_columns(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframePageInfo_endCursor(ctx context.Context, field graphql.CollectedField, obj *model.DataframePageInfo) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_columns(ctx, field) + return ec.fieldContext_DataframePageInfo_endCursor(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Columns, nil + return obj.EndCursor, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeColumn) graphql.Marshaler { - return ec.marshalNDataframeColumn2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeColumnᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { + return ec.marshalOString2ᚖstring(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_columns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeMaterialization", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeColumn(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_DataframePageInfo_endCursor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframePageInfo", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_rowCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeProjectStatus_project(ctx context.Context, field graphql.CollectedField, obj *model.DataframeProjectStatus) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_rowCount(ctx, field) + return ec.fieldContext_DataframeProjectStatus_project(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RowCount, nil + return obj.Project, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *int) graphql.Marshaler { - return ec.marshalOInt2ᚖint(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_rowCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeProjectStatus_project(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeProjectStatus", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_createdAt(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeProjectStatus_state(ctx context.Context, field graphql.CollectedField, obj *model.DataframeProjectStatus) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_createdAt(ctx, field) + return ec.fieldContext_DataframeProjectStatus_state(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.CreatedAt, nil + return obj.State, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v model.DataframeProjectState) graphql.Marshaler { + return ec.marshalNDataframeProjectState2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeProjectState(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_createdAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeProjectStatus_state(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeProjectStatus", field, false, false, errors.New("field of type DataframeProjectState does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_readyAt(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeProjectStatus_generation(ctx context.Context, field graphql.CollectedField, obj *model.DataframeProjectStatus) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_readyAt(ctx, field) + return ec.fieldContext_DataframeProjectStatus_generation(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ReadyAt, nil + return obj.Generation, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { @@ -2785,43 +2502,43 @@ func (ec *executionContext) _DataframeMaterialization_readyAt(ctx context.Contex false, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_readyAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeProjectStatus_generation(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeProjectStatus", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_error(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeProjectStatus_executionId(ctx context.Context, field graphql.CollectedField, obj *model.DataframeProjectStatus) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_error(ctx, field) + return ec.fieldContext_DataframeProjectStatus_executionId(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Error, nil + return obj.ExecutionID, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + return ec.marshalOID2ᚖstring(ctx, selections, v) }, true, false, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_error(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeProjectStatus_executionId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeProjectStatus", field, false, false, errors.New("field of type ID does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_errorCode(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeProjectStatus_createdAt(ctx context.Context, field graphql.CollectedField, obj *model.DataframeProjectStatus) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_errorCode(ctx, field) + return ec.fieldContext_DataframeProjectStatus_createdAt(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ErrorCode, nil + return obj.CreatedAt, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { @@ -2831,668 +2548,686 @@ func (ec *executionContext) _DataframeMaterialization_errorCode(ctx context.Cont false, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_errorCode(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeProjectStatus_createdAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeProjectStatus", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_errorRetryable(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeProjectStatus_updatedAt(ctx context.Context, field graphql.CollectedField, obj *model.DataframeProjectStatus) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_errorRetryable(ctx, field) + return ec.fieldContext_DataframeProjectStatus_updatedAt(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ErrorRetryable, nil + return obj.UpdatedAt, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *bool) graphql.Marshaler { - return ec.marshalOBoolean2ᚖbool(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { + return ec.marshalOString2ᚖstring(ctx, selections, v) }, true, false, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_errorRetryable(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type Boolean does not have child fields")) +func (ec *executionContext) fieldContext_DataframeProjectStatus_updatedAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeProjectStatus", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_selector(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeProjectStatus_errorCode(ctx context.Context, field graphql.CollectedField, obj *model.DataframeProjectStatus) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_selector(ctx, field) + return ec.fieldContext_DataframeProjectStatus_errorCode(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Selector, nil + return obj.ErrorCode, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeSelector) graphql.Marshaler { - return ec.marshalODataframeSelector2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeSelector(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { + return ec.marshalOString2ᚖstring(ctx, selections, v) }, true, false, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_selector(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeMaterialization", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeSelector(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_DataframeProjectStatus_errorCode(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeProjectStatus", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_activeContractVersion(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeProjectStatus_retryable(ctx context.Context, field graphql.CollectedField, obj *model.DataframeProjectStatus) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_activeContractVersion(ctx, field) + return ec.fieldContext_DataframeProjectStatus_retryable(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ActiveContractVersion, nil + return obj.Retryable, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { + return ec.marshalNBoolean2bool(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_activeContractVersion(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeProjectStatus_retryable(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeProjectStatus", field, false, false, errors.New("field of type Boolean does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_availability(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeQueryDiagnostics_inputResolutionMs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeQueryDiagnostics) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_availability(ctx, field) + return ec.fieldContext_DataframeQueryDiagnostics_inputResolutionMs(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Availability, nil + return obj.InputResolutionMs, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeAvailability) graphql.Marshaler { - return ec.marshalODataframeAvailability2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeAvailability(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v float64) graphql.Marshaler { + return ec.marshalNFloat2float64(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_availability(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type DataframeAvailability does not have child fields")) +func (ec *executionContext) fieldContext_DataframeQueryDiagnostics_inputResolutionMs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeQueryDiagnostics", field, false, false, errors.New("field of type Float does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_completeness(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeQueryDiagnostics_requestPreparationMs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeQueryDiagnostics) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_completeness(ctx, field) + return ec.fieldContext_DataframeQueryDiagnostics_requestPreparationMs(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Completeness, nil + return obj.RequestPreparationMs, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *float64) graphql.Marshaler { - return ec.marshalOFloat2ᚖfloat64(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v float64) graphql.Marshaler { + return ec.marshalNFloat2float64(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_completeness(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type Float does not have child fields")) +func (ec *executionContext) fieldContext_DataframeQueryDiagnostics_requestPreparationMs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeQueryDiagnostics", field, false, false, errors.New("field of type Float does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_includedProjectCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeQueryDiagnostics_compilationMs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeQueryDiagnostics) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_includedProjectCount(ctx, field) + return ec.fieldContext_DataframeQueryDiagnostics_compilationMs(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.IncludedProjectCount, nil + return obj.CompilationMs, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *int) graphql.Marshaler { - return ec.marshalOInt2ᚖint(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v float64) graphql.Marshaler { + return ec.marshalNFloat2float64(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_includedProjectCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeQueryDiagnostics_compilationMs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeQueryDiagnostics", field, false, false, errors.New("field of type Float does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_expectedProjectCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeQueryDiagnostics_arangoQueryMs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeQueryDiagnostics) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_expectedProjectCount(ctx, field) + return ec.fieldContext_DataframeQueryDiagnostics_arangoQueryMs(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ExpectedProjectCount, nil + return obj.ArangoQueryMs, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *int) graphql.Marshaler { - return ec.marshalOInt2ᚖint(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v float64) graphql.Marshaler { + return ec.marshalNFloat2float64(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_expectedProjectCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeMaterialization", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeQueryDiagnostics_arangoQueryMs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeQueryDiagnostics", field, false, false, errors.New("field of type Float does not have child fields")) } -func (ec *executionContext) _DataframeMaterialization_projectStatuses(ctx context.Context, field graphql.CollectedField, obj *model.DataframeMaterialization) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeQueryDiagnostics_rowMaterializationMs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeQueryDiagnostics) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeMaterialization_projectStatuses(ctx, field) + return ec.fieldContext_DataframeQueryDiagnostics_rowMaterializationMs(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ProjectStatuses, nil + return obj.RowMaterializationMs, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeProjectStatus) graphql.Marshaler { - return ec.marshalNDataframeProjectStatus2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeProjectStatusᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v float64) graphql.Marshaler { + return ec.marshalNFloat2float64(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeMaterialization_projectStatuses(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeMaterialization", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeProjectStatus(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_DataframeQueryDiagnostics_rowMaterializationMs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeQueryDiagnostics", field, false, false, errors.New("field of type Float does not have child fields")) } -func (ec *executionContext) _DataframeOptimizationDecision_rule(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationDecision) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeQueryDiagnostics_resultAssemblyMs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeQueryDiagnostics) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeOptimizationDecision_rule(ctx, field) + return ec.fieldContext_DataframeQueryDiagnostics_resultAssemblyMs(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Rule, nil + return obj.ResultAssemblyMs, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v float64) graphql.Marshaler { + return ec.marshalNFloat2float64(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeOptimizationDecision_rule(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeOptimizationDecision", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeQueryDiagnostics_resultAssemblyMs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeQueryDiagnostics", field, false, false, errors.New("field of type Float does not have child fields")) } -func (ec *executionContext) _DataframeOptimizationDecision_enabled(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationDecision) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeQueryDiagnostics_totalMs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeQueryDiagnostics) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeOptimizationDecision_enabled(ctx, field) + return ec.fieldContext_DataframeQueryDiagnostics_totalMs(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Enabled, nil + return obj.TotalMs, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { - return ec.marshalNBoolean2bool(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v float64) graphql.Marshaler { + return ec.marshalNFloat2float64(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeOptimizationDecision_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeOptimizationDecision", field, false, false, errors.New("field of type Boolean does not have child fields")) +func (ec *executionContext) fieldContext_DataframeQueryDiagnostics_totalMs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeQueryDiagnostics", field, false, false, errors.New("field of type Float does not have child fields")) } -func (ec *executionContext) _DataframeOptimizationDecision_candidateSets(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationDecision) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeQueryDiagnostics_plan(ctx context.Context, field graphql.CollectedField, obj *model.DataframeQueryDiagnostics) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeOptimizationDecision_candidateSets(ctx, field) + return ec.fieldContext_DataframeQueryDiagnostics_plan(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.CandidateSets, nil + return obj.Plan, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeCompilerPlanDiagnostics) graphql.Marshaler { + return ec.marshalNDataframeCompilerPlanDiagnostics2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeCompilerPlanDiagnostics(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeOptimizationDecision_candidateSets(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeOptimizationDecision", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeQueryDiagnostics_plan(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DataframeQueryDiagnostics", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeCompilerPlanDiagnostics(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeOptimizationDecision_estimatedBaselineWork(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationDecision) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeArangoAssessment_plans(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeArangoAssessment) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeOptimizationDecision_estimatedBaselineWork(ctx, field) + return ec.fieldContext_DataframeRecipeArangoAssessment_plans(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.EstimatedBaselineWork, nil + return obj.Plans, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeExplainPlanEstimate) graphql.Marshaler { + return ec.marshalNDataframeRecipeExplainPlanEstimate2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExplainPlanEstimateᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeOptimizationDecision_estimatedBaselineWork(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeOptimizationDecision", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeArangoAssessment_plans(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DataframeRecipeArangoAssessment", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipeExplainPlanEstimate(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeOptimizationDecision_estimatedOptimizedWork(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationDecision) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeArangoAssessment_fullCollectionScans(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeArangoAssessment) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeOptimizationDecision_estimatedOptimizedWork(ctx, field) + return ec.fieldContext_DataframeRecipeArangoAssessment_fullCollectionScans(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.EstimatedOptimizedWork, nil + return obj.FullCollectionScans, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeExplainCollectionScan) graphql.Marshaler { + return ec.marshalNDataframeRecipeExplainCollectionScan2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExplainCollectionScanᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeOptimizationDecision_estimatedOptimizedWork(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeOptimizationDecision", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeArangoAssessment_fullCollectionScans(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DataframeRecipeArangoAssessment", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipeExplainCollectionScan(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeOptimizationDecision_estimatedSavings(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationDecision) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeArangoAssessment_indexes(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeArangoAssessment) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeOptimizationDecision_estimatedSavings(ctx, field) + return ec.fieldContext_DataframeRecipeArangoAssessment_indexes(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.EstimatedSavings, nil + return obj.Indexes, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeExplainIndexSummary) graphql.Marshaler { + return ec.marshalNDataframeRecipeExplainIndexSummary2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExplainIndexSummaryᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeOptimizationDecision_estimatedSavings(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeOptimizationDecision", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeArangoAssessment_indexes(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DataframeRecipeArangoAssessment", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipeExplainIndexSummary(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeOptimizationDecision_reason(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationDecision) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeArangoAssessment_warnings(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeArangoAssessment) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeOptimizationDecision_reason(ctx, field) + return ec.fieldContext_DataframeRecipeArangoAssessment_warnings(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Reason, nil + return obj.Warnings, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeExplainWarning) graphql.Marshaler { + return ec.marshalNDataframeRecipeExplainWarning2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExplainWarningᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeOptimizationDecision_reason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeOptimizationDecision", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeArangoAssessment_warnings(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DataframeRecipeArangoAssessment", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipeExplainWarning(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeOptimizationPolicy_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationPolicy) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeArangoAssessment_appliedOptimizerRules(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeArangoAssessment) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeOptimizationPolicy_name(ctx, field) + return ec.fieldContext_DataframeRecipeArangoAssessment_appliedOptimizerRules(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Name, nil + return obj.AppliedOptimizerRules, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { + return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeOptimizationPolicy_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeOptimizationPolicy", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeArangoAssessment_appliedOptimizerRules(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeArangoAssessment", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeOptimizationPolicy_enabled(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationPolicy) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeColumn_output(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeColumn) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeOptimizationPolicy_enabled(ctx, field) + return ec.fieldContext_DataframeRecipeColumn_output(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Enabled, nil + return obj.Output, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { - return ec.marshalNBoolean2bool(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeOptimizationPolicy_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeOptimizationPolicy", field, false, false, errors.New("field of type Boolean does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeColumn_output(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeColumn", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeOptimizationPolicy_minimumSavings(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationPolicy) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeColumn_dynamicName(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeColumn) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeOptimizationPolicy_minimumSavings(ctx, field) + return ec.fieldContext_DataframeRecipeColumn_dynamicName(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.MinimumSavings, nil + return obj.DynamicName, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeOptimizationPolicy_minimumSavings(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeOptimizationPolicy", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeColumn_dynamicName(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeColumn", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeOptimizationPolicy_decisions(ctx context.Context, field graphql.CollectedField, obj *model.DataframeOptimizationPolicy) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeColumn_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeColumn) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeOptimizationPolicy_decisions(ctx, field) + return ec.fieldContext_DataframeRecipeColumn_name(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Decisions, nil + return obj.Name, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeOptimizationDecision) graphql.Marshaler { - return ec.marshalNDataframeOptimizationDecision2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeOptimizationDecisionᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeOptimizationPolicy_decisions(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeOptimizationPolicy", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeOptimizationDecision(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_DataframeRecipeColumn_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeColumn", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframePageInfo_hasNextPage(ctx context.Context, field graphql.CollectedField, obj *model.DataframePageInfo) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeColumn_logicalType(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeColumn) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframePageInfo_hasNextPage(ctx, field) + return ec.fieldContext_DataframeRecipeColumn_logicalType(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.HasNextPage, nil + return obj.LogicalType, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { - return ec.marshalNBoolean2bool(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframePageInfo_hasNextPage(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframePageInfo", field, false, false, errors.New("field of type Boolean does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeColumn_logicalType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeColumn", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframePageInfo_endCursor(ctx context.Context, field graphql.CollectedField, obj *model.DataframePageInfo) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeColumn_repeated(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeColumn) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframePageInfo_endCursor(ctx, field) + return ec.fieldContext_DataframeRecipeColumn_repeated(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.EndCursor, nil + return obj.Repeated, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { + return ec.marshalNBoolean2bool(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframePageInfo_endCursor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframePageInfo", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeColumn_repeated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeColumn", field, false, false, errors.New("field of type Boolean does not have child fields")) } -func (ec *executionContext) _DataframeProjectStatus_project(ctx context.Context, field graphql.CollectedField, obj *model.DataframeProjectStatus) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeColumn_nullable(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeColumn) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeProjectStatus_project(ctx, field) + return ec.fieldContext_DataframeRecipeColumn_nullable(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Project, nil + return obj.Nullable, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { + return ec.marshalNBoolean2bool(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeProjectStatus_project(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeProjectStatus", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeColumn_nullable(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeColumn", field, false, false, errors.New("field of type Boolean does not have child fields")) } -func (ec *executionContext) _DataframeProjectStatus_state(ctx context.Context, field graphql.CollectedField, obj *model.DataframeProjectStatus) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecution_id(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeProjectStatus_state(ctx, field) + return ec.fieldContext_DataframeRecipeExecution_id(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.State, nil + return obj.ID, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v model.DataframeProjectState) graphql.Marshaler { - return ec.marshalNDataframeProjectState2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeProjectState(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNID2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeProjectStatus_state(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeProjectStatus", field, false, false, errors.New("field of type DataframeProjectState does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExecution_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type ID does not have child fields")) } -func (ec *executionContext) _DataframeProjectStatus_generation(ctx context.Context, field graphql.CollectedField, obj *model.DataframeProjectStatus) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecution_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeProjectStatus_generation(ctx, field) + return ec.fieldContext_DataframeRecipeExecution_name(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Generation, nil + return obj.Name, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeProjectStatus_generation(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeProjectStatus", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExecution_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeProjectStatus_executionId(ctx context.Context, field graphql.CollectedField, obj *model.DataframeProjectStatus) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecution_recipeDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeProjectStatus_executionId(ctx, field) + return ec.fieldContext_DataframeRecipeExecution_recipeDigest(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ExecutionID, nil + return obj.RecipeDigest, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOID2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeProjectStatus_executionId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeProjectStatus", field, false, false, errors.New("field of type ID does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExecution_recipeDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeProjectStatus_createdAt(ctx context.Context, field graphql.CollectedField, obj *model.DataframeProjectStatus) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecution_resolvedSchemaDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeProjectStatus_createdAt(ctx, field) + return ec.fieldContext_DataframeRecipeExecution_resolvedSchemaDigest(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.CreatedAt, nil + return obj.ResolvedSchemaDigest, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeProjectStatus_createdAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeProjectStatus", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExecution_resolvedSchemaDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeProjectStatus_updatedAt(ctx context.Context, field graphql.CollectedField, obj *model.DataframeProjectStatus) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecution_sourceGeneration(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeProjectStatus_updatedAt(ctx, field) + return ec.fieldContext_DataframeRecipeExecution_sourceGeneration(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.UpdatedAt, nil + return obj.SourceGeneration, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeProjectStatus_updatedAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeProjectStatus", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExecution_sourceGeneration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeProjectStatus_errorCode(ctx context.Context, field graphql.CollectedField, obj *model.DataframeProjectStatus) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecution_translationVersion(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeProjectStatus_errorCode(ctx, field) + return ec.fieldContext_DataframeRecipeExecution_translationVersion(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ErrorCode, nil + return obj.TranslationVersion, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { @@ -3502,433 +3237,415 @@ func (ec *executionContext) _DataframeProjectStatus_errorCode(ctx context.Contex false, ) } -func (ec *executionContext) fieldContext_DataframeProjectStatus_errorCode(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeProjectStatus", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExecution_translationVersion(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeProjectStatus_retryable(ctx context.Context, field graphql.CollectedField, obj *model.DataframeProjectStatus) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecution_state(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeProjectStatus_retryable(ctx, field) + return ec.fieldContext_DataframeRecipeExecution_state(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Retryable, nil + return obj.State, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { - return ec.marshalNBoolean2bool(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v model.DataframeRecipeExecutionState) graphql.Marshaler { + return ec.marshalNDataframeRecipeExecutionState2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExecutionState(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeProjectStatus_retryable(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeProjectStatus", field, false, false, errors.New("field of type Boolean does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExecution_state(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type DataframeRecipeExecutionState does not have child fields")) } -func (ec *executionContext) _DataframeQueryDiagnostics_inputResolutionMs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeQueryDiagnostics) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecution_outputs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeQueryDiagnostics_inputResolutionMs(ctx, field) + return ec.fieldContext_DataframeRecipeExecution_outputs(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.InputResolutionMs, nil + return obj.Outputs, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v float64) graphql.Marshaler { - return ec.marshalNFloat2float64(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeExecutionOutput) graphql.Marshaler { + return ec.marshalNDataframeRecipeExecutionOutput2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExecutionOutputᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeQueryDiagnostics_inputResolutionMs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeQueryDiagnostics", field, false, false, errors.New("field of type Float does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExecution_outputs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DataframeRecipeExecution", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipeExecutionOutput(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeQueryDiagnostics_requestPreparationMs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeQueryDiagnostics) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecution_error(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeQueryDiagnostics_requestPreparationMs(ctx, field) + return ec.fieldContext_DataframeRecipeExecution_error(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RequestPreparationMs, nil + return obj.Error, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v float64) graphql.Marshaler { - return ec.marshalNFloat2float64(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { + return ec.marshalOString2ᚖstring(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeQueryDiagnostics_requestPreparationMs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeQueryDiagnostics", field, false, false, errors.New("field of type Float does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExecution_error(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeQueryDiagnostics_compilationMs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeQueryDiagnostics) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecution_errorCode(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeQueryDiagnostics_compilationMs(ctx, field) + return ec.fieldContext_DataframeRecipeExecution_errorCode(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.CompilationMs, nil + return obj.ErrorCode, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v float64) graphql.Marshaler { - return ec.marshalNFloat2float64(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { + return ec.marshalOString2ᚖstring(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeQueryDiagnostics_compilationMs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeQueryDiagnostics", field, false, false, errors.New("field of type Float does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExecution_errorCode(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeQueryDiagnostics_arangoQueryMs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeQueryDiagnostics) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecution_errorRetryable(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeQueryDiagnostics_arangoQueryMs(ctx, field) + return ec.fieldContext_DataframeRecipeExecution_errorRetryable(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ArangoQueryMs, nil + return obj.ErrorRetryable, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v float64) graphql.Marshaler { - return ec.marshalNFloat2float64(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *bool) graphql.Marshaler { + return ec.marshalOBoolean2ᚖbool(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeQueryDiagnostics_arangoQueryMs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeQueryDiagnostics", field, false, false, errors.New("field of type Float does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExecution_errorRetryable(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type Boolean does not have child fields")) } -func (ec *executionContext) _DataframeQueryDiagnostics_rowMaterializationMs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeQueryDiagnostics) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecution_phase(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeQueryDiagnostics_rowMaterializationMs(ctx, field) + return ec.fieldContext_DataframeRecipeExecution_phase(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RowMaterializationMs, nil + return obj.Phase, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v float64) graphql.Marshaler { - return ec.marshalNFloat2float64(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { + return ec.marshalOString2ᚖstring(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeQueryDiagnostics_rowMaterializationMs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeQueryDiagnostics", field, false, false, errors.New("field of type Float does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExecution_phase(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeQueryDiagnostics_resultAssemblyMs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeQueryDiagnostics) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecution_requestId(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeQueryDiagnostics_resultAssemblyMs(ctx, field) + return ec.fieldContext_DataframeRecipeExecution_requestId(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ResultAssemblyMs, nil + return obj.RequestID, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v float64) graphql.Marshaler { - return ec.marshalNFloat2float64(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { + return ec.marshalOString2ᚖstring(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeQueryDiagnostics_resultAssemblyMs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeQueryDiagnostics", field, false, false, errors.New("field of type Float does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExecution_requestId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeQueryDiagnostics_totalMs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeQueryDiagnostics) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecutionOutput_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeQueryDiagnostics_totalMs(ctx, field) + return ec.fieldContext_DataframeRecipeExecutionOutput_name(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.TotalMs, nil + return obj.Name, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v float64) graphql.Marshaler { - return ec.marshalNFloat2float64(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeQueryDiagnostics_totalMs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeQueryDiagnostics", field, false, false, errors.New("field of type Float does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecutionOutput", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeQueryDiagnostics_plan(ctx context.Context, field graphql.CollectedField, obj *model.DataframeQueryDiagnostics) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecutionOutput_state(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeQueryDiagnostics_plan(ctx, field) + return ec.fieldContext_DataframeRecipeExecutionOutput_state(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Plan, nil + return obj.State, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeCompilerPlanDiagnostics) graphql.Marshaler { - return ec.marshalNDataframeCompilerPlanDiagnostics2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeCompilerPlanDiagnostics(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v model.DataframeRecipeExecutionState) graphql.Marshaler { + return ec.marshalNDataframeRecipeExecutionState2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExecutionState(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeQueryDiagnostics_plan(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeQueryDiagnostics", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeCompilerPlanDiagnostics(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_state(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecutionOutput", field, false, false, errors.New("field of type DataframeRecipeExecutionState does not have child fields")) } -func (ec *executionContext) _DataframeRecipeArangoAssessment_plans(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeArangoAssessment) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecutionOutput_rowCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeArangoAssessment_plans(ctx, field) + return ec.fieldContext_DataframeRecipeExecutionOutput_rowCount(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Plans, nil + return obj.RowCount, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeExplainPlanEstimate) graphql.Marshaler { - return ec.marshalNDataframeRecipeExplainPlanEstimate2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExplainPlanEstimateᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *int) graphql.Marshaler { + return ec.marshalOInt2ᚖint(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeRecipeArangoAssessment_plans(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeRecipeArangoAssessment", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeExplainPlanEstimate(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_rowCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecutionOutput", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeArangoAssessment_fullCollectionScans(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeArangoAssessment) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecutionOutput_columns(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeArangoAssessment_fullCollectionScans(ctx, field) + return ec.fieldContext_DataframeRecipeExecutionOutput_columns(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.FullCollectionScans, nil + return obj.Columns, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeExplainCollectionScan) graphql.Marshaler { - return ec.marshalNDataframeRecipeExplainCollectionScan2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExplainCollectionScanᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeColumn) graphql.Marshaler { + return ec.marshalNDataframeColumn2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeColumnᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeArangoAssessment_fullCollectionScans(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_columns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "DataframeRecipeArangoAssessment", + Object: "DataframeRecipeExecutionOutput", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeExplainCollectionScan(ctx, field) + return ec.childFields_DataframeColumn(ctx, field) }, } return fc, nil } -func (ec *executionContext) _DataframeRecipeArangoAssessment_indexes(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeArangoAssessment) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecutionOutput_error(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeArangoAssessment_indexes(ctx, field) + return ec.fieldContext_DataframeRecipeExecutionOutput_error(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Indexes, nil + return obj.Error, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeExplainIndexSummary) graphql.Marshaler { - return ec.marshalNDataframeRecipeExplainIndexSummary2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExplainIndexSummaryᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { + return ec.marshalOString2ᚖstring(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeRecipeArangoAssessment_indexes(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeRecipeArangoAssessment", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeExplainIndexSummary(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_error(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecutionOutput", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeArangoAssessment_warnings(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeArangoAssessment) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecutionOutput_errorCode(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeArangoAssessment_warnings(ctx, field) + return ec.fieldContext_DataframeRecipeExecutionOutput_errorCode(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Warnings, nil + return obj.ErrorCode, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeExplainWarning) graphql.Marshaler { - return ec.marshalNDataframeRecipeExplainWarning2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExplainWarningᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { + return ec.marshalOString2ᚖstring(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeRecipeArangoAssessment_warnings(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeRecipeArangoAssessment", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeExplainWarning(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_errorCode(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecutionOutput", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeArangoAssessment_appliedOptimizerRules(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeArangoAssessment) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecutionOutput_errorRetryable(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeArangoAssessment_appliedOptimizerRules(ctx, field) + return ec.fieldContext_DataframeRecipeExecutionOutput_errorRetryable(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.AppliedOptimizerRules, nil + return obj.ErrorRetryable, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { - return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *bool) graphql.Marshaler { + return ec.marshalOBoolean2ᚖbool(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeRecipeArangoAssessment_appliedOptimizerRules(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeArangoAssessment", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_errorRetryable(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecutionOutput", field, false, false, errors.New("field of type Boolean does not have child fields")) } -func (ec *executionContext) _DataframeRecipeColumn_output(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeColumn) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecutionOutput_selector(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeColumn_output(ctx, field) + return ec.fieldContext_DataframeRecipeExecutionOutput_selector(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Output, nil + return obj.Selector, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeSelector) graphql.Marshaler { + return ec.marshalODataframeSelector2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeSelector(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeRecipeColumn_output(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeColumn", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_selector(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DataframeRecipeExecutionOutput", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeSelector(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeRecipeColumn_dynamicName(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeColumn) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExecutionOutput_phase(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeColumn_dynamicName(ctx, field) + return ec.fieldContext_DataframeRecipeExecutionOutput_phase(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.DynamicName, nil + return obj.Phase, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { + return ec.marshalOString2ᚖstring(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeRecipeColumn_dynamicName(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeColumn", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_phase(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExecutionOutput", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeColumn_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeColumn) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExpansionExplanation_sourcePath(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExpansionExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeColumn_name(ctx, field) + return ec.fieldContext_DataframeRecipeExpansionExplanation_sourcePath(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Name, nil + return obj.SourcePath, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -3938,20 +3655,20 @@ func (ec *executionContext) _DataframeRecipeColumn_name(ctx context.Context, fie true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeColumn_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeColumn", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExpansionExplanation_sourcePath(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExpansionExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeColumn_logicalType(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeColumn) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExpansionExplanation_alias(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExpansionExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeColumn_logicalType(ctx, field) + return ec.fieldContext_DataframeRecipeExpansionExplanation_alias(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.LogicalType, nil + return obj.Alias, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -3961,135 +3678,135 @@ func (ec *executionContext) _DataframeRecipeColumn_logicalType(ctx context.Conte true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeColumn_logicalType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeColumn", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExpansionExplanation_alias(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExpansionExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeColumn_repeated(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeColumn) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplainCollectionScan_plan(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainCollectionScan) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeColumn_repeated(ctx, field) + return ec.fieldContext_DataframeRecipeExplainCollectionScan_plan(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Repeated, nil + return obj.Plan, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { - return ec.marshalNBoolean2bool(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeColumn_repeated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeColumn", field, false, false, errors.New("field of type Boolean does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExplainCollectionScan_plan(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExplainCollectionScan", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeColumn_nullable(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeColumn) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplainCollectionScan_nodeId(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainCollectionScan) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeColumn_nullable(ctx, field) + return ec.fieldContext_DataframeRecipeExplainCollectionScan_nodeId(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Nullable, nil + return obj.NodeID, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { - return ec.marshalNBoolean2bool(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeColumn_nullable(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeColumn", field, false, false, errors.New("field of type Boolean does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExplainCollectionScan_nodeId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExplainCollectionScan", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecution_id(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplainCollectionScan_collection(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainCollectionScan) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecution_id(ctx, field) + return ec.fieldContext_DataframeRecipeExplainCollectionScan_collection(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ID, nil + return obj.Collection, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNID2string(ctx, selections, v) + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecution_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type ID does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExplainCollectionScan_collection(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExplainCollectionScan", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecution_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplainIndexLocation_plan(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainIndexLocation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecution_name(ctx, field) + return ec.fieldContext_DataframeRecipeExplainIndexLocation_plan(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Name, nil + return obj.Plan, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecution_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExplainIndexLocation_plan(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExplainIndexLocation", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecution_recipeDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplainIndexLocation_nodeId(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainIndexLocation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecution_recipeDigest(ctx, field) + return ec.fieldContext_DataframeRecipeExplainIndexLocation_nodeId(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RecipeDigest, nil + return obj.NodeID, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecution_recipeDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExplainIndexLocation_nodeId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExplainIndexLocation", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecution_resolvedSchemaDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplainIndexSummary_collection(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainIndexSummary) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecution_resolvedSchemaDigest(ctx, field) + return ec.fieldContext_DataframeRecipeExplainIndexSummary_collection(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ResolvedSchemaDigest, nil + return obj.Collection, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -4099,20 +3816,20 @@ func (ec *executionContext) _DataframeRecipeExecution_resolvedSchemaDigest(ctx c true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecution_resolvedSchemaDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExplainIndexSummary_collection(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExplainIndexSummary", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecution_sourceGeneration(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplainIndexSummary_id(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainIndexSummary) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecution_sourceGeneration(ctx, field) + return ec.fieldContext_DataframeRecipeExplainIndexSummary_id(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.SourceGeneration, nil + return obj.ID, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -4122,210 +3839,233 @@ func (ec *executionContext) _DataframeRecipeExecution_sourceGeneration(ctx conte true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecution_sourceGeneration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExplainIndexSummary_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExplainIndexSummary", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecution_translationVersion(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplainIndexSummary_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainIndexSummary) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecution_translationVersion(ctx, field) + return ec.fieldContext_DataframeRecipeExplainIndexSummary_name(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.TranslationVersion, nil + return obj.Name, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecution_translationVersion(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExplainIndexSummary_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExplainIndexSummary", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecution_state(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplainIndexSummary_type(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainIndexSummary) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecution_state(ctx, field) + return ec.fieldContext_DataframeRecipeExplainIndexSummary_type(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.State, nil + return obj.Type, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v model.DataframeRecipeExecutionState) graphql.Marshaler { - return ec.marshalNDataframeRecipeExecutionState2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExecutionState(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecution_state(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type DataframeRecipeExecutionState does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExplainIndexSummary_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExplainIndexSummary", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecution_outputs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplainIndexSummary_fields(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainIndexSummary) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecution_outputs(ctx, field) + return ec.fieldContext_DataframeRecipeExplainIndexSummary_fields(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Outputs, nil + return obj.Fields, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeExecutionOutput) graphql.Marshaler { - return ec.marshalNDataframeRecipeExecutionOutput2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExecutionOutputᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { + return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecution_outputs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_DataframeRecipeExplainIndexSummary_fields(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExplainIndexSummary", field, false, false, errors.New("field of type String does not have child fields")) +} + +func (ec *executionContext) _DataframeRecipeExplainIndexSummary_uses(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainIndexSummary) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.fieldContext_DataframeRecipeExplainIndexSummary_uses(ctx, field) + }, + func(ctx context.Context) (any, error) { + return obj.Uses, nil + }, + nil, + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeExplainIndexLocation) graphql.Marshaler { + return ec.marshalNDataframeRecipeExplainIndexLocation2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExplainIndexLocationᚄ(ctx, selections, v) + }, + true, + true, + ) +} +func (ec *executionContext) fieldContext_DataframeRecipeExplainIndexSummary_uses(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "DataframeRecipeExecution", + Object: "DataframeRecipeExplainIndexSummary", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeExecutionOutput(ctx, field) + return ec.childFields_DataframeRecipeExplainIndexLocation(ctx, field) }, } return fc, nil } -func (ec *executionContext) _DataframeRecipeExecution_error(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplainPlanEstimate_plan(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainPlanEstimate) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecution_error(ctx, field) + return ec.fieldContext_DataframeRecipeExplainPlanEstimate_plan(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Error, nil + return obj.Plan, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecution_error(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExplainPlanEstimate_plan(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExplainPlanEstimate", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecution_errorCode(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplainPlanEstimate_estimatedCost(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainPlanEstimate) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecution_errorCode(ctx, field) + return ec.fieldContext_DataframeRecipeExplainPlanEstimate_estimatedCost(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ErrorCode, nil + return obj.EstimatedCost, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v float64) graphql.Marshaler { + return ec.marshalNFloat2float64(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecution_errorCode(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExplainPlanEstimate_estimatedCost(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExplainPlanEstimate", field, false, false, errors.New("field of type Float does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecution_errorRetryable(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplainPlanEstimate_estimatedNrItems(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainPlanEstimate) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecution_errorRetryable(ctx, field) + return ec.fieldContext_DataframeRecipeExplainPlanEstimate_estimatedNrItems(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ErrorRetryable, nil + return obj.EstimatedNrItems, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *bool) graphql.Marshaler { - return ec.marshalOBoolean2ᚖbool(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v float64) graphql.Marshaler { + return ec.marshalNFloat2float64(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecution_errorRetryable(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type Boolean does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExplainPlanEstimate_estimatedNrItems(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExplainPlanEstimate", field, false, false, errors.New("field of type Float does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecution_phase(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplainWarning_code(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainWarning) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecution_phase(ctx, field) + return ec.fieldContext_DataframeRecipeExplainWarning_code(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Phase, nil + return obj.Code, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecution_phase(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExplainWarning_code(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExplainWarning", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecution_requestId(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecution) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplainWarning_message(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainWarning) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecution_requestId(ctx, field) + return ec.fieldContext_DataframeRecipeExplainWarning_message(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RequestID, nil + return obj.Message, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecution_requestId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecution", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExplainWarning_message(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExplainWarning", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecutionOutput_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplanation_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecutionOutput_name(ctx, field) + return ec.fieldContext_DataframeRecipeExplanation_name(ctx, field) }, func(ctx context.Context) (any, error) { return obj.Name, nil @@ -4338,337 +4078,337 @@ func (ec *executionContext) _DataframeRecipeExecutionOutput_name(ctx context.Con true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecutionOutput", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExplanation_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecutionOutput_state(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplanation_recipeDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecutionOutput_state(ctx, field) + return ec.fieldContext_DataframeRecipeExplanation_recipeDigest(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.State, nil + return obj.RecipeDigest, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v model.DataframeRecipeExecutionState) graphql.Marshaler { - return ec.marshalNDataframeRecipeExecutionState2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExecutionState(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_state(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecutionOutput", field, false, false, errors.New("field of type DataframeRecipeExecutionState does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExplanation_recipeDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecutionOutput_rowCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplanation_translationVersion(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecutionOutput_rowCount(ctx, field) + return ec.fieldContext_DataframeRecipeExplanation_translationVersion(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RowCount, nil + return obj.TranslationVersion, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *int) graphql.Marshaler { - return ec.marshalOInt2ᚖint(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_rowCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecutionOutput", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExplanation_translationVersion(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecutionOutput_columns(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplanation_outputs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecutionOutput_columns(ctx, field) + return ec.fieldContext_DataframeRecipeExplanation_outputs(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Columns, nil + return obj.Outputs, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeColumn) graphql.Marshaler { - return ec.marshalNDataframeColumn2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeColumnᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeOutputExplanation) graphql.Marshaler { + return ec.marshalNDataframeRecipeOutputExplanation2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeOutputExplanationᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_columns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_DataframeRecipeExplanation_outputs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "DataframeRecipeExecutionOutput", + Object: "DataframeRecipeExplanation", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeColumn(ctx, field) + return ec.childFields_DataframeRecipeOutputExplanation(ctx, field) }, } return fc, nil } -func (ec *executionContext) _DataframeRecipeExecutionOutput_error(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExplanation_physical(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecutionOutput_error(ctx, field) + return ec.fieldContext_DataframeRecipeExplanation_physical(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Error, nil + return obj.Physical, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipePhysicalExplanation) graphql.Marshaler { + return ec.marshalODataframeRecipePhysicalExplanation2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipePhysicalExplanation(ctx, selections, v) }, true, false, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_error(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecutionOutput", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExplanation_physical(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DataframeRecipeExplanation", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipePhysicalExplanation(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeRecipeExecutionOutput_errorCode(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExpressionExplanation_sourcePath(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExpressionExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecutionOutput_errorCode(ctx, field) + return ec.fieldContext_DataframeRecipeExpressionExplanation_sourcePath(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ErrorCode, nil + return obj.SourcePath, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_errorCode(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecutionOutput", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExpressionExplanation_sourcePath(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExpressionExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecutionOutput_errorRetryable(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExpressionExplanation_context(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExpressionExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecutionOutput_errorRetryable(ctx, field) + return ec.fieldContext_DataframeRecipeExpressionExplanation_context(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ErrorRetryable, nil + return obj.Context, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *bool) graphql.Marshaler { - return ec.marshalOBoolean2ᚖbool(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_errorRetryable(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecutionOutput", field, false, false, errors.New("field of type Boolean does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExpressionExplanation_context(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExpressionExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecutionOutput_selector(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExpressionExplanation_kind(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExpressionExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecutionOutput_selector(ctx, field) + return ec.fieldContext_DataframeRecipeExpressionExplanation_kind(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Selector, nil + return obj.Kind, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeSelector) graphql.Marshaler { - return ec.marshalODataframeSelector2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeSelector(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_selector(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeRecipeExecutionOutput", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeSelector(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_DataframeRecipeExpressionExplanation_kind(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExpressionExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExecutionOutput_phase(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExecutionOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExpressionExplanation_valueType(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExpressionExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExecutionOutput_phase(ctx, field) + return ec.fieldContext_DataframeRecipeExpressionExplanation_valueType(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Phase, nil + return obj.ValueType, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExecutionOutput_phase(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExecutionOutput", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExpressionExplanation_valueType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExpressionExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExpansionExplanation_sourcePath(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExpansionExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExpressionExplanation_repeated(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExpressionExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExpansionExplanation_sourcePath(ctx, field) + return ec.fieldContext_DataframeRecipeExpressionExplanation_repeated(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.SourcePath, nil + return obj.Repeated, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { + return ec.marshalNBoolean2bool(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExpansionExplanation_sourcePath(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExpansionExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExpressionExplanation_repeated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExpressionExplanation", field, false, false, errors.New("field of type Boolean does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExpansionExplanation_alias(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExpansionExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeExpressionExplanation_nullable(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExpressionExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExpansionExplanation_alias(ctx, field) + return ec.fieldContext_DataframeRecipeExpressionExplanation_nullable(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Alias, nil + return obj.Nullable, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { + return ec.marshalNBoolean2bool(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExpansionExplanation_alias(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExpansionExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeExpressionExplanation_nullable(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeExpressionExplanation", field, false, false, errors.New("field of type Boolean does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExplainCollectionScan_plan(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainCollectionScan) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOptimizationDecision_rule(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationDecision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplainCollectionScan_plan(ctx, field) + return ec.fieldContext_DataframeRecipeOptimizationDecision_rule(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Plan, nil + return obj.Rule, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplainCollectionScan_plan(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExplainCollectionScan", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOptimizationDecision_rule(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOptimizationDecision", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExplainCollectionScan_nodeId(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainCollectionScan) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOptimizationDecision_enabled(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationDecision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplainCollectionScan_nodeId(ctx, field) + return ec.fieldContext_DataframeRecipeOptimizationDecision_enabled(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.NodeID, nil + return obj.Enabled, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { + return ec.marshalNBoolean2bool(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplainCollectionScan_nodeId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExplainCollectionScan", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOptimizationDecision_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOptimizationDecision", field, false, false, errors.New("field of type Boolean does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExplainCollectionScan_collection(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainCollectionScan) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOptimizationDecision_candidateSets(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationDecision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplainCollectionScan_collection(ctx, field) + return ec.fieldContext_DataframeRecipeOptimizationDecision_candidateSets(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Collection, nil + return obj.CandidateSets, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplainCollectionScan_collection(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExplainCollectionScan", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOptimizationDecision_candidateSets(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOptimizationDecision", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExplainIndexLocation_plan(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainIndexLocation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOptimizationDecision_estimatedBaselineWork(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationDecision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplainIndexLocation_plan(ctx, field) + return ec.fieldContext_DataframeRecipeOptimizationDecision_estimatedBaselineWork(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Plan, nil + return obj.EstimatedBaselineWork, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { @@ -4678,20 +4418,20 @@ func (ec *executionContext) _DataframeRecipeExplainIndexLocation_plan(ctx contex true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplainIndexLocation_plan(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExplainIndexLocation", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOptimizationDecision_estimatedBaselineWork(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOptimizationDecision", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExplainIndexLocation_nodeId(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainIndexLocation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOptimizationDecision_estimatedOptimizedWork(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationDecision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplainIndexLocation_nodeId(ctx, field) + return ec.fieldContext_DataframeRecipeOptimizationDecision_estimatedOptimizedWork(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.NodeID, nil + return obj.EstimatedOptimizedWork, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { @@ -4701,43 +4441,43 @@ func (ec *executionContext) _DataframeRecipeExplainIndexLocation_nodeId(ctx cont true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplainIndexLocation_nodeId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExplainIndexLocation", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOptimizationDecision_estimatedOptimizedWork(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOptimizationDecision", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExplainIndexSummary_collection(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainIndexSummary) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOptimizationDecision_estimatedSavings(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationDecision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplainIndexSummary_collection(ctx, field) + return ec.fieldContext_DataframeRecipeOptimizationDecision_estimatedSavings(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Collection, nil + return obj.EstimatedSavings, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplainIndexSummary_collection(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExplainIndexSummary", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOptimizationDecision_estimatedSavings(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOptimizationDecision", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExplainIndexSummary_id(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainIndexSummary) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOptimizationDecision_reason(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationDecision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplainIndexSummary_id(ctx, field) + return ec.fieldContext_DataframeRecipeOptimizationDecision_reason(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ID, nil + return obj.Reason, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -4747,20 +4487,20 @@ func (ec *executionContext) _DataframeRecipeExplainIndexSummary_id(ctx context.C true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplainIndexSummary_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExplainIndexSummary", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOptimizationDecision_reason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOptimizationDecision", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExplainIndexSummary_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainIndexSummary) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOptimizationExplanation_policy(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplainIndexSummary_name(ctx, field) + return ec.fieldContext_DataframeRecipeOptimizationExplanation_policy(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Name, nil + return obj.Policy, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -4770,190 +4510,199 @@ func (ec *executionContext) _DataframeRecipeExplainIndexSummary_name(ctx context true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplainIndexSummary_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExplainIndexSummary", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOptimizationExplanation_policy(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOptimizationExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExplainIndexSummary_type(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainIndexSummary) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOptimizationExplanation_enabled(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplainIndexSummary_type(ctx, field) + return ec.fieldContext_DataframeRecipeOptimizationExplanation_enabled(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Type, nil + return obj.Enabled, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { + return ec.marshalNBoolean2bool(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplainIndexSummary_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExplainIndexSummary", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOptimizationExplanation_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOptimizationExplanation", field, false, false, errors.New("field of type Boolean does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExplainIndexSummary_fields(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainIndexSummary) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOptimizationExplanation_minimumSavings(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplainIndexSummary_fields(ctx, field) + return ec.fieldContext_DataframeRecipeOptimizationExplanation_minimumSavings(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Fields, nil + return obj.MinimumSavings, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { - return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplainIndexSummary_fields(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExplainIndexSummary", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOptimizationExplanation_minimumSavings(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOptimizationExplanation", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExplainIndexSummary_uses(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainIndexSummary) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOptimizationExplanation_rules(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplainIndexSummary_uses(ctx, field) + return ec.fieldContext_DataframeRecipeOptimizationExplanation_rules(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Uses, nil + return obj.Rules, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeExplainIndexLocation) graphql.Marshaler { - return ec.marshalNDataframeRecipeExplainIndexLocation2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExplainIndexLocationᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeOptimizationRuleState) graphql.Marshaler { + return ec.marshalNDataframeRecipeOptimizationRuleState2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeOptimizationRuleStateᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplainIndexSummary_uses(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_DataframeRecipeOptimizationExplanation_rules(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "DataframeRecipeExplainIndexSummary", + Object: "DataframeRecipeOptimizationExplanation", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeExplainIndexLocation(ctx, field) + return ec.childFields_DataframeRecipeOptimizationRuleState(ctx, field) }, } return fc, nil } -func (ec *executionContext) _DataframeRecipeExplainPlanEstimate_plan(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainPlanEstimate) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOptimizationExplanation_decisions(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplainPlanEstimate_plan(ctx, field) + return ec.fieldContext_DataframeRecipeOptimizationExplanation_decisions(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Plan, nil + return obj.Decisions, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeOptimizationDecision) graphql.Marshaler { + return ec.marshalNDataframeRecipeOptimizationDecision2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeOptimizationDecisionᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplainPlanEstimate_plan(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExplainPlanEstimate", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOptimizationExplanation_decisions(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DataframeRecipeOptimizationExplanation", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipeOptimizationDecision(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeRecipeExplainPlanEstimate_estimatedCost(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainPlanEstimate) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOptimizationRuleState_rule(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationRuleState) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplainPlanEstimate_estimatedCost(ctx, field) + return ec.fieldContext_DataframeRecipeOptimizationRuleState_rule(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.EstimatedCost, nil + return obj.Rule, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v float64) graphql.Marshaler { - return ec.marshalNFloat2float64(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplainPlanEstimate_estimatedCost(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExplainPlanEstimate", field, false, false, errors.New("field of type Float does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOptimizationRuleState_rule(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOptimizationRuleState", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExplainPlanEstimate_estimatedNrItems(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainPlanEstimate) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOptimizationRuleState_enabled(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationRuleState) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplainPlanEstimate_estimatedNrItems(ctx, field) + return ec.fieldContext_DataframeRecipeOptimizationRuleState_enabled(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.EstimatedNrItems, nil + return obj.Enabled, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v float64) graphql.Marshaler { - return ec.marshalNFloat2float64(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { + return ec.marshalNBoolean2bool(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplainPlanEstimate_estimatedNrItems(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExplainPlanEstimate", field, false, false, errors.New("field of type Float does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOptimizationRuleState_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOptimizationRuleState", field, false, false, errors.New("field of type Boolean does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExplainWarning_code(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainWarning) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOptimizationRuleState_reason(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationRuleState) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplainWarning_code(ctx, field) + return ec.fieldContext_DataframeRecipeOptimizationRuleState_reason(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Code, nil + return obj.Reason, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplainWarning_code(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExplainWarning", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOptimizationRuleState_reason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOptimizationRuleState", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExplainWarning_message(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplainWarning) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOutputExplanation_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplainWarning_message(ctx, field) + return ec.fieldContext_DataframeRecipeOutputExplanation_name(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Message, nil + return obj.Name, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -4963,20 +4712,20 @@ func (ec *executionContext) _DataframeRecipeExplainWarning_message(ctx context.C true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplainWarning_message(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExplainWarning", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOutputExplanation_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOutputExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExplanation_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOutputExplanation_rootResourceType(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplanation_name(ctx, field) + return ec.fieldContext_DataframeRecipeOutputExplanation_rootResourceType(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Name, nil + return obj.RootResourceType, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -4986,20 +4735,20 @@ func (ec *executionContext) _DataframeRecipeExplanation_name(ctx context.Context true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplanation_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOutputExplanation_rootResourceType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOutputExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExplanation_recipeDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOutputExplanation_rowGrain(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplanation_recipeDigest(ctx, field) + return ec.fieldContext_DataframeRecipeOutputExplanation_rowGrain(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RecipeDigest, nil + return obj.RowGrain, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -5009,153 +4758,162 @@ func (ec *executionContext) _DataframeRecipeExplanation_recipeDigest(ctx context true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplanation_recipeDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOutputExplanation_rowGrain(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOutputExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExplanation_translationVersion(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOutputExplanation_fields(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplanation_translationVersion(ctx, field) + return ec.fieldContext_DataframeRecipeOutputExplanation_fields(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.TranslationVersion, nil + return obj.Fields, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeExpressionExplanation) graphql.Marshaler { + return ec.marshalNDataframeRecipeExpressionExplanation2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExpressionExplanationᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplanation_translationVersion(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOutputExplanation_fields(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DataframeRecipeOutputExplanation", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipeExpressionExplanation(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeRecipeExplanation_outputs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOutputExplanation_identity(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplanation_outputs(ctx, field) + return ec.fieldContext_DataframeRecipeOutputExplanation_identity(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Outputs, nil + return obj.Identity, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeOutputExplanation) graphql.Marshaler { - return ec.marshalNDataframeRecipeOutputExplanation2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeOutputExplanationᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeExpressionExplanation) graphql.Marshaler { + return ec.marshalODataframeRecipeExpressionExplanation2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExpressionExplanation(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplanation_outputs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_DataframeRecipeOutputExplanation_identity(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "DataframeRecipeExplanation", + Object: "DataframeRecipeOutputExplanation", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeOutputExplanation(ctx, field) + return ec.childFields_DataframeRecipeExpressionExplanation(ctx, field) }, } return fc, nil } -func (ec *executionContext) _DataframeRecipeExplanation_physical(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOutputExplanation_expansion(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExplanation_physical(ctx, field) + return ec.fieldContext_DataframeRecipeOutputExplanation_expansion(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Physical, nil + return obj.Expansion, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipePhysicalExplanation) graphql.Marshaler { - return ec.marshalODataframeRecipePhysicalExplanation2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipePhysicalExplanation(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeExpansionExplanation) graphql.Marshaler { + return ec.marshalODataframeRecipeExpansionExplanation2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExpansionExplanation(ctx, selections, v) }, true, false, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExplanation_physical(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_DataframeRecipeOutputExplanation_expansion(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "DataframeRecipeExplanation", + Object: "DataframeRecipeOutputExplanation", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipePhysicalExplanation(ctx, field) + return ec.childFields_DataframeRecipeExpansionExplanation(ctx, field) }, } return fc, nil } -func (ec *executionContext) _DataframeRecipeExpressionExplanation_sourcePath(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExpressionExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOutputExplanation_dynamicMaps(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExpressionExplanation_sourcePath(ctx, field) + return ec.fieldContext_DataframeRecipeOutputExplanation_dynamicMaps(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.SourcePath, nil + return obj.DynamicMaps, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { + return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExpressionExplanation_sourcePath(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExpressionExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOutputExplanation_dynamicMaps(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOutputExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExpressionExplanation_context(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExpressionExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOutputExplanation_catalogProjections(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExpressionExplanation_context(ctx, field) + return ec.fieldContext_DataframeRecipeOutputExplanation_catalogProjections(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Context, nil + return obj.CatalogProjections, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { + return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExpressionExplanation_context(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExpressionExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOutputExplanation_catalogProjections(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOutputExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExpressionExplanation_kind(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExpressionExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOutputValidation_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputValidation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExpressionExplanation_kind(ctx, field) + return ec.fieldContext_DataframeRecipeOutputValidation_name(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Kind, nil + return obj.Name, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -5165,20 +4923,20 @@ func (ec *executionContext) _DataframeRecipeExpressionExplanation_kind(ctx conte true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExpressionExplanation_kind(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExpressionExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOutputValidation_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOutputValidation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExpressionExplanation_valueType(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExpressionExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOutputValidation_rootResourceType(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputValidation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExpressionExplanation_valueType(ctx, field) + return ec.fieldContext_DataframeRecipeOutputValidation_rootResourceType(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ValueType, nil + return obj.RootResourceType, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -5188,181 +4946,190 @@ func (ec *executionContext) _DataframeRecipeExpressionExplanation_valueType(ctx true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExpressionExplanation_valueType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExpressionExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOutputValidation_rootResourceType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOutputValidation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExpressionExplanation_repeated(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExpressionExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOutputValidation_rowGrain(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputValidation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExpressionExplanation_repeated(ctx, field) + return ec.fieldContext_DataframeRecipeOutputValidation_rowGrain(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Repeated, nil + return obj.RowGrain, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { - return ec.marshalNBoolean2bool(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExpressionExplanation_repeated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExpressionExplanation", field, false, false, errors.New("field of type Boolean does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOutputValidation_rowGrain(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOutputValidation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeExpressionExplanation_nullable(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeExpressionExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOutputValidation_fieldNames(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputValidation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeExpressionExplanation_nullable(ctx, field) + return ec.fieldContext_DataframeRecipeOutputValidation_fieldNames(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Nullable, nil + return obj.FieldNames, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { - return ec.marshalNBoolean2bool(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { + return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeExpressionExplanation_nullable(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeExpressionExplanation", field, false, false, errors.New("field of type Boolean does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOutputValidation_fieldNames(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOutputValidation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOptimizationDecision_rule(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationDecision) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeOutputValidation_dynamicColumns(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputValidation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOptimizationDecision_rule(ctx, field) + return ec.fieldContext_DataframeRecipeOutputValidation_dynamicColumns(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Rule, nil + return obj.DynamicColumns, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { + return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOptimizationDecision_rule(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOptimizationDecision", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeOutputValidation_dynamicColumns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeOutputValidation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOptimizationDecision_enabled(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationDecision) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePhysicalExplanation_outputs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOptimizationDecision_enabled(ctx, field) + return ec.fieldContext_DataframeRecipePhysicalExplanation_outputs(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Enabled, nil + return obj.Outputs, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { - return ec.marshalNBoolean2bool(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipePhysicalOutputExplanation) graphql.Marshaler { + return ec.marshalNDataframeRecipePhysicalOutputExplanation2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipePhysicalOutputExplanationᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOptimizationDecision_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOptimizationDecision", field, false, false, errors.New("field of type Boolean does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePhysicalExplanation_outputs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DataframeRecipePhysicalExplanation", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipePhysicalOutputExplanation(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeRecipeOptimizationDecision_candidateSets(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationDecision) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOptimizationDecision_candidateSets(ctx, field) + return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_name(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.CandidateSets, nil + return obj.Name, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOptimizationDecision_candidateSets(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOptimizationDecision", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePhysicalOutputExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOptimizationDecision_estimatedBaselineWork(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationDecision) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_planFingerprint(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOptimizationDecision_estimatedBaselineWork(ctx, field) + return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_planFingerprint(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.EstimatedBaselineWork, nil + return obj.PlanFingerprint, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOptimizationDecision_estimatedBaselineWork(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOptimizationDecision", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_planFingerprint(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePhysicalOutputExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOptimizationDecision_estimatedOptimizedWork(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationDecision) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_columns(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOptimizationDecision_estimatedOptimizedWork(ctx, field) + return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_columns(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.EstimatedOptimizedWork, nil + return obj.Columns, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { + return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOptimizationDecision_estimatedOptimizedWork(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOptimizationDecision", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_columns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePhysicalOutputExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOptimizationDecision_estimatedSavings(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationDecision) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_traversalSets(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOptimizationDecision_estimatedSavings(ctx, field) + return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_traversalSets(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.EstimatedSavings, nil + return obj.TraversalSets, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { @@ -5372,89 +5139,89 @@ func (ec *executionContext) _DataframeRecipeOptimizationDecision_estimatedSaving true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOptimizationDecision_estimatedSavings(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOptimizationDecision", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_traversalSets(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePhysicalOutputExplanation", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOptimizationDecision_reason(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationDecision) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_endpointTraversalCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOptimizationDecision_reason(ctx, field) + return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_endpointTraversalCount(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Reason, nil + return obj.EndpointTraversalCount, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOptimizationDecision_reason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOptimizationDecision", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_endpointTraversalCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePhysicalOutputExplanation", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOptimizationExplanation_policy(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_nativeTraversalCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOptimizationExplanation_policy(ctx, field) + return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_nativeTraversalCount(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Policy, nil + return obj.NativeTraversalCount, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOptimizationExplanation_policy(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOptimizationExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_nativeTraversalCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePhysicalOutputExplanation", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOptimizationExplanation_enabled(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_sharedTraversalCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOptimizationExplanation_enabled(ctx, field) + return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_sharedTraversalCount(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Enabled, nil + return obj.SharedTraversalCount, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { - return ec.marshalNBoolean2bool(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOptimizationExplanation_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOptimizationExplanation", field, false, false, errors.New("field of type Boolean does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_sharedTraversalCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePhysicalOutputExplanation", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOptimizationExplanation_minimumSavings(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_requiredMatchReuseCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOptimizationExplanation_minimumSavings(ctx, field) + return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_requiredMatchReuseCount(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.MinimumSavings, nil + return obj.RequiredMatchReuseCount, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { @@ -5464,84 +5231,84 @@ func (ec *executionContext) _DataframeRecipeOptimizationExplanation_minimumSavin true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOptimizationExplanation_minimumSavings(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOptimizationExplanation", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_requiredMatchReuseCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePhysicalOutputExplanation", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOptimizationExplanation_rules(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_optimization(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOptimizationExplanation_rules(ctx, field) + return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_optimization(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Rules, nil + return obj.Optimization, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeOptimizationRuleState) graphql.Marshaler { - return ec.marshalNDataframeRecipeOptimizationRuleState2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeOptimizationRuleStateᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeOptimizationExplanation) graphql.Marshaler { + return ec.marshalNDataframeRecipeOptimizationExplanation2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeOptimizationExplanation(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOptimizationExplanation_rules(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_optimization(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "DataframeRecipeOptimizationExplanation", + Object: "DataframeRecipePhysicalOutputExplanation", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeOptimizationRuleState(ctx, field) + return ec.childFields_DataframeRecipeOptimizationExplanation(ctx, field) }, } return fc, nil } -func (ec *executionContext) _DataframeRecipeOptimizationExplanation_decisions(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_live(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOptimizationExplanation_decisions(ctx, field) + return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_live(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Decisions, nil + return obj.Live, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeOptimizationDecision) graphql.Marshaler { - return ec.marshalNDataframeRecipeOptimizationDecision2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeOptimizationDecisionᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeArangoAssessment) graphql.Marshaler { + return ec.marshalODataframeRecipeArangoAssessment2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeArangoAssessment(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOptimizationExplanation_decisions(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_live(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "DataframeRecipeOptimizationExplanation", + Object: "DataframeRecipePhysicalOutputExplanation", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeOptimizationDecision(ctx, field) + return ec.childFields_DataframeRecipeArangoAssessment(ctx, field) }, } return fc, nil } -func (ec *executionContext) _DataframeRecipeOptimizationRuleState_rule(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationRuleState) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePreflight_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreflight) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOptimizationRuleState_rule(ctx, field) + return ec.fieldContext_DataframeRecipePreflight_name(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Rule, nil + return obj.Name, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -5551,43 +5318,20 @@ func (ec *executionContext) _DataframeRecipeOptimizationRuleState_rule(ctx conte true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOptimizationRuleState_rule(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOptimizationRuleState", field, false, false, errors.New("field of type String does not have child fields")) -} - -func (ec *executionContext) _DataframeRecipeOptimizationRuleState_enabled(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationRuleState) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOptimizationRuleState_enabled(ctx, field) - }, - func(ctx context.Context) (any, error) { - return obj.Enabled, nil - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { - return ec.marshalNBoolean2bool(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_DataframeRecipeOptimizationRuleState_enabled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOptimizationRuleState", field, false, false, errors.New("field of type Boolean does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePreflight_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePreflight", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOptimizationRuleState_reason(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOptimizationRuleState) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePreflight_recipeDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreflight) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOptimizationRuleState_reason(ctx, field) + return ec.fieldContext_DataframeRecipePreflight_recipeDigest(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Reason, nil + return obj.RecipeDigest, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -5597,20 +5341,20 @@ func (ec *executionContext) _DataframeRecipeOptimizationRuleState_reason(ctx con true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOptimizationRuleState_reason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOptimizationRuleState", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePreflight_recipeDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePreflight", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOutputExplanation_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePreflight_resolvedSchemaDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreflight) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOutputExplanation_name(ctx, field) + return ec.fieldContext_DataframeRecipePreflight_resolvedSchemaDigest(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Name, nil + return obj.ResolvedSchemaDigest, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -5620,20 +5364,20 @@ func (ec *executionContext) _DataframeRecipeOutputExplanation_name(ctx context.C true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOutputExplanation_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOutputExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePreflight_resolvedSchemaDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePreflight", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOutputExplanation_rootResourceType(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePreflight_sourceGeneration(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreflight) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOutputExplanation_rootResourceType(ctx, field) + return ec.fieldContext_DataframeRecipePreflight_sourceGeneration(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RootResourceType, nil + return obj.SourceGeneration, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -5643,20 +5387,20 @@ func (ec *executionContext) _DataframeRecipeOutputExplanation_rootResourceType(c true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOutputExplanation_rootResourceType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOutputExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePreflight_sourceGeneration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePreflight", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOutputExplanation_rowGrain(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePreflight_scopeDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreflight) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOutputExplanation_rowGrain(ctx, field) + return ec.fieldContext_DataframeRecipePreflight_scopeDigest(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RowGrain, nil + return obj.ScopeDigest, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -5666,185 +5410,176 @@ func (ec *executionContext) _DataframeRecipeOutputExplanation_rowGrain(ctx conte true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOutputExplanation_rowGrain(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOutputExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePreflight_scopeDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePreflight", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOutputExplanation_fields(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePreflight_columns(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreflight) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOutputExplanation_fields(ctx, field) + return ec.fieldContext_DataframeRecipePreflight_columns(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Fields, nil + return obj.Columns, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeExpressionExplanation) graphql.Marshaler { - return ec.marshalNDataframeRecipeExpressionExplanation2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExpressionExplanationᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeColumn) graphql.Marshaler { + return ec.marshalNDataframeRecipeColumn2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeColumnᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOutputExplanation_fields(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_DataframeRecipePreflight_columns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "DataframeRecipeOutputExplanation", + Object: "DataframeRecipePreflight", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeExpressionExplanation(ctx, field) + return ec.childFields_DataframeRecipeColumn(ctx, field) }, } return fc, nil } -func (ec *executionContext) _DataframeRecipeOutputExplanation_identity(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePreview_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreview) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOutputExplanation_identity(ctx, field) + return ec.fieldContext_DataframeRecipePreview_name(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Identity, nil + return obj.Name, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeExpressionExplanation) graphql.Marshaler { - return ec.marshalODataframeRecipeExpressionExplanation2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExpressionExplanation(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOutputExplanation_identity(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeRecipeOutputExplanation", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeExpressionExplanation(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_DataframeRecipePreview_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePreview", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOutputExplanation_expansion(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePreview_recipeDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreview) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOutputExplanation_expansion(ctx, field) + return ec.fieldContext_DataframeRecipePreview_recipeDigest(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Expansion, nil + return obj.RecipeDigest, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeExpansionExplanation) graphql.Marshaler { - return ec.marshalODataframeRecipeExpansionExplanation2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExpansionExplanation(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOutputExplanation_expansion(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeRecipeOutputExplanation", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeExpansionExplanation(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_DataframeRecipePreview_recipeDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePreview", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOutputExplanation_dynamicMaps(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePreview_resolvedSchemaDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreview) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOutputExplanation_dynamicMaps(ctx, field) + return ec.fieldContext_DataframeRecipePreview_resolvedSchemaDigest(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.DynamicMaps, nil + return obj.ResolvedSchemaDigest, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { - return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOutputExplanation_dynamicMaps(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOutputExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePreview_resolvedSchemaDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePreview", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOutputExplanation_catalogProjections(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePreview_sourceGeneration(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreview) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOutputExplanation_catalogProjections(ctx, field) + return ec.fieldContext_DataframeRecipePreview_sourceGeneration(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.CatalogProjections, nil + return obj.SourceGeneration, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { - return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOutputExplanation_catalogProjections(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOutputExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePreview_sourceGeneration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePreview", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOutputValidation_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputValidation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePreview_outputs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreview) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOutputValidation_name(ctx, field) + return ec.fieldContext_DataframeRecipePreview_outputs(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Name, nil + return obj.Outputs, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipePreviewOutput) graphql.Marshaler { + return ec.marshalNDataframeRecipePreviewOutput2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipePreviewOutputᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOutputValidation_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOutputValidation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePreview_outputs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DataframeRecipePreview", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipePreviewOutput(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeRecipeOutputValidation_rootResourceType(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputValidation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePreviewOutput_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreviewOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOutputValidation_rootResourceType(ctx, field) + return ec.fieldContext_DataframeRecipePreviewOutput_name(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RootResourceType, nil + return obj.Name, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -5854,118 +5589,109 @@ func (ec *executionContext) _DataframeRecipeOutputValidation_rootResourceType(ct true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOutputValidation_rootResourceType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOutputValidation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePreviewOutput_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePreviewOutput", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOutputValidation_rowGrain(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputValidation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePreviewOutput_columns(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreviewOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOutputValidation_rowGrain(ctx, field) + return ec.fieldContext_DataframeRecipePreviewOutput_columns(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RowGrain, nil + return obj.Columns, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { + return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOutputValidation_rowGrain(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOutputValidation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePreviewOutput_columns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePreviewOutput", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOutputValidation_fieldNames(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputValidation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePreviewOutput_rows(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreviewOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOutputValidation_fieldNames(ctx, field) + return ec.fieldContext_DataframeRecipePreviewOutput_rows(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.FieldNames, nil + return obj.Rows, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { - return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v json.RawMessage) graphql.Marshaler { + return ec.marshalNJSON2encodingᚋjsonᚐRawMessage(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOutputValidation_fieldNames(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOutputValidation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePreviewOutput_rows(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePreviewOutput", field, false, false, errors.New("field of type JSON does not have child fields")) } -func (ec *executionContext) _DataframeRecipeOutputValidation_dynamicColumns(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeOutputValidation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePreviewOutput_csv(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreviewOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeOutputValidation_dynamicColumns(ctx, field) + return ec.fieldContext_DataframeRecipePreviewOutput_csv(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.DynamicColumns, nil + return obj.CSV, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { - return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { + return ec.marshalOString2ᚖstring(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeRecipeOutputValidation_dynamicColumns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeOutputValidation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipePreviewOutput_csv(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePreviewOutput", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipePhysicalExplanation_outputs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipePreviewOutput_rowCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreviewOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePhysicalExplanation_outputs(ctx, field) + return ec.fieldContext_DataframeRecipePreviewOutput_rowCount(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Outputs, nil + return obj.RowCount, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipePhysicalOutputExplanation) graphql.Marshaler { - return ec.marshalNDataframeRecipePhysicalOutputExplanation2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipePhysicalOutputExplanationᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePhysicalExplanation_outputs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeRecipePhysicalExplanation", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipePhysicalOutputExplanation(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_DataframeRecipePreviewOutput_rowCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipePreviewOutput", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeResult_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_name(ctx, field) + return ec.fieldContext_DataframeRecipeResult_name(ctx, field) }, func(ctx context.Context) (any, error) { return obj.Name, nil @@ -5978,20 +5704,20 @@ func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_name(ctx c true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePhysicalOutputExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeResult_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeResult", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_planFingerprint(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeResult_recipeDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_planFingerprint(ctx, field) + return ec.fieldContext_DataframeRecipeResult_recipeDigest(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.PlanFingerprint, nil + return obj.RecipeDigest, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -6001,245 +5727,213 @@ func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_planFinger true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_planFingerprint(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePhysicalOutputExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeResult_recipeDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeResult", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_columns(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeResult_resolvedSchemaDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_columns(ctx, field) + return ec.fieldContext_DataframeRecipeResult_resolvedSchemaDigest(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Columns, nil + return obj.ResolvedSchemaDigest, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { - return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_columns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePhysicalOutputExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeResult_resolvedSchemaDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeResult", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_traversalSets(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeResult_sourceGeneration(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_traversalSets(ctx, field) + return ec.fieldContext_DataframeRecipeResult_sourceGeneration(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.TraversalSets, nil + return obj.SourceGeneration, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_traversalSets(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePhysicalOutputExplanation", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeResult_sourceGeneration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeResult", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_endpointTraversalCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeResult_outputs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_endpointTraversalCount(ctx, field) + return ec.fieldContext_DataframeRecipeResult_outputs(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.EndpointTraversalCount, nil + return obj.Outputs, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeResultOutput) graphql.Marshaler { + return ec.marshalNDataframeRecipeResultOutput2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeResultOutputᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_endpointTraversalCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePhysicalOutputExplanation", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeResult_outputs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DataframeRecipeResult", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipeResultOutput(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_nativeTraversalCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeResultOutput_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResultOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_nativeTraversalCount(ctx, field) + return ec.fieldContext_DataframeRecipeResultOutput_name(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.NativeTraversalCount, nil + return obj.Name, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_nativeTraversalCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePhysicalOutputExplanation", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeResultOutput_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeResultOutput", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_sharedTraversalCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeResultOutput_columns(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResultOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_sharedTraversalCount(ctx, field) + return ec.fieldContext_DataframeRecipeResultOutput_columns(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.SharedTraversalCount, nil + return obj.Columns, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { + return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_sharedTraversalCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePhysicalOutputExplanation", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeResultOutput_columns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeResultOutput", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_requiredMatchReuseCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeResultOutput_rows(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResultOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_requiredMatchReuseCount(ctx, field) + return ec.fieldContext_DataframeRecipeResultOutput_rows(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RequiredMatchReuseCount, nil + return obj.Rows, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v json.RawMessage) graphql.Marshaler { + return ec.marshalNJSON2encodingᚋjsonᚐRawMessage(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_requiredMatchReuseCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePhysicalOutputExplanation", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeResultOutput_rows(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeResultOutput", field, false, false, errors.New("field of type JSON does not have child fields")) } -func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_optimization(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeResultOutput_csv(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResultOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_optimization(ctx, field) + return ec.fieldContext_DataframeRecipeResultOutput_csv(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Optimization, nil + return obj.CSV, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeOptimizationExplanation) graphql.Marshaler { - return ec.marshalNDataframeRecipeOptimizationExplanation2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeOptimizationExplanation(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { + return ec.marshalOString2ᚖstring(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_optimization(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeRecipePhysicalOutputExplanation", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeOptimizationExplanation(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_DataframeRecipeResultOutput_csv(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeResultOutput", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipePhysicalOutputExplanation_live(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePhysicalOutputExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeResultOutput_rowCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResultOutput) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePhysicalOutputExplanation_live(ctx, field) + return ec.fieldContext_DataframeRecipeResultOutput_rowCount(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Live, nil + return obj.RowCount, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeArangoAssessment) graphql.Marshaler { - return ec.marshalODataframeRecipeArangoAssessment2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeArangoAssessment(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePhysicalOutputExplanation_live(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeRecipePhysicalOutputExplanation", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeArangoAssessment(ctx, field) - }, - } - return fc, nil -} - -func (ec *executionContext) _DataframeRecipePreflight_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreflight) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePreflight_name(ctx, field) - }, - func(ctx context.Context) (any, error) { - return obj.Name, nil - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_DataframeRecipePreflight_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePreflight", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeResultOutput_rowCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeResultOutput", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipePreflight_recipeDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreflight) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeRevision_projectId(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeRevision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePreflight_recipeDigest(ctx, field) + return ec.fieldContext_DataframeRecipeRevision_projectId(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RecipeDigest, nil + return obj.ProjectID, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -6249,20 +5943,20 @@ func (ec *executionContext) _DataframeRecipePreflight_recipeDigest(ctx context.C true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePreflight_recipeDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePreflight", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeRevision_projectId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeRevision", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipePreflight_resolvedSchemaDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreflight) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeRevision_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeRevision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePreflight_resolvedSchemaDigest(ctx, field) + return ec.fieldContext_DataframeRecipeRevision_name(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ResolvedSchemaDigest, nil + return obj.Name, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -6272,20 +5966,20 @@ func (ec *executionContext) _DataframeRecipePreflight_resolvedSchemaDigest(ctx c true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePreflight_resolvedSchemaDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePreflight", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeRevision_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeRevision", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipePreflight_sourceGeneration(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreflight) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeRevision_digest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeRevision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePreflight_sourceGeneration(ctx, field) + return ec.fieldContext_DataframeRecipeRevision_digest(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.SourceGeneration, nil + return obj.Digest, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -6295,75 +5989,66 @@ func (ec *executionContext) _DataframeRecipePreflight_sourceGeneration(ctx conte true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePreflight_sourceGeneration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePreflight", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeRevision_digest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeRevision", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipePreflight_scopeDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreflight) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeRevision_parentDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeRevision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePreflight_scopeDigest(ctx, field) + return ec.fieldContext_DataframeRecipeRevision_parentDigest(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ScopeDigest, nil + return obj.ParentDigest, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { + return ec.marshalOString2ᚖstring(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeRecipePreflight_scopeDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePreflight", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeRevision_parentDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeRevision", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipePreflight_columns(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreflight) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeRevision_recipe(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeRevision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePreflight_columns(ctx, field) + return ec.fieldContext_DataframeRecipeRevision_recipe(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Columns, nil + return obj.Recipe, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeColumn) graphql.Marshaler { - return ec.marshalNDataframeRecipeColumn2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeColumnᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v json.RawMessage) graphql.Marshaler { + return ec.marshalNJSON2encodingᚋjsonᚐRawMessage(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePreflight_columns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeRecipePreflight", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeColumn(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_DataframeRecipeRevision_recipe(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeRevision", field, false, false, errors.New("field of type JSON does not have child fields")) } -func (ec *executionContext) _DataframeRecipePreview_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreview) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeRevision_createdAt(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeRevision) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePreview_name(ctx, field) + return ec.fieldContext_DataframeRecipeRevision_createdAt(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Name, nil + return obj.CreatedAt, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -6373,20 +6058,20 @@ func (ec *executionContext) _DataframeRecipePreview_name(ctx context.Context, fi true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePreview_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePreview", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeRevision_createdAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeRevision", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipePreview_recipeDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreview) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeValidation_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeValidation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePreview_recipeDigest(ctx, field) + return ec.fieldContext_DataframeRecipeValidation_name(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RecipeDigest, nil + return obj.Name, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -6396,20 +6081,20 @@ func (ec *executionContext) _DataframeRecipePreview_recipeDigest(ctx context.Con true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePreview_recipeDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePreview", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeValidation_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeValidation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipePreview_resolvedSchemaDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreview) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeValidation_recipeDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeValidation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePreview_resolvedSchemaDigest(ctx, field) + return ec.fieldContext_DataframeRecipeValidation_recipeDigest(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ResolvedSchemaDigest, nil + return obj.RecipeDigest, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -6419,20 +6104,20 @@ func (ec *executionContext) _DataframeRecipePreview_resolvedSchemaDigest(ctx con true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePreview_resolvedSchemaDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePreview", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeValidation_recipeDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeValidation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipePreview_sourceGeneration(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreview) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeValidation_translationVersion(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeValidation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePreview_sourceGeneration(ctx, field) + return ec.fieldContext_DataframeRecipeValidation_translationVersion(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.SourceGeneration, nil + return obj.TranslationVersion, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -6442,52 +6127,52 @@ func (ec *executionContext) _DataframeRecipePreview_sourceGeneration(ctx context true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePreview_sourceGeneration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePreview", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRecipeValidation_translationVersion(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRecipeValidation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipePreview_outputs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreview) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRecipeValidation_outputs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeValidation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePreview_outputs(ctx, field) + return ec.fieldContext_DataframeRecipeValidation_outputs(ctx, field) }, func(ctx context.Context) (any, error) { return obj.Outputs, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipePreviewOutput) graphql.Marshaler { - return ec.marshalNDataframeRecipePreviewOutput2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipePreviewOutputᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeOutputValidation) graphql.Marshaler { + return ec.marshalNDataframeRecipeOutputValidation2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeOutputValidationᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePreview_outputs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_DataframeRecipeValidation_outputs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "DataframeRecipePreview", + Object: "DataframeRecipeValidation", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipePreviewOutput(ctx, field) + return ec.childFields_DataframeRecipeOutputValidation(ctx, field) }, } return fc, nil } -func (ec *executionContext) _DataframeRecipePreviewOutput_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreviewOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRichSourceReuse_sourceSet(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRichSourceReuse) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePreviewOutput_name(ctx, field) + return ec.fieldContext_DataframeRichSourceReuse_sourceSet(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Name, nil + return obj.SourceSet, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -6497,89 +6182,89 @@ func (ec *executionContext) _DataframeRecipePreviewOutput_name(ctx context.Conte true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePreviewOutput_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePreviewOutput", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRichSourceReuse_sourceSet(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRichSourceReuse", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipePreviewOutput_columns(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreviewOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRichSourceReuse_aggregateConsumers(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRichSourceReuse) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePreviewOutput_columns(ctx, field) + return ec.fieldContext_DataframeRichSourceReuse_aggregateConsumers(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Columns, nil + return obj.AggregateConsumers, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { - return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePreviewOutput_columns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePreviewOutput", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRichSourceReuse_aggregateConsumers(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRichSourceReuse", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipePreviewOutput_rows(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreviewOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRichSourceReuse_pivotConsumers(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRichSourceReuse) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePreviewOutput_rows(ctx, field) + return ec.fieldContext_DataframeRichSourceReuse_pivotConsumers(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Rows, nil + return obj.PivotConsumers, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v json.RawMessage) graphql.Marshaler { - return ec.marshalNJSON2encodingᚋjsonᚐRawMessage(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePreviewOutput_rows(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePreviewOutput", field, false, false, errors.New("field of type JSON does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRichSourceReuse_pivotConsumers(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRichSourceReuse", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipePreviewOutput_csv(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreviewOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRichSourceReuse_sliceConsumers(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRichSourceReuse) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePreviewOutput_csv(ctx, field) + return ec.fieldContext_DataframeRichSourceReuse_sliceConsumers(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.CSV, nil + return obj.SliceConsumers, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePreviewOutput_csv(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePreviewOutput", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRichSourceReuse_sliceConsumers(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRichSourceReuse", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipePreviewOutput_rowCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipePreviewOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRichSourceReuse_totalConsumers(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRichSourceReuse) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipePreviewOutput_rowCount(ctx, field) + return ec.fieldContext_DataframeRichSourceReuse_totalConsumers(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RowCount, nil + return obj.TotalConsumers, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { @@ -6589,144 +6274,153 @@ func (ec *executionContext) _DataframeRecipePreviewOutput_rowCount(ctx context.C true, ) } -func (ec *executionContext) fieldContext_DataframeRecipePreviewOutput_rowCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipePreviewOutput", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRichSourceReuse_totalConsumers(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRichSourceReuse", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeResult_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResult) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRowConnection_materialization(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRowConnection) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeResult_name(ctx, field) + return ec.fieldContext_DataframeRowConnection_materialization(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Name, nil + return obj.Materialization, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeMaterialization) graphql.Marshaler { + return ec.marshalNDataframeMaterialization2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeMaterialization(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeResult_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeResult", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRowConnection_materialization(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DataframeRowConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeMaterialization(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeRecipeResult_recipeDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResult) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRowConnection_columns(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRowConnection) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeResult_recipeDigest(ctx, field) + return ec.fieldContext_DataframeRowConnection_columns(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RecipeDigest, nil + return obj.Columns, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { + return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeResult_recipeDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeResult", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRowConnection_columns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRowConnection", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeResult_resolvedSchemaDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResult) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRowConnection_rows(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRowConnection) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeResult_resolvedSchemaDigest(ctx, field) + return ec.fieldContext_DataframeRowConnection_rows(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ResolvedSchemaDigest, nil + return obj.Rows, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v json.RawMessage) graphql.Marshaler { + return ec.marshalNJSON2encodingᚋjsonᚐRawMessage(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeResult_resolvedSchemaDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeResult", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRowConnection_rows(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRowConnection", field, false, false, errors.New("field of type JSON does not have child fields")) } -func (ec *executionContext) _DataframeRecipeResult_sourceGeneration(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResult) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRowConnection_totalCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRowConnection) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeResult_sourceGeneration(ctx, field) + return ec.fieldContext_DataframeRowConnection_totalCount(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.SourceGeneration, nil + return obj.TotalCount, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *int) graphql.Marshaler { + return ec.marshalOInt2ᚖint(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeRecipeResult_sourceGeneration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeResult", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeRowConnection_totalCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeRowConnection", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeResult_outputs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResult) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeRowConnection_pageInfo(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRowConnection) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeResult_outputs(ctx, field) + return ec.fieldContext_DataframeRowConnection_pageInfo(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Outputs, nil + return obj.PageInfo, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeResultOutput) graphql.Marshaler { - return ec.marshalNDataframeRecipeResultOutput2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeResultOutputᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframePageInfo) graphql.Marshaler { + return ec.marshalNDataframePageInfo2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframePageInfo(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeResult_outputs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_DataframeRowConnection_pageInfo(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "DataframeRecipeResult", + Object: "DataframeRowConnection", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeResultOutput(ctx, field) + return ec.childFields_DataframePageInfo(ctx, field) }, } return fc, nil } -func (ec *executionContext) _DataframeRecipeResultOutput_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResultOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeSelector_recipe(ctx context.Context, field graphql.CollectedField, obj *model.DataframeSelector) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeResultOutput_name(ctx, field) + return ec.fieldContext_DataframeSelector_recipe(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Name, nil + return obj.Recipe, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -6736,158 +6430,167 @@ func (ec *executionContext) _DataframeRecipeResultOutput_name(ctx context.Contex true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeResultOutput_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeResultOutput", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeSelector_recipe(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeSelector", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeResultOutput_columns(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResultOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeSelector_translationVersion(ctx context.Context, field graphql.CollectedField, obj *model.DataframeSelector) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeResultOutput_columns(ctx, field) + return ec.fieldContext_DataframeSelector_translationVersion(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Columns, nil + return obj.TranslationVersion, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { - return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeResultOutput_columns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeResultOutput", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_DataframeSelector_translationVersion(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeSelector", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeResultOutput_rows(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResultOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _DataframeSelector_output(ctx context.Context, field graphql.CollectedField, obj *model.DataframeSelector) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeResultOutput_rows(ctx, field) + return ec.fieldContext_DataframeSelector_output(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Rows, nil + return obj.Output, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v json.RawMessage) graphql.Marshaler { - return ec.marshalNJSON2encodingᚋjsonᚐRawMessage(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeResultOutput_rows(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeResultOutput", field, false, false, errors.New("field of type JSON does not have child fields")) +func (ec *executionContext) fieldContext_DataframeSelector_output(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("DataframeSelector", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeResultOutput_csv(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResultOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirDataframeResult_columns(ctx context.Context, field graphql.CollectedField, obj *model.FhirDataframeResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeResultOutput_csv(ctx, field) + return ec.fieldContext_FhirDataframeResult_columns(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.CSV, nil + return obj.Columns, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { + return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeResultOutput_csv(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeResultOutput", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_FhirDataframeResult_columns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirDataframeResult", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeResultOutput_rowCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeResultOutput) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirDataframeResult_rows(ctx context.Context, field graphql.CollectedField, obj *model.FhirDataframeResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeResultOutput_rowCount(ctx, field) + return ec.fieldContext_FhirDataframeResult_rows(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RowCount, nil + return obj.Rows, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v json.RawMessage) graphql.Marshaler { + return ec.marshalNJSON2encodingᚋjsonᚐRawMessage(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeResultOutput_rowCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeResultOutput", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_FhirDataframeResult_rows(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirDataframeResult", field, false, false, errors.New("field of type JSON does not have child fields")) } -func (ec *executionContext) _DataframeRecipeRevision_projectId(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeRevision) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirDataframeResult_rowCount(ctx context.Context, field graphql.CollectedField, obj *model.FhirDataframeResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeRevision_projectId(ctx, field) + return ec.fieldContext_FhirDataframeResult_rowCount(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ProjectID, nil + return obj.RowCount, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeRevision_projectId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeRevision", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_FhirDataframeResult_rowCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirDataframeResult", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRecipeRevision_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeRevision) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirDataframeResult_diagnostics(ctx context.Context, field graphql.CollectedField, obj *model.FhirDataframeResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeRevision_name(ctx, field) + return ec.fieldContext_FhirDataframeResult_diagnostics(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Name, nil + return obj.Diagnostics, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeQueryDiagnostics) graphql.Marshaler { + return ec.marshalNDataframeQueryDiagnostics2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeQueryDiagnostics(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeRevision_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeRevision", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_FhirDataframeResult_diagnostics(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "FhirDataframeResult", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeQueryDiagnostics(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeRecipeRevision_digest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeRevision) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphNode_alias(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphNode) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeRevision_digest(ctx, field) + return ec.fieldContext_FhirGraphNode_alias(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Digest, nil + return obj.Alias, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -6897,112 +6600,112 @@ func (ec *executionContext) _DataframeRecipeRevision_digest(ctx context.Context, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeRevision_digest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeRevision", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_FhirGraphNode_alias(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirGraphNode", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeRevision_parentDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeRevision) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphNode_resourceType(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphNode) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeRevision_parentDigest(ctx, field) + return ec.fieldContext_FhirGraphNode_resourceType(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ParentDigest, nil + return obj.ResourceType, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *string) graphql.Marshaler { - return ec.marshalOString2ᚖstring(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeRevision_parentDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeRevision", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_FhirGraphNode_resourceType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirGraphNode", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeRevision_recipe(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeRevision) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphNode_id(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphNode) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeRevision_recipe(ctx, field) + return ec.fieldContext_FhirGraphNode_id(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Recipe, nil + return obj.ID, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v json.RawMessage) graphql.Marshaler { - return ec.marshalNJSON2encodingᚋjsonᚐRawMessage(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNID2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeRevision_recipe(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeRevision", field, false, false, errors.New("field of type JSON does not have child fields")) +func (ec *executionContext) fieldContext_FhirGraphNode_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirGraphNode", field, false, false, errors.New("field of type ID does not have child fields")) } -func (ec *executionContext) _DataframeRecipeRevision_createdAt(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeRevision) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphNode_resource(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphNode) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeRevision_createdAt(ctx, field) + return ec.fieldContext_FhirGraphNode_resource(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.CreatedAt, nil + return obj.Resource, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v json.RawMessage) graphql.Marshaler { + return ec.marshalNJSON2encodingᚋjsonᚐRawMessage(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeRevision_createdAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeRevision", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_FhirGraphNode_resource(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirGraphNode", field, false, false, errors.New("field of type JSON does not have child fields")) } -func (ec *executionContext) _DataframeRecipeValidation_name(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeValidation) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphPageInfo_hasMore(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphPageInfo) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeValidation_name(ctx, field) + return ec.fieldContext_FhirGraphPageInfo_hasMore(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Name, nil + return obj.HasMore, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { + return ec.marshalNBoolean2bool(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeValidation_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeValidation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_FhirGraphPageInfo_hasMore(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirGraphPageInfo", field, false, false, errors.New("field of type Boolean does not have child fields")) } -func (ec *executionContext) _DataframeRecipeValidation_recipeDigest(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeValidation) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphPath_terminalAlias(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphPath) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeValidation_recipeDigest(ctx, field) + return ec.fieldContext_FhirGraphPath_terminalAlias(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RecipeDigest, nil + return obj.TerminalAlias, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -7012,341 +6715,309 @@ func (ec *executionContext) _DataframeRecipeValidation_recipeDigest(ctx context. true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeValidation_recipeDigest(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeValidation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_FhirGraphPath_terminalAlias(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirGraphPath", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRecipeValidation_translationVersion(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeValidation) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphPath_nodes(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphPath) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeValidation_translationVersion(ctx, field) + return ec.fieldContext_FhirGraphPath_nodes(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.TranslationVersion, nil + return obj.Nodes, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.FhirGraphNode) graphql.Marshaler { + return ec.marshalNFhirGraphNode2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirGraphNodeᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeValidation_translationVersion(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRecipeValidation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_FhirGraphPath_nodes(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "FhirGraphPath", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_FhirGraphNode(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeRecipeValidation_outputs(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRecipeValidation) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphPath_relationships(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphPath) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRecipeValidation_outputs(ctx, field) + return ec.fieldContext_FhirGraphPath_relationships(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Outputs, nil + return obj.Relationships, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeOutputValidation) graphql.Marshaler { - return ec.marshalNDataframeRecipeOutputValidation2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeOutputValidationᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.FhirGraphRelationship) graphql.Marshaler { + return ec.marshalNFhirGraphRelationship2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirGraphRelationshipᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRecipeValidation_outputs(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_FhirGraphPath_relationships(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "DataframeRecipeValidation", + Object: "FhirGraphPath", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeOutputValidation(ctx, field) + return ec.childFields_FhirGraphRelationship(ctx, field) }, } return fc, nil } -func (ec *executionContext) _DataframeRelatedResourceHints_viaLabel(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRelatedResourceHints) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphQueryExplanation_sourceGeneration(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRelatedResourceHints_viaLabel(ctx, field) + return ec.fieldContext_FhirGraphQueryExplanation_sourceGeneration(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ViaLabel, nil + return obj.SourceGeneration, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + return ec.marshalNID2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRelatedResourceHints_viaLabel(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRelatedResourceHints", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_FhirGraphQueryExplanation_sourceGeneration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirGraphQueryExplanation", field, false, false, errors.New("field of type ID does not have child fields")) } -func (ec *executionContext) _DataframeRelatedResourceHints_edgeCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRelatedResourceHints) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphQueryExplanation_rootResourceType(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRelatedResourceHints_edgeCount(ctx, field) + return ec.fieldContext_FhirGraphQueryExplanation_rootResourceType(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.EdgeCount, nil + return obj.RootResourceType, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRelatedResourceHints_edgeCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRelatedResourceHints", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_FhirGraphQueryExplanation_rootResourceType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirGraphQueryExplanation", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRelatedResourceHints_target(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRelatedResourceHints) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphQueryExplanation_traversalCount(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRelatedResourceHints_target(ctx, field) + return ec.fieldContext_FhirGraphQueryExplanation_traversalCount(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Target, nil + return obj.TraversalCount, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeResourceHints) graphql.Marshaler { - return ec.marshalNDataframeResourceHints2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeResourceHints(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRelatedResourceHints_target(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeRelatedResourceHints", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeResourceHints(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_FhirGraphQueryExplanation_traversalCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirGraphQueryExplanation", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeResourceHints_resourceType(ctx context.Context, field graphql.CollectedField, obj *model.DataframeResourceHints) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphQueryExplanation_maxDepth(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeResourceHints_resourceType(ctx, field) + return ec.fieldContext_FhirGraphQueryExplanation_maxDepth(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ResourceType, nil + return obj.MaxDepth, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeResourceHints_resourceType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeResourceHints", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_FhirGraphQueryExplanation_maxDepth(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirGraphQueryExplanation", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeResourceHints_fields(ctx context.Context, field graphql.CollectedField, obj *model.DataframeResourceHints) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphQueryExplanation_limit(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeResourceHints_fields(ctx, field) + return ec.fieldContext_FhirGraphQueryExplanation_limit(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Fields, nil + return obj.Limit, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeFieldHint) graphql.Marshaler { - return ec.marshalNDataframeFieldHint2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeFieldHintᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { + return ec.marshalNInt2int(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeResourceHints_fields(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeResourceHints", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeFieldHint(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_FhirGraphQueryExplanation_limit(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirGraphQueryExplanation", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeResourceHints_pivotFields(ctx context.Context, field graphql.CollectedField, obj *model.DataframeResourceHints) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphQueryExplanation_live(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeResourceHints_pivotFields(ctx, field) + return ec.fieldContext_FhirGraphQueryExplanation_live(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.PivotFields, nil + return obj.Live, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeFieldHint) graphql.Marshaler { - return ec.marshalNDataframeFieldHint2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeFieldHintᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { + return ec.marshalNBoolean2bool(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeResourceHints_pivotFields(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeResourceHints", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeFieldHint(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_FhirGraphQueryExplanation_live(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirGraphQueryExplanation", field, false, false, errors.New("field of type Boolean does not have child fields")) } -func (ec *executionContext) _DataframeResourceHints_traversals(ctx context.Context, field graphql.CollectedField, obj *model.DataframeResourceHints) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphQueryExplanation_diagnostics(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryExplanation) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeResourceHints_traversals(ctx, field) + return ec.fieldContext_FhirGraphQueryExplanation_diagnostics(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Traversals, nil + return obj.Diagnostics, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeTraversalHint) graphql.Marshaler { - return ec.marshalNDataframeTraversalHint2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeTraversalHintᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeQueryDiagnostics) graphql.Marshaler { + return ec.marshalODataframeQueryDiagnostics2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeQueryDiagnostics(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_DataframeResourceHints_traversals(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_FhirGraphQueryExplanation_diagnostics(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "DataframeResourceHints", + Object: "FhirGraphQueryExplanation", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeTraversalHint(ctx, field) + return ec.childFields_DataframeQueryDiagnostics(ctx, field) }, } return fc, nil } -func (ec *executionContext) _DataframeRichSourceReuse_sourceSet(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRichSourceReuse) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphQueryResult_sourceGeneration(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRichSourceReuse_sourceSet(ctx, field) + return ec.fieldContext_FhirGraphQueryResult_sourceGeneration(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.SourceSet, nil + return obj.SourceGeneration, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + return ec.marshalNID2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRichSourceReuse_sourceSet(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRichSourceReuse", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_FhirGraphQueryResult_sourceGeneration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirGraphQueryResult", field, false, false, errors.New("field of type ID does not have child fields")) } -func (ec *executionContext) _DataframeRichSourceReuse_aggregateConsumers(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRichSourceReuse) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphQueryResult_paths(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRichSourceReuse_aggregateConsumers(ctx, field) + return ec.fieldContext_FhirGraphQueryResult_paths(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.AggregateConsumers, nil + return obj.Paths, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.FhirGraphPath) graphql.Marshaler { + return ec.marshalNFhirGraphPath2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirGraphPathᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRichSourceReuse_aggregateConsumers(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRichSourceReuse", field, false, false, errors.New("field of type Int does not have child fields")) -} - -func (ec *executionContext) _DataframeRichSourceReuse_pivotConsumers(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRichSourceReuse) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRichSourceReuse_pivotConsumers(ctx, field) - }, - func(ctx context.Context) (any, error) { - return obj.PivotConsumers, nil - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) +func (ec *executionContext) fieldContext_FhirGraphQueryResult_paths(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "FhirGraphQueryResult", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_FhirGraphPath(ctx, field) }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_DataframeRichSourceReuse_pivotConsumers(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRichSourceReuse", field, false, false, errors.New("field of type Int does not have child fields")) + } + return fc, nil } -func (ec *executionContext) _DataframeRichSourceReuse_sliceConsumers(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRichSourceReuse) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphQueryResult_returnedCount(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRichSourceReuse_sliceConsumers(ctx, field) + return ec.fieldContext_FhirGraphQueryResult_returnedCount(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.SliceConsumers, nil + return obj.ReturnedCount, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { @@ -7356,438 +7027,574 @@ func (ec *executionContext) _DataframeRichSourceReuse_sliceConsumers(ctx context true, ) } -func (ec *executionContext) fieldContext_DataframeRichSourceReuse_sliceConsumers(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRichSourceReuse", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_FhirGraphQueryResult_returnedCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirGraphQueryResult", field, false, false, errors.New("field of type Int does not have child fields")) } -func (ec *executionContext) _DataframeRichSourceReuse_totalConsumers(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRichSourceReuse) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphQueryResult_pageInfo(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRichSourceReuse_totalConsumers(ctx, field) + return ec.fieldContext_FhirGraphQueryResult_pageInfo(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.TotalConsumers, nil + return obj.PageInfo, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.FhirGraphPageInfo) graphql.Marshaler { + return ec.marshalNFhirGraphPageInfo2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirGraphPageInfo(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRichSourceReuse_totalConsumers(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRichSourceReuse", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_FhirGraphQueryResult_pageInfo(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "FhirGraphQueryResult", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_FhirGraphPageInfo(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _DataframeRowConnection_materialization(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRowConnection) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphQueryResult_diagnostics(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRowConnection_materialization(ctx, field) + return ec.fieldContext_FhirGraphQueryResult_diagnostics(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Materialization, nil + return obj.Diagnostics, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeMaterialization) graphql.Marshaler { - return ec.marshalNDataframeMaterialization2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeMaterialization(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeQueryDiagnostics) graphql.Marshaler { + return ec.marshalNDataframeQueryDiagnostics2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeQueryDiagnostics(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRowConnection_materialization(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_FhirGraphQueryResult_diagnostics(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "DataframeRowConnection", + Object: "FhirGraphQueryResult", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeMaterialization(ctx, field) + return ec.childFields_DataframeQueryDiagnostics(ctx, field) }, } return fc, nil } -func (ec *executionContext) _DataframeRowConnection_columns(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRowConnection) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphRelationship_alias(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphRelationship) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRowConnection_columns(ctx, field) + return ec.fieldContext_FhirGraphRelationship_alias(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Columns, nil + return obj.Alias, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { - return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRowConnection_columns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRowConnection", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_FhirGraphRelationship_alias(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirGraphRelationship", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRowConnection_rows(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRowConnection) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphRelationship_label(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphRelationship) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRowConnection_rows(ctx, field) + return ec.fieldContext_FhirGraphRelationship_label(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Rows, nil + return obj.Label, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v json.RawMessage) graphql.Marshaler { - return ec.marshalNJSON2encodingᚋjsonᚐRawMessage(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRowConnection_rows(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRowConnection", field, false, false, errors.New("field of type JSON does not have child fields")) +func (ec *executionContext) fieldContext_FhirGraphRelationship_label(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirGraphRelationship", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRowConnection_totalCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRowConnection) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphRelationship_fromResourceType(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphRelationship) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRowConnection_totalCount(ctx, field) + return ec.fieldContext_FhirGraphRelationship_fromResourceType(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.TotalCount, nil + return obj.FromResourceType, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *int) graphql.Marshaler { - return ec.marshalOInt2ᚖint(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_DataframeRowConnection_totalCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeRowConnection", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_FhirGraphRelationship_fromResourceType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirGraphRelationship", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeRowConnection_pageInfo(ctx context.Context, field graphql.CollectedField, obj *model.DataframeRowConnection) (ret graphql.Marshaler) { +func (ec *executionContext) _FhirGraphRelationship_toResourceType(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphRelationship) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeRowConnection_pageInfo(ctx, field) + return ec.fieldContext_FhirGraphRelationship_toResourceType(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.PageInfo, nil + return obj.ToResourceType, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframePageInfo) graphql.Marshaler { - return ec.marshalNDataframePageInfo2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframePageInfo(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeRowConnection_pageInfo(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "DataframeRowConnection", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframePageInfo(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_FhirGraphRelationship_toResourceType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("FhirGraphRelationship", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _DataframeSelector_recipe(ctx context.Context, field graphql.CollectedField, obj *model.DataframeSelector) (ret graphql.Marshaler) { +func (ec *executionContext) _Mutation_runFhirDataframe(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeSelector_recipe(ctx, field) + return ec.fieldContext_Mutation_runFhirDataframe(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Recipe, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Mutation().RunFhirDataframe(ctx, fc.Args["input"].(model.FhirDataframeInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.FhirDataframeResult) graphql.Marshaler { + return ec.marshalNFhirDataframeResult2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirDataframeResult(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeSelector_recipe(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeSelector", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_Mutation_runFhirDataframe(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_FhirDataframeResult(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_runFhirDataframe_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _DataframeSelector_translationVersion(ctx context.Context, field graphql.CollectedField, obj *model.DataframeSelector) (ret graphql.Marshaler) { +func (ec *executionContext) _Mutation_runDataframeRecipe(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeSelector_translationVersion(ctx, field) + return ec.fieldContext_Mutation_runDataframeRecipe(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.TranslationVersion, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Mutation().RunDataframeRecipe(ctx, fc.Args["input"].(model.RunDataframeRecipeInput)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeResult) graphql.Marshaler { + return ec.marshalNDataframeRecipeResult2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeResult(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeSelector_translationVersion(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeSelector", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_Mutation_runDataframeRecipe(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipeResult(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_runDataframeRecipe_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _DataframeSelector_output(ctx context.Context, field graphql.CollectedField, obj *model.DataframeSelector) (ret graphql.Marshaler) { +func (ec *executionContext) _Mutation_validateDataframeRecipe(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeSelector_output(ctx, field) + return ec.fieldContext_Mutation_validateDataframeRecipe(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Output, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Mutation().ValidateDataframeRecipe(ctx, fc.Args["input"].(model.ValidateDataframeRecipeInput)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeValidation) graphql.Marshaler { + return ec.marshalNDataframeRecipeValidation2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeValidation(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeSelector_output(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeSelector", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_Mutation_validateDataframeRecipe(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipeValidation(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_validateDataframeRecipe_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _DataframeTraversalHint_fromType(ctx context.Context, field graphql.CollectedField, obj *model.DataframeTraversalHint) (ret graphql.Marshaler) { +func (ec *executionContext) _Mutation_previewDataframeRecipe(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeTraversalHint_fromType(ctx, field) + return ec.fieldContext_Mutation_previewDataframeRecipe(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.FromType, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Mutation().PreviewDataframeRecipe(ctx, fc.Args["input"].(model.PreviewDataframeRecipeInput)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipePreview) graphql.Marshaler { + return ec.marshalNDataframeRecipePreview2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipePreview(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeTraversalHint_fromType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeTraversalHint", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_Mutation_previewDataframeRecipe(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipePreview(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_previewDataframeRecipe_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _DataframeTraversalHint_label(ctx context.Context, field graphql.CollectedField, obj *model.DataframeTraversalHint) (ret graphql.Marshaler) { +func (ec *executionContext) _Mutation_materializeDataframeRecipeBundle(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeTraversalHint_label(ctx, field) + return ec.fieldContext_Mutation_materializeDataframeRecipeBundle(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Label, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Mutation().MaterializeDataframeRecipeBundle(ctx, fc.Args["input"].(model.MaterializeDataframeRecipeInput)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeExecution) graphql.Marshaler { + return ec.marshalNDataframeRecipeExecution2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExecution(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeTraversalHint_label(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeTraversalHint", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_Mutation_materializeDataframeRecipeBundle(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipeExecution(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_materializeDataframeRecipeBundle_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _DataframeTraversalHint_toType(ctx context.Context, field graphql.CollectedField, obj *model.DataframeTraversalHint) (ret graphql.Marshaler) { +func (ec *executionContext) _Mutation_startDataframeMaterialization(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeTraversalHint_toType(ctx, field) + return ec.fieldContext_Mutation_startDataframeMaterialization(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ToType, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Mutation().StartDataframeMaterialization(ctx, fc.Args["input"].(model.StartDataframeMaterializationInput)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeExecution) graphql.Marshaler { + return ec.marshalNDataframeRecipeExecution2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExecution(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeTraversalHint_toType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeTraversalHint", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_Mutation_startDataframeMaterialization(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipeExecution(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_startDataframeMaterialization_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _DataframeTraversalHint_edgeCount(ctx context.Context, field graphql.CollectedField, obj *model.DataframeTraversalHint) (ret graphql.Marshaler) { +func (ec *executionContext) _Mutation_activateProjectRelease(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_DataframeTraversalHint_edgeCount(ctx, field) + return ec.fieldContext_Mutation_activateProjectRelease(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.EdgeCount, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Mutation().ActivateProjectRelease(ctx, fc.Args["input"].(model.ActivateProjectReleaseInput)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.ProjectRelease) graphql.Marshaler { + return ec.marshalNProjectRelease2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐProjectRelease(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_DataframeTraversalHint_edgeCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("DataframeTraversalHint", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_Mutation_activateProjectRelease(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_ProjectRelease(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_activateProjectRelease_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _FhirDataframeResult_columns(ctx context.Context, field graphql.CollectedField, obj *model.FhirDataframeResult) (ret graphql.Marshaler) { +func (ec *executionContext) _Mutation_registerDataframeRecipeRevision(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirDataframeResult_columns(ctx, field) + return ec.fieldContext_Mutation_registerDataframeRecipeRevision(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Columns, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Mutation().RegisterDataframeRecipeRevision(ctx, fc.Args["input"].(model.RegisterDataframeRecipeRevisionInput)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []string) graphql.Marshaler { - return ec.marshalNString2ᚕstringᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeRevision) graphql.Marshaler { + return ec.marshalNDataframeRecipeRevision2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeRevision(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirDataframeResult_columns(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirDataframeResult", field, false, false, errors.New("field of type String does not have child fields")) -} - -func (ec *executionContext) _FhirDataframeResult_rows(ctx context.Context, field graphql.CollectedField, obj *model.FhirDataframeResult) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirDataframeResult_rows(ctx, field) - }, - func(ctx context.Context) (any, error) { - return obj.Rows, nil - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v json.RawMessage) graphql.Marshaler { - return ec.marshalNJSON2encodingᚋjsonᚐRawMessage(ctx, selections, v) +func (ec *executionContext) fieldContext_Mutation_registerDataframeRecipeRevision(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipeRevision(ctx, field) }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_FhirDataframeResult_rows(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirDataframeResult", field, false, false, errors.New("field of type JSON does not have child fields")) + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_registerDataframeRecipeRevision_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _FhirDataframeResult_rowCount(ctx context.Context, field graphql.CollectedField, obj *model.FhirDataframeResult) (ret graphql.Marshaler) { +func (ec *executionContext) _ProjectRelease_id(ctx context.Context, field graphql.CollectedField, obj *model.ProjectRelease) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirDataframeResult_rowCount(ctx, field) + return ec.fieldContext_ProjectRelease_id(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RowCount, nil + return obj.ID, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNID2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirDataframeResult_rowCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirDataframeResult", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_ProjectRelease_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("ProjectRelease", field, false, false, errors.New("field of type ID does not have child fields")) } -func (ec *executionContext) _FhirDataframeResult_diagnostics(ctx context.Context, field graphql.CollectedField, obj *model.FhirDataframeResult) (ret graphql.Marshaler) { +func (ec *executionContext) _ProjectRelease_project(ctx context.Context, field graphql.CollectedField, obj *model.ProjectRelease) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirDataframeResult_diagnostics(ctx, field) + return ec.fieldContext_ProjectRelease_project(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Diagnostics, nil + return obj.Project, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeQueryDiagnostics) graphql.Marshaler { - return ec.marshalNDataframeQueryDiagnostics2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeQueryDiagnostics(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { + return ec.marshalNString2string(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirDataframeResult_diagnostics(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "FhirDataframeResult", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeQueryDiagnostics(ctx, field) - }, - } - return fc, nil +func (ec *executionContext) fieldContext_ProjectRelease_project(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("ProjectRelease", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _FhirGraphNode_alias(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphNode) (ret graphql.Marshaler) { +func (ec *executionContext) _ProjectRelease_generation(ctx context.Context, field graphql.CollectedField, obj *model.ProjectRelease) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphNode_alias(ctx, field) + return ec.fieldContext_ProjectRelease_generation(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Alias, nil + return obj.Generation, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -7797,20 +7604,20 @@ func (ec *executionContext) _FhirGraphNode_alias(ctx context.Context, field grap true, ) } -func (ec *executionContext) fieldContext_FhirGraphNode_alias(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirGraphNode", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_ProjectRelease_generation(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("ProjectRelease", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _FhirGraphNode_resourceType(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphNode) (ret graphql.Marshaler) { +func (ec *executionContext) _ProjectRelease_revision(ctx context.Context, field graphql.CollectedField, obj *model.ProjectRelease) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphNode_resourceType(ctx, field) + return ec.fieldContext_ProjectRelease_revision(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ResourceType, nil + return obj.Revision, nil }, nil, func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { @@ -7820,598 +7627,973 @@ func (ec *executionContext) _FhirGraphNode_resourceType(ctx context.Context, fie true, ) } -func (ec *executionContext) fieldContext_FhirGraphNode_resourceType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirGraphNode", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_ProjectRelease_revision(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("ProjectRelease", field, false, false, errors.New("field of type String does not have child fields")) } -func (ec *executionContext) _FhirGraphNode_id(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphNode) (ret graphql.Marshaler) { +func (ec *executionContext) _ProjectRelease_state(ctx context.Context, field graphql.CollectedField, obj *model.ProjectRelease) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphNode_id(ctx, field) + return ec.fieldContext_ProjectRelease_state(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ID, nil + return obj.State, nil }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNID2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v model.ProjectReleaseState) graphql.Marshaler { + return ec.marshalNProjectReleaseState2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐProjectReleaseState(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirGraphNode_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirGraphNode", field, false, false, errors.New("field of type ID does not have child fields")) +func (ec *executionContext) fieldContext_ProjectRelease_state(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + return graphql.NewScalarFieldContext("ProjectRelease", field, false, false, errors.New("field of type ProjectReleaseState does not have child fields")) } -func (ec *executionContext) _FhirGraphNode_resource(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphNode) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_dataframeDatasets(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphNode_resource(ctx, field) + return ec.fieldContext_Query_dataframeDatasets(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Resource, nil + return ec.Resolvers.Query().DataframeDatasets(ctx) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v json.RawMessage) graphql.Marshaler { - return ec.marshalNJSON2encodingᚋjsonᚐRawMessage(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeMaterialization) graphql.Marshaler { + return ec.marshalNDataframeMaterialization2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeMaterializationᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirGraphNode_resource(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirGraphNode", field, false, false, errors.New("field of type JSON does not have child fields")) +func (ec *executionContext) fieldContext_Query_dataframeDatasets(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeMaterialization(ctx, field) + }, + } + return fc, nil } -func (ec *executionContext) _FhirGraphPageInfo_hasMore(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphPageInfo) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_projectDataframeDatasets(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphPageInfo_hasMore(ctx, field) + return ec.fieldContext_Query_projectDataframeDatasets(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.HasMore, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().ProjectDataframeDatasets(ctx, fc.Args["projectId"].(string)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { - return ec.marshalNBoolean2bool(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeMaterialization) graphql.Marshaler { + return ec.marshalNDataframeMaterialization2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeMaterializationᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirGraphPageInfo_hasMore(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirGraphPageInfo", field, false, false, errors.New("field of type Boolean does not have child fields")) +func (ec *executionContext) fieldContext_Query_projectDataframeDatasets(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeMaterialization(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_projectDataframeDatasets_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _FhirGraphPath_terminalAlias(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphPath) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_dataframeDataset(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphPath_terminalAlias(ctx, field) + return ec.fieldContext_Query_dataframeDataset(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.TerminalAlias, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().DataframeDataset(ctx, fc.Args["input"].(model.DataframeDatasetInput)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeMaterialization) graphql.Marshaler { + return ec.marshalODataframeMaterialization2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeMaterialization(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_FhirGraphPath_terminalAlias(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirGraphPath", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_Query_dataframeDataset(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeMaterialization(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_dataframeDataset_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _FhirGraphPath_nodes(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphPath) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_dataframeRows(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphPath_nodes(ctx, field) + return ec.fieldContext_Query_dataframeRows(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Nodes, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().DataframeRows(ctx, fc.Args["input"].(model.DataframeRowsInput)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.FhirGraphNode) graphql.Marshaler { - return ec.marshalNFhirGraphNode2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirGraphNodeᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRowConnection) graphql.Marshaler { + return ec.marshalNDataframeRowConnection2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRowConnection(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirGraphPath_nodes(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_dataframeRows(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "FhirGraphPath", + Object: "Query", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_FhirGraphNode(ctx, field) + return ec.childFields_DataframeRowConnection(ctx, field) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_dataframeRows_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } -func (ec *executionContext) _FhirGraphPath_relationships(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphPath) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_dataframeAggregate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphPath_relationships(ctx, field) + return ec.fieldContext_Query_dataframeAggregate(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Relationships, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().DataframeAggregate(ctx, fc.Args["input"].(model.DataframeAggregateInput)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.FhirGraphRelationship) graphql.Marshaler { - return ec.marshalNFhirGraphRelationship2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirGraphRelationshipᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeAggregateResult) graphql.Marshaler { + return ec.marshalNDataframeAggregateResult2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeAggregateResult(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirGraphPath_relationships(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_dataframeAggregate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "FhirGraphPath", + Object: "Query", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_FhirGraphRelationship(ctx, field) + return ec.childFields_DataframeAggregateResult(ctx, field) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_dataframeAggregate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } -func (ec *executionContext) _FhirGraphQueryExplanation_sourceGeneration(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_dataframeAggregations(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphQueryExplanation_sourceGeneration(ctx, field) + return ec.fieldContext_Query_dataframeAggregations(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.SourceGeneration, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().DataframeAggregations(ctx, fc.Args["input"].(model.DataframeAggregationsInput)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNID2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeAggregationsResult) graphql.Marshaler { + return ec.marshalNDataframeAggregationsResult2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeAggregationsResult(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirGraphQueryExplanation_sourceGeneration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirGraphQueryExplanation", field, false, false, errors.New("field of type ID does not have child fields")) +func (ec *executionContext) fieldContext_Query_dataframeAggregations(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeAggregationsResult(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_dataframeAggregations_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _FhirGraphQueryExplanation_rootResourceType(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_dataframeRecipeExecution(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphQueryExplanation_rootResourceType(ctx, field) + return ec.fieldContext_Query_dataframeRecipeExecution(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.RootResourceType, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().DataframeRecipeExecution(ctx, fc.Args["id"].(string)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeExecution) graphql.Marshaler { + return ec.marshalODataframeRecipeExecution2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExecution(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_FhirGraphQueryExplanation_rootResourceType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirGraphQueryExplanation", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_Query_dataframeRecipeExecution(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipeExecution(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_dataframeRecipeExecution_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _FhirGraphQueryExplanation_traversalCount(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_dataframeRecipeRevision(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphQueryExplanation_traversalCount(ctx, field) + return ec.fieldContext_Query_dataframeRecipeRevision(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.TraversalCount, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().DataframeRecipeRevision(ctx, fc.Args["projectId"].(string), fc.Args["name"].(string), fc.Args["digest"].(string)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeRevision) graphql.Marshaler { + return ec.marshalODataframeRecipeRevision2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeRevision(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_FhirGraphQueryExplanation_traversalCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirGraphQueryExplanation", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_Query_dataframeRecipeRevision(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipeRevision(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_dataframeRecipeRevision_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _FhirGraphQueryExplanation_maxDepth(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_dataframeRecipeRevisions(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphQueryExplanation_maxDepth(ctx, field) + return ec.fieldContext_Query_dataframeRecipeRevisions(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.MaxDepth, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().DataframeRecipeRevisions(ctx, fc.Args["projectId"].(string), fc.Args["name"].(string)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeRevision) graphql.Marshaler { + return ec.marshalNDataframeRecipeRevision2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeRevisionᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirGraphQueryExplanation_maxDepth(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirGraphQueryExplanation", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_Query_dataframeRecipeRevisions(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipeRevision(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_dataframeRecipeRevisions_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _FhirGraphQueryExplanation_limit(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_explainDataframeRecipe(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphQueryExplanation_limit(ctx, field) + return ec.fieldContext_Query_explainDataframeRecipe(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Limit, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().ExplainDataframeRecipe(ctx, fc.Args["input"].(model.ExplainDataframeRecipeInput)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeExplanation) graphql.Marshaler { + return ec.marshalNDataframeRecipeExplanation2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExplanation(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirGraphQueryExplanation_limit(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirGraphQueryExplanation", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_Query_explainDataframeRecipe(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipeExplanation(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_explainDataframeRecipe_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _FhirGraphQueryExplanation_live(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_preflightDataframeRecipe(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphQueryExplanation_live(ctx, field) + return ec.fieldContext_Query_preflightDataframeRecipe(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Live, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().PreflightDataframeRecipe(ctx, fc.Args["input"].(model.PreflightDataframeRecipeInput)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v bool) graphql.Marshaler { - return ec.marshalNBoolean2bool(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipePreflight) graphql.Marshaler { + return ec.marshalNDataframeRecipePreflight2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipePreflight(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirGraphQueryExplanation_live(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirGraphQueryExplanation", field, false, false, errors.New("field of type Boolean does not have child fields")) +func (ec *executionContext) fieldContext_Query_preflightDataframeRecipe(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_DataframeRecipePreflight(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_preflightDataframeRecipe_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _FhirGraphQueryExplanation_diagnostics(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryExplanation) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_fhirGraph(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphQueryExplanation_diagnostics(ctx, field) + return ec.fieldContext_Query_fhirGraph(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Diagnostics, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().FhirGraph(ctx, fc.Args["input"].(model.FhirGraphQueryInput)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeQueryDiagnostics) graphql.Marshaler { - return ec.marshalODataframeQueryDiagnostics2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeQueryDiagnostics(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.FhirGraphQueryResult) graphql.Marshaler { + return ec.marshalNFhirGraphQueryResult2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirGraphQueryResult(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_FhirGraphQueryExplanation_diagnostics(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_fhirGraph(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "FhirGraphQueryExplanation", + Object: "Query", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeQueryDiagnostics(ctx, field) + return ec.childFields_FhirGraphQueryResult(ctx, field) }, } - return fc, nil -} - -func (ec *executionContext) _FhirGraphQueryResult_sourceGeneration(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryResult) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_fhirGraph_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_explainFhirGraph(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphQueryResult_sourceGeneration(ctx, field) + return ec.fieldContext_Query_explainFhirGraph(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.SourceGeneration, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().ExplainFhirGraph(ctx, fc.Args["input"].(model.FhirGraphQueryInput), fc.Args["live"].(*bool)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNID2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *model.FhirGraphQueryExplanation) graphql.Marshaler { + return ec.marshalNFhirGraphQueryExplanation2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirGraphQueryExplanation(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirGraphQueryResult_sourceGeneration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirGraphQueryResult", field, false, false, errors.New("field of type ID does not have child fields")) +func (ec *executionContext) fieldContext_Query_explainFhirGraph(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_FhirGraphQueryExplanation(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_explainFhirGraph_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _FhirGraphQueryResult_paths(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryResult) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_BodyStructure(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphQueryResult_paths(ctx, field) + return ec.fieldContext_Query_BodyStructure(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Paths, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().BodyStructure(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.FhirGraphPath) graphql.Marshaler { - return ec.marshalNFhirGraphPath2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirGraphPathᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.BodyStructure) graphql.Marshaler { + return ec.marshalNBodyStructure2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐBodyStructureᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirGraphQueryResult_paths(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_BodyStructure(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "FhirGraphQueryResult", + Object: "Query", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_FhirGraphPath(ctx, field) + return ec.childFields_BodyStructure(ctx, field) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_BodyStructure_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } -func (ec *executionContext) _FhirGraphQueryResult_returnedCount(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryResult) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_Condition(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphQueryResult_returnedCount(ctx, field) + return ec.fieldContext_Query_Condition(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ReturnedCount, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().Condition(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v int) graphql.Marshaler { - return ec.marshalNInt2int(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Condition) graphql.Marshaler { + return ec.marshalNCondition2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐConditionᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirGraphQueryResult_returnedCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirGraphQueryResult", field, false, false, errors.New("field of type Int does not have child fields")) +func (ec *executionContext) fieldContext_Query_Condition(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_Condition(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_Condition_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _FhirGraphQueryResult_pageInfo(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryResult) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_DiagnosticReport(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphQueryResult_pageInfo(ctx, field) + return ec.fieldContext_Query_DiagnosticReport(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.PageInfo, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().DiagnosticReport(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.FhirGraphPageInfo) graphql.Marshaler { - return ec.marshalNFhirGraphPageInfo2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirGraphPageInfo(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.DiagnosticReport) graphql.Marshaler { + return ec.marshalNDiagnosticReport2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐDiagnosticReportᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirGraphQueryResult_pageInfo(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_DiagnosticReport(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "FhirGraphQueryResult", + Object: "Query", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_FhirGraphPageInfo(ctx, field) + return ec.childFields_DiagnosticReport(ctx, field) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_DiagnosticReport_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } -func (ec *executionContext) _FhirGraphQueryResult_diagnostics(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphQueryResult) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_DocumentReference(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphQueryResult_diagnostics(ctx, field) + return ec.fieldContext_Query_DocumentReference(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Diagnostics, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().DocumentReference(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeQueryDiagnostics) graphql.Marshaler { - return ec.marshalNDataframeQueryDiagnostics2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeQueryDiagnostics(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.DocumentReference) graphql.Marshaler { + return ec.marshalNDocumentReference2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐDocumentReferenceᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirGraphQueryResult_diagnostics(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_DocumentReference(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "FhirGraphQueryResult", + Object: "Query", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeQueryDiagnostics(ctx, field) + return ec.childFields_DocumentReference(ctx, field) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_DocumentReference_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } -func (ec *executionContext) _FhirGraphRelationship_alias(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphRelationship) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_FamilyMemberHistory(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphRelationship_alias(ctx, field) + return ec.fieldContext_Query_FamilyMemberHistory(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Alias, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().FamilyMemberHistory(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.FamilyMemberHistory) graphql.Marshaler { + return ec.marshalNFamilyMemberHistory2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐFamilyMemberHistoryᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirGraphRelationship_alias(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirGraphRelationship", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_Query_FamilyMemberHistory(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_FamilyMemberHistory(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_FamilyMemberHistory_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _FhirGraphRelationship_label(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphRelationship) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_Group(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphRelationship_label(ctx, field) + return ec.fieldContext_Query_Group(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.Label, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().Group(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Group) graphql.Marshaler { + return ec.marshalNGroup2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐGroupᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirGraphRelationship_label(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirGraphRelationship", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_Query_Group(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_Group(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_Group_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _FhirGraphRelationship_fromResourceType(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphRelationship) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_ImagingStudy(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphRelationship_fromResourceType(ctx, field) + return ec.fieldContext_Query_ImagingStudy(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.FromResourceType, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().ImagingStudy(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.ImagingStudy) graphql.Marshaler { + return ec.marshalNImagingStudy2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐImagingStudyᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirGraphRelationship_fromResourceType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirGraphRelationship", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_Query_ImagingStudy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_ImagingStudy(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_ImagingStudy_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _FhirGraphRelationship_toResourceType(ctx context.Context, field graphql.CollectedField, obj *model.FhirGraphRelationship) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_Medication(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_FhirGraphRelationship_toResourceType(ctx, field) + return ec.fieldContext_Query_Medication(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ToResourceType, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().Medication(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Medication) graphql.Marshaler { + return ec.marshalNMedication2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐMedicationᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_FhirGraphRelationship_toResourceType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("FhirGraphRelationship", field, false, false, errors.New("field of type String does not have child fields")) +func (ec *executionContext) fieldContext_Query_Medication(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_Medication(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_Medication_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _Mutation_runFhirDataframe(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_MedicationAdministration(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Mutation_runFhirDataframe(ctx, field) + return ec.fieldContext_Query_MedicationAdministration(ctx, field) }, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Mutation().RunFhirDataframe(ctx, fc.Args["input"].(model.FhirDataframeInput), fc.Args["limit"].(*int)) + return ec.Resolvers.Query().MedicationAdministration(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.FhirDataframeResult) graphql.Marshaler { - return ec.marshalNFhirDataframeResult2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirDataframeResult(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.MedicationAdministration) graphql.Marshaler { + return ec.marshalNMedicationAdministration2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐMedicationAdministrationᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_Mutation_runFhirDataframe(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_MedicationAdministration(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Mutation", + Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_FhirDataframeResult(ctx, field) + return ec.childFields_MedicationAdministration(ctx, field) }, } defer func() { @@ -8421,41 +8603,41 @@ func (ec *executionContext) fieldContext_Mutation_runFhirDataframe(ctx context.C } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_runFhirDataframe_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_MedicationAdministration_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Mutation_runDataframeRecipe(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_MedicationRequest(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Mutation_runDataframeRecipe(ctx, field) + return ec.fieldContext_Query_MedicationRequest(ctx, field) }, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Mutation().RunDataframeRecipe(ctx, fc.Args["input"].(model.RunDataframeRecipeInput)) + return ec.Resolvers.Query().MedicationRequest(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeResult) graphql.Marshaler { - return ec.marshalNDataframeRecipeResult2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeResult(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.MedicationRequest) graphql.Marshaler { + return ec.marshalNMedicationRequest2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐMedicationRequestᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_Mutation_runDataframeRecipe(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_MedicationRequest(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Mutation", + Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeResult(ctx, field) + return ec.childFields_MedicationRequest(ctx, field) }, } defer func() { @@ -8465,41 +8647,41 @@ func (ec *executionContext) fieldContext_Mutation_runDataframeRecipe(ctx context } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_runDataframeRecipe_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_MedicationRequest_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Mutation_validateDataframeRecipe(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_MedicationStatement(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Mutation_validateDataframeRecipe(ctx, field) + return ec.fieldContext_Query_MedicationStatement(ctx, field) }, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Mutation().ValidateDataframeRecipe(ctx, fc.Args["input"].(model.ValidateDataframeRecipeInput)) + return ec.Resolvers.Query().MedicationStatement(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeValidation) graphql.Marshaler { - return ec.marshalNDataframeRecipeValidation2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeValidation(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.MedicationStatement) graphql.Marshaler { + return ec.marshalNMedicationStatement2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐMedicationStatementᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_Mutation_validateDataframeRecipe(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_MedicationStatement(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Mutation", + Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeValidation(ctx, field) + return ec.childFields_MedicationStatement(ctx, field) }, } defer func() { @@ -8509,41 +8691,41 @@ func (ec *executionContext) fieldContext_Mutation_validateDataframeRecipe(ctx co } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_validateDataframeRecipe_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_MedicationStatement_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Mutation_previewDataframeRecipe(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_Observation(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Mutation_previewDataframeRecipe(ctx, field) + return ec.fieldContext_Query_Observation(ctx, field) }, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Mutation().PreviewDataframeRecipe(ctx, fc.Args["input"].(model.PreviewDataframeRecipeInput)) + return ec.Resolvers.Query().Observation(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipePreview) graphql.Marshaler { - return ec.marshalNDataframeRecipePreview2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipePreview(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Observation) graphql.Marshaler { + return ec.marshalNObservation2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐObservationᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_Mutation_previewDataframeRecipe(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_Observation(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Mutation", + Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipePreview(ctx, field) + return ec.childFields_Observation(ctx, field) }, } defer func() { @@ -8553,41 +8735,41 @@ func (ec *executionContext) fieldContext_Mutation_previewDataframeRecipe(ctx con } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_previewDataframeRecipe_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_Observation_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Mutation_materializeDataframeRecipeBundle(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_Organization(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Mutation_materializeDataframeRecipeBundle(ctx, field) + return ec.fieldContext_Query_Organization(ctx, field) }, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Mutation().MaterializeDataframeRecipeBundle(ctx, fc.Args["input"].(model.MaterializeDataframeRecipeInput)) + return ec.Resolvers.Query().Organization(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeExecution) graphql.Marshaler { - return ec.marshalNDataframeRecipeExecution2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExecution(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Organization) graphql.Marshaler { + return ec.marshalNOrganization2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐOrganizationᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_Mutation_materializeDataframeRecipeBundle(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_Organization(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Mutation", + Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeExecution(ctx, field) + return ec.childFields_Organization(ctx, field) }, } defer func() { @@ -8597,41 +8779,41 @@ func (ec *executionContext) fieldContext_Mutation_materializeDataframeRecipeBund } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_materializeDataframeRecipeBundle_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_Organization_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Mutation_startDataframeMaterialization(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_Patient(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Mutation_startDataframeMaterialization(ctx, field) + return ec.fieldContext_Query_Patient(ctx, field) }, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Mutation().StartDataframeMaterialization(ctx, fc.Args["input"].(model.StartDataframeMaterializationInput)) + return ec.Resolvers.Query().Patient(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeExecution) graphql.Marshaler { - return ec.marshalNDataframeRecipeExecution2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExecution(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Patient) graphql.Marshaler { + return ec.marshalNPatient2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐPatientᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_Mutation_startDataframeMaterialization(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_Patient(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Mutation", + Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeExecution(ctx, field) + return ec.childFields_Patient(ctx, field) }, } defer func() { @@ -8641,41 +8823,41 @@ func (ec *executionContext) fieldContext_Mutation_startDataframeMaterialization( } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_startDataframeMaterialization_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_Patient_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Mutation_activateProjectRelease(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_Practitioner(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Mutation_activateProjectRelease(ctx, field) + return ec.fieldContext_Query_Practitioner(ctx, field) }, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Mutation().ActivateProjectRelease(ctx, fc.Args["input"].(model.ActivateProjectReleaseInput)) + return ec.Resolvers.Query().Practitioner(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.ProjectRelease) graphql.Marshaler { - return ec.marshalNProjectRelease2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐProjectRelease(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Practitioner) graphql.Marshaler { + return ec.marshalNPractitioner2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐPractitionerᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_Mutation_activateProjectRelease(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_Practitioner(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Mutation", + Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_ProjectRelease(ctx, field) + return ec.childFields_Practitioner(ctx, field) }, } defer func() { @@ -8685,41 +8867,41 @@ func (ec *executionContext) fieldContext_Mutation_activateProjectRelease(ctx con } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_activateProjectRelease_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_Practitioner_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Mutation_promoteDataframeContract(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_PractitionerRole(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Mutation_promoteDataframeContract(ctx, field) + return ec.fieldContext_Query_PractitionerRole(ctx, field) }, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Mutation().PromoteDataframeContract(ctx, fc.Args["input"].(model.PromoteDataframeContractInput)) + return ec.Resolvers.Query().PractitionerRole(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeContract) graphql.Marshaler { - return ec.marshalNDataframeContract2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeContract(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.PractitionerRole) graphql.Marshaler { + return ec.marshalNPractitionerRole2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐPractitionerRoleᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_Mutation_promoteDataframeContract(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_PractitionerRole(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Mutation", + Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeContract(ctx, field) + return ec.childFields_PractitionerRole(ctx, field) }, } defer func() { @@ -8729,41 +8911,41 @@ func (ec *executionContext) fieldContext_Mutation_promoteDataframeContract(ctx c } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_promoteDataframeContract_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_PractitionerRole_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Mutation_registerDataframeRecipeRevision(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_Procedure(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Mutation_registerDataframeRecipeRevision(ctx, field) + return ec.fieldContext_Query_Procedure(ctx, field) }, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Mutation().RegisterDataframeRecipeRevision(ctx, fc.Args["input"].(model.RegisterDataframeRecipeRevisionInput)) + return ec.Resolvers.Query().Procedure(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeRevision) graphql.Marshaler { - return ec.marshalNDataframeRecipeRevision2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeRevision(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Procedure) graphql.Marshaler { + return ec.marshalNProcedure2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐProcedureᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_Mutation_registerDataframeRecipeRevision(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_Procedure(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Mutation", + Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeRevision(ctx, field) + return ec.childFields_Procedure(ctx, field) }, } defer func() { @@ -8773,156 +8955,85 @@ func (ec *executionContext) fieldContext_Mutation_registerDataframeRecipeRevisio } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_registerDataframeRecipeRevision_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_Procedure_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _ProjectRelease_id(ctx context.Context, field graphql.CollectedField, obj *model.ProjectRelease) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_ResearchStudy(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_ProjectRelease_id(ctx, field) + return ec.fieldContext_Query_ResearchStudy(ctx, field) }, func(ctx context.Context) (any, error) { - return obj.ID, nil + fc := graphql.GetFieldContext(ctx) + return ec.Resolvers.Query().ResearchStudy(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNID2string(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.ResearchStudy) graphql.Marshaler { + return ec.marshalNResearchStudy2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐResearchStudyᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_ProjectRelease_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("ProjectRelease", field, false, false, errors.New("field of type ID does not have child fields")) +func (ec *executionContext) fieldContext_Query_ResearchStudy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return ec.childFields_ResearchStudy(ctx, field) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_ResearchStudy_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil } -func (ec *executionContext) _ProjectRelease_project(ctx context.Context, field graphql.CollectedField, obj *model.ProjectRelease) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_ProjectRelease_project(ctx, field) - }, - func(ctx context.Context) (any, error) { - return obj.Project, nil - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_ProjectRelease_project(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("ProjectRelease", field, false, false, errors.New("field of type String does not have child fields")) -} - -func (ec *executionContext) _ProjectRelease_generation(ctx context.Context, field graphql.CollectedField, obj *model.ProjectRelease) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_ProjectRelease_generation(ctx, field) - }, - func(ctx context.Context) (any, error) { - return obj.Generation, nil - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_ProjectRelease_generation(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("ProjectRelease", field, false, false, errors.New("field of type String does not have child fields")) -} - -func (ec *executionContext) _ProjectRelease_revision(ctx context.Context, field graphql.CollectedField, obj *model.ProjectRelease) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_ProjectRelease_revision(ctx, field) - }, - func(ctx context.Context) (any, error) { - return obj.Revision, nil - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v string) graphql.Marshaler { - return ec.marshalNString2string(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_ProjectRelease_revision(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("ProjectRelease", field, false, false, errors.New("field of type String does not have child fields")) -} - -func (ec *executionContext) _ProjectRelease_state(ctx context.Context, field graphql.CollectedField, obj *model.ProjectRelease) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_ProjectRelease_state(ctx, field) - }, - func(ctx context.Context) (any, error) { - return obj.State, nil - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v model.ProjectReleaseState) graphql.Marshaler { - return ec.marshalNProjectReleaseState2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐProjectReleaseState(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_ProjectRelease_state(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - return graphql.NewScalarFieldContext("ProjectRelease", field, false, false, errors.New("field of type ProjectReleaseState does not have child fields")) -} - -func (ec *executionContext) _Query_dataframeBuilderIntrospection(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_ResearchSubject(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_dataframeBuilderIntrospection(ctx, field) + return ec.fieldContext_Query_ResearchSubject(ctx, field) }, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().DataframeBuilderIntrospection(ctx, fc.Args["input"].(model.DataframeBuilderIntrospectionInput)) + return ec.Resolvers.Query().ResearchSubject(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeBuilderIntrospection) graphql.Marshaler { - return ec.marshalNDataframeBuilderIntrospection2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeBuilderIntrospection(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.ResearchSubject) graphql.Marshaler { + return ec.marshalNResearchSubject2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐResearchSubjectᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_Query_dataframeBuilderIntrospection(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_ResearchSubject(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeBuilderIntrospection(ctx, field) + return ec.childFields_ResearchSubject(ctx, field) }, } defer func() { @@ -8932,41 +9043,41 @@ func (ec *executionContext) fieldContext_Query_dataframeBuilderIntrospection(ctx } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_dataframeBuilderIntrospection_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_ResearchSubject_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Query_dataframeMaterialization(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_Specimen(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_dataframeMaterialization(ctx, field) + return ec.fieldContext_Query_Specimen(ctx, field) }, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().DataframeMaterialization(ctx, fc.Args["id"].(string)) + return ec.Resolvers.Query().Specimen(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeMaterialization) graphql.Marshaler { - return ec.marshalODataframeMaterialization2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeMaterialization(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Specimen) graphql.Marshaler { + return ec.marshalNSpecimen2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐSpecimenᚄ(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_Query_dataframeMaterialization(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_Specimen(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeMaterialization(ctx, field) + return ec.childFields_Specimen(ctx, field) }, } defer func() { @@ -8976,73 +9087,41 @@ func (ec *executionContext) fieldContext_Query_dataframeMaterialization(ctx cont } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_dataframeMaterialization_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_Specimen_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Query_dataframeDatasets(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_dataframeDatasets(ctx, field) - }, - func(ctx context.Context) (any, error) { - return ec.Resolvers.Query().DataframeDatasets(ctx) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeMaterialization) graphql.Marshaler { - return ec.marshalNDataframeMaterialization2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeMaterializationᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_dataframeDatasets(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeMaterialization(ctx, field) - }, - } - return fc, nil -} - -func (ec *executionContext) _Query_projectDataframeDatasets(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_Substance(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_projectDataframeDatasets(ctx, field) + return ec.fieldContext_Query_Substance(ctx, field) }, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().ProjectDataframeDatasets(ctx, fc.Args["projectId"].(string)) + return ec.Resolvers.Query().Substance(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeMaterialization) graphql.Marshaler { - return ec.marshalNDataframeMaterialization2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeMaterializationᚄ(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Substance) graphql.Marshaler { + return ec.marshalNSubstance2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐSubstanceᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_Query_projectDataframeDatasets(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_Substance(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeMaterialization(ctx, field) + return ec.childFields_Substance(ctx, field) }, } defer func() { @@ -9052,41 +9131,41 @@ func (ec *executionContext) fieldContext_Query_projectDataframeDatasets(ctx cont } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_projectDataframeDatasets_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_Substance_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Query_dataframeDataset(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_SubstanceDefinition(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_dataframeDataset(ctx, field) + return ec.fieldContext_Query_SubstanceDefinition(ctx, field) }, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().DataframeDataset(ctx, fc.Args["input"].(model.DataframeDatasetInput)) + return ec.Resolvers.Query().SubstanceDefinition(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeMaterialization) graphql.Marshaler { - return ec.marshalODataframeMaterialization2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeMaterialization(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.SubstanceDefinition) graphql.Marshaler { + return ec.marshalNSubstanceDefinition2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐSubstanceDefinitionᚄ(ctx, selections, v) }, true, - false, + true, ) } -func (ec *executionContext) fieldContext_Query_dataframeDataset(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_SubstanceDefinition(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeMaterialization(ctx, field) + return ec.childFields_SubstanceDefinition(ctx, field) }, } defer func() { @@ -9096,41 +9175,41 @@ func (ec *executionContext) fieldContext_Query_dataframeDataset(ctx context.Cont } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_dataframeDataset_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_SubstanceDefinition_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Query_dataframeRows(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_Task(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_dataframeRows(ctx, field) + return ec.fieldContext_Query_Task(ctx, field) }, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().DataframeRows(ctx, fc.Args["input"].(model.DataframeRowsInput)) + return ec.Resolvers.Query().Task(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRowConnection) graphql.Marshaler { - return ec.marshalNDataframeRowConnection2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRowConnection(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Task) graphql.Marshaler { + return ec.marshalNTask2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐTaskᚄ(ctx, selections, v) }, true, true, ) } -func (ec *executionContext) fieldContext_Query_dataframeRows(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_Task(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRowConnection(ctx, field) + return ec.childFields_Task(ctx, field) }, } defer func() { @@ -9140,41 +9219,41 @@ func (ec *executionContext) fieldContext_Query_dataframeRows(ctx context.Context } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_dataframeRows_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_Task_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Query_dataframeAggregate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_dataframeAggregate(ctx, field) + return ec.fieldContext_Query___type(ctx, field) }, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().DataframeAggregate(ctx, fc.Args["input"].(model.DataframeAggregateInput)) + return ec.IntrospectType(fc.Args["name"].(string)) }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeAggregateResult) graphql.Marshaler { - return ec.marshalNDataframeAggregateResult2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeAggregateResult(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *introspection.Type) graphql.Marshaler { + return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_Query_dataframeAggregate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query___type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, - IsResolver: true, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeAggregateResult(ctx, field) + return ec.childFields___Type(ctx, field) }, } defer func() { @@ -9184,1448 +9263,40 @@ func (ec *executionContext) fieldContext_Query_dataframeAggregate(ctx context.Co } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_dataframeAggregate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query___type_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Query_dataframeAggregations(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_dataframeAggregations(ctx, field) + return ec.fieldContext_Query___schema(ctx, field) }, func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().DataframeAggregations(ctx, fc.Args["input"].(model.DataframeAggregationsInput)) + return ec.IntrospectSchema() }, nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeAggregationsResult) graphql.Marshaler { - return ec.marshalNDataframeAggregationsResult2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeAggregationsResult(ctx, selections, v) + func(ctx context.Context, selections ast.SelectionSet, v *introspection.Schema) graphql.Marshaler { + return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, selections, v) }, true, - true, + false, ) } -func (ec *executionContext) fieldContext_Query_dataframeAggregations(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query___schema(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, - IsResolver: true, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeAggregationsResult(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_dataframeAggregations_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_dataframeRecipeExecution(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_dataframeRecipeExecution(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().DataframeRecipeExecution(ctx, fc.Args["id"].(string)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeExecution) graphql.Marshaler { - return ec.marshalODataframeRecipeExecution2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExecution(ctx, selections, v) - }, - true, - false, - ) -} -func (ec *executionContext) fieldContext_Query_dataframeRecipeExecution(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeExecution(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_dataframeRecipeExecution_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_dataframeRecipeRevision(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_dataframeRecipeRevision(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().DataframeRecipeRevision(ctx, fc.Args["projectId"].(string), fc.Args["name"].(string), fc.Args["digest"].(string)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeRevision) graphql.Marshaler { - return ec.marshalODataframeRecipeRevision2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeRevision(ctx, selections, v) - }, - true, - false, - ) -} -func (ec *executionContext) fieldContext_Query_dataframeRecipeRevision(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeRevision(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_dataframeRecipeRevision_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_dataframeRecipeRevisions(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_dataframeRecipeRevisions(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().DataframeRecipeRevisions(ctx, fc.Args["projectId"].(string), fc.Args["name"].(string)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*model.DataframeRecipeRevision) graphql.Marshaler { - return ec.marshalNDataframeRecipeRevision2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeRevisionᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_dataframeRecipeRevisions(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeRevision(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_dataframeRecipeRevisions_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_explainDataframeRecipe(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_explainDataframeRecipe(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().ExplainDataframeRecipe(ctx, fc.Args["input"].(model.ExplainDataframeRecipeInput)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipeExplanation) graphql.Marshaler { - return ec.marshalNDataframeRecipeExplanation2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeExplanation(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_explainDataframeRecipe(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipeExplanation(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_explainDataframeRecipe_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_preflightDataframeRecipe(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_preflightDataframeRecipe(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().PreflightDataframeRecipe(ctx, fc.Args["input"].(model.PreflightDataframeRecipeInput)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.DataframeRecipePreflight) graphql.Marshaler { - return ec.marshalNDataframeRecipePreflight2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipePreflight(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_preflightDataframeRecipe(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DataframeRecipePreflight(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_preflightDataframeRecipe_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_fhirGraph(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_fhirGraph(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().FhirGraph(ctx, fc.Args["input"].(model.FhirGraphQueryInput)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.FhirGraphQueryResult) graphql.Marshaler { - return ec.marshalNFhirGraphQueryResult2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirGraphQueryResult(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_fhirGraph(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_FhirGraphQueryResult(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_fhirGraph_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_explainFhirGraph(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_explainFhirGraph(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().ExplainFhirGraph(ctx, fc.Args["input"].(model.FhirGraphQueryInput), fc.Args["live"].(*bool)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v *model.FhirGraphQueryExplanation) graphql.Marshaler { - return ec.marshalNFhirGraphQueryExplanation2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirGraphQueryExplanation(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_explainFhirGraph(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_FhirGraphQueryExplanation(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_explainFhirGraph_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_BodyStructure(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_BodyStructure(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().BodyStructure(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.BodyStructure) graphql.Marshaler { - return ec.marshalNBodyStructure2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐBodyStructureᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_BodyStructure(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_BodyStructure(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_BodyStructure_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_Condition(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_Condition(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().Condition(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Condition) graphql.Marshaler { - return ec.marshalNCondition2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐConditionᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_Condition(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_Condition(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_Condition_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_DiagnosticReport(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_DiagnosticReport(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().DiagnosticReport(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.DiagnosticReport) graphql.Marshaler { - return ec.marshalNDiagnosticReport2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐDiagnosticReportᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_DiagnosticReport(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DiagnosticReport(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_DiagnosticReport_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_DocumentReference(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_DocumentReference(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().DocumentReference(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.DocumentReference) graphql.Marshaler { - return ec.marshalNDocumentReference2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐDocumentReferenceᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_DocumentReference(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_DocumentReference(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_DocumentReference_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_FamilyMemberHistory(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_FamilyMemberHistory(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().FamilyMemberHistory(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.FamilyMemberHistory) graphql.Marshaler { - return ec.marshalNFamilyMemberHistory2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐFamilyMemberHistoryᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_FamilyMemberHistory(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_FamilyMemberHistory(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_FamilyMemberHistory_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_Group(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_Group(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().Group(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Group) graphql.Marshaler { - return ec.marshalNGroup2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐGroupᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_Group(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_Group(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_Group_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_ImagingStudy(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_ImagingStudy(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().ImagingStudy(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.ImagingStudy) graphql.Marshaler { - return ec.marshalNImagingStudy2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐImagingStudyᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_ImagingStudy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_ImagingStudy(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_ImagingStudy_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_Medication(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_Medication(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().Medication(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Medication) graphql.Marshaler { - return ec.marshalNMedication2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐMedicationᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_Medication(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_Medication(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_Medication_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_MedicationAdministration(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_MedicationAdministration(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().MedicationAdministration(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.MedicationAdministration) graphql.Marshaler { - return ec.marshalNMedicationAdministration2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐMedicationAdministrationᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_MedicationAdministration(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_MedicationAdministration(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_MedicationAdministration_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_MedicationRequest(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_MedicationRequest(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().MedicationRequest(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.MedicationRequest) graphql.Marshaler { - return ec.marshalNMedicationRequest2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐMedicationRequestᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_MedicationRequest(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_MedicationRequest(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_MedicationRequest_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_MedicationStatement(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_MedicationStatement(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().MedicationStatement(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.MedicationStatement) graphql.Marshaler { - return ec.marshalNMedicationStatement2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐMedicationStatementᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_MedicationStatement(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_MedicationStatement(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_MedicationStatement_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_Observation(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_Observation(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().Observation(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Observation) graphql.Marshaler { - return ec.marshalNObservation2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐObservationᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_Observation(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_Observation(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_Observation_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_Organization(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_Organization(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().Organization(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Organization) graphql.Marshaler { - return ec.marshalNOrganization2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐOrganizationᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_Organization(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_Organization(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_Organization_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_Patient(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_Patient(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().Patient(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Patient) graphql.Marshaler { - return ec.marshalNPatient2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐPatientᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_Patient(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_Patient(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_Patient_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_Practitioner(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_Practitioner(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().Practitioner(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Practitioner) graphql.Marshaler { - return ec.marshalNPractitioner2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐPractitionerᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_Practitioner(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_Practitioner(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_Practitioner_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_PractitionerRole(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_PractitionerRole(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().PractitionerRole(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.PractitionerRole) graphql.Marshaler { - return ec.marshalNPractitionerRole2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐPractitionerRoleᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_PractitionerRole(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_PractitionerRole(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_PractitionerRole_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_Procedure(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_Procedure(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().Procedure(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Procedure) graphql.Marshaler { - return ec.marshalNProcedure2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐProcedureᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_Procedure(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_Procedure(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_Procedure_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_ResearchStudy(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_ResearchStudy(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().ResearchStudy(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.ResearchStudy) graphql.Marshaler { - return ec.marshalNResearchStudy2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐResearchStudyᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_ResearchStudy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_ResearchStudy(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_ResearchStudy_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_ResearchSubject(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_ResearchSubject(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().ResearchSubject(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.ResearchSubject) graphql.Marshaler { - return ec.marshalNResearchSubject2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐResearchSubjectᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_ResearchSubject(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_ResearchSubject(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_ResearchSubject_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_Specimen(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_Specimen(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().Specimen(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Specimen) graphql.Marshaler { - return ec.marshalNSpecimen2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐSpecimenᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_Specimen(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_Specimen(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_Specimen_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_Substance(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_Substance(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().Substance(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Substance) graphql.Marshaler { - return ec.marshalNSubstance2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐSubstanceᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_Substance(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_Substance(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_Substance_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_SubstanceDefinition(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_SubstanceDefinition(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().SubstanceDefinition(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.SubstanceDefinition) graphql.Marshaler { - return ec.marshalNSubstanceDefinition2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐSubstanceDefinitionᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_SubstanceDefinition(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_SubstanceDefinition(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_SubstanceDefinition_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_Task(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query_Task(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.Resolvers.Query().Task(ctx, fc.Args["project"].(string), fc.Args["filters"].([]*model.FhirFilterInput), fc.Args["limit"].(*int)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v []*fhir.Task) graphql.Marshaler { - return ec.marshalNTask2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋfhirᚐTaskᚄ(ctx, selections, v) - }, - true, - true, - ) -} -func (ec *executionContext) fieldContext_Query_Task(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields_Task(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_Task_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query___type(ctx, field) - }, - func(ctx context.Context) (any, error) { - fc := graphql.GetFieldContext(ctx) - return ec.IntrospectType(fc.Args["name"].(string)) - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v *introspection.Type) graphql.Marshaler { - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, selections, v) - }, - true, - false, - ) -} -func (ec *executionContext) fieldContext_Query___type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields___Type(ctx, field) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query___type_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.fieldContext_Query___schema(ctx, field) - }, - func(ctx context.Context) (any, error) { - return ec.IntrospectSchema() - }, - nil, - func(ctx context.Context, selections ast.SelectionSet, v *introspection.Schema) graphql.Marshaler { - return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, selections, v) - }, - true, - false, - ) -} -func (ec *executionContext) fieldContext_Query___schema(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return ec.childFields___Schema(ctx, field) + return ec.childFields___Schema(ctx, field) }, } return fc, nil @@ -10690,34 +9361,20 @@ func (ec *executionContext) unmarshalInputDataframeAggregateInput(ctx context.Co asMap[k] = v } - fieldsInOrder := [...]string{"materializationId", "selector", "dataType", "groupBy", "filters", "operation", "column"} + fieldsInOrder := [...]string{"selector", "groupBy", "filters", "operation", "column"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { - case "materializationId": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("materializationId")) - data, err := ec.unmarshalOID2ᚖstring(ctx, v) - if err != nil { - return it, err - } - it.MaterializationID = data case "selector": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("selector")) - data, err := ec.unmarshalODataframeSelectorInput2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeSelectorInput(ctx, v) + data, err := ec.unmarshalNDataframeSelectorInput2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeSelectorInput(ctx, v) if err != nil { return it, err } it.Selector = data - case "dataType": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("dataType")) - data, err := ec.unmarshalOString2ᚖstring(ctx, v) - if err != nil { - return it, err - } - it.DataType = data case "groupBy": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("groupBy")) data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) @@ -10814,72 +9471,21 @@ func (ec *executionContext) unmarshalInputDataframeAggregationSpecInput(ctx cont if err != nil { return it, err } - it.DateInterval = data - case "excludeSelfFilter": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("excludeSelfFilter")) - data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) - if err != nil { - return it, err - } - it.ExcludeSelfFilter = data - } - } - return it, nil -} - -func (ec *executionContext) unmarshalInputDataframeAggregationsInput(ctx context.Context, obj any) (model.DataframeAggregationsInput, error) { - var it model.DataframeAggregationsInput - if obj == nil { - return it, nil - } - - asMap := map[string]any{} - for k, v := range obj.(map[string]any) { - asMap[k] = v - } - - fieldsInOrder := [...]string{"selector", "dataType", "filters", "specs"} - for _, k := range fieldsInOrder { - v, ok := asMap[k] - if !ok { - continue - } - switch k { - case "selector": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("selector")) - data, err := ec.unmarshalODataframeSelectorInput2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeSelectorInput(ctx, v) - if err != nil { - return it, err - } - it.Selector = data - case "dataType": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("dataType")) - data, err := ec.unmarshalOString2ᚖstring(ctx, v) - if err != nil { - return it, err - } - it.DataType = data - case "filters": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filters")) - data, err := ec.unmarshalODataframeFilterInput2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeFilterInputᚄ(ctx, v) - if err != nil { - return it, err - } - it.Filters = data - case "specs": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("specs")) - data, err := ec.unmarshalNDataframeAggregationSpecInput2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeAggregationSpecInputᚄ(ctx, v) + it.DateInterval = data + case "excludeSelfFilter": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("excludeSelfFilter")) + data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) if err != nil { return it, err } - it.Specs = data + it.ExcludeSelfFilter = data } } return it, nil } -func (ec *executionContext) unmarshalInputDataframeBuilderIntrospectionInput(ctx context.Context, obj any) (model.DataframeBuilderIntrospectionInput, error) { - var it model.DataframeBuilderIntrospectionInput +func (ec *executionContext) unmarshalInputDataframeAggregationsInput(ctx context.Context, obj any) (model.DataframeAggregationsInput, error) { + var it model.DataframeAggregationsInput if obj == nil { return it, nil } @@ -10889,45 +9495,34 @@ func (ec *executionContext) unmarshalInputDataframeBuilderIntrospectionInput(ctx asMap[k] = v } - if _, present := asMap["includePivotOnlyFields"]; !present { - asMap["includePivotOnlyFields"] = true - } - - fieldsInOrder := [...]string{"project", "rootResourceType", "authResourcePaths", "includePivotOnlyFields"} + fieldsInOrder := [...]string{"selector", "filters", "specs"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { - case "project": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("project")) - data, err := ec.unmarshalNString2string(ctx, v) - if err != nil { - return it, err - } - it.Project = data - case "rootResourceType": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("rootResourceType")) - data, err := ec.unmarshalNString2string(ctx, v) + case "selector": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("selector")) + data, err := ec.unmarshalNDataframeSelectorInput2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeSelectorInput(ctx, v) if err != nil { return it, err } - it.RootResourceType = data - case "authResourcePaths": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("authResourcePaths")) - data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) + it.Selector = data + case "filters": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filters")) + data, err := ec.unmarshalODataframeFilterInput2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeFilterInputᚄ(ctx, v) if err != nil { return it, err } - it.AuthResourcePaths = data - case "includePivotOnlyFields": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includePivotOnlyFields")) - data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) + it.Filters = data + case "specs": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("specs")) + data, err := ec.unmarshalNDataframeAggregationSpecInput2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeAggregationSpecInputᚄ(ctx, v) if err != nil { return it, err } - it.IncludePivotOnlyFields = data + it.Specs = data } } return it, nil @@ -10944,7 +9539,7 @@ func (ec *executionContext) unmarshalInputDataframeDatasetInput(ctx context.Cont asMap[k] = v } - fieldsInOrder := [...]string{"selector", "dataType"} + fieldsInOrder := [...]string{"selector"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -10953,18 +9548,11 @@ func (ec *executionContext) unmarshalInputDataframeDatasetInput(ctx context.Cont switch k { case "selector": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("selector")) - data, err := ec.unmarshalODataframeSelectorInput2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeSelectorInput(ctx, v) + data, err := ec.unmarshalNDataframeSelectorInput2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeSelectorInput(ctx, v) if err != nil { return it, err } it.Selector = data - case "dataType": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("dataType")) - data, err := ec.unmarshalOString2ᚖstring(ctx, v) - if err != nil { - return it, err - } - it.DataType = data } } return it, nil @@ -11091,34 +9679,20 @@ func (ec *executionContext) unmarshalInputDataframeRowsInput(ctx context.Context asMap["first"] = 100 } - fieldsInOrder := [...]string{"materializationId", "selector", "dataType", "columns", "filters", "sort", "first", "after"} + fieldsInOrder := [...]string{"selector", "columns", "filters", "sort", "first", "after"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { - case "materializationId": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("materializationId")) - data, err := ec.unmarshalOID2ᚖstring(ctx, v) - if err != nil { - return it, err - } - it.MaterializationID = data case "selector": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("selector")) - data, err := ec.unmarshalODataframeSelectorInput2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeSelectorInput(ctx, v) + data, err := ec.unmarshalNDataframeSelectorInput2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeSelectorInput(ctx, v) if err != nil { return it, err } it.Selector = data - case "dataType": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("dataType")) - data, err := ec.unmarshalOString2ᚖstring(ctx, v) - if err != nil { - return it, err - } - it.DataType = data case "columns": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("columns")) data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) @@ -12529,43 +11103,6 @@ func (ec *executionContext) unmarshalInputPreviewDataframeRecipeInput(ctx contex return it, nil } -func (ec *executionContext) unmarshalInputPromoteDataframeContractInput(ctx context.Context, obj any) (model.PromoteDataframeContractInput, error) { - var it model.PromoteDataframeContractInput - if obj == nil { - return it, nil - } - - asMap := map[string]any{} - for k, v := range obj.(map[string]any) { - asMap[k] = v - } - - fieldsInOrder := [...]string{"recipe", "translationVersion"} - for _, k := range fieldsInOrder { - v, ok := asMap[k] - if !ok { - continue - } - switch k { - case "recipe": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("recipe")) - data, err := ec.unmarshalNString2string(ctx, v) - if err != nil { - return it, err - } - it.Recipe = data - case "translationVersion": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("translationVersion")) - data, err := ec.unmarshalNString2string(ctx, v) - if err != nil { - return it, err - } - it.TranslationVersion = data - } - } - return it, nil -} - func (ec *executionContext) unmarshalInputRegisterDataframeRecipeRevisionInput(ctx context.Context, obj any) (model.RegisterDataframeRecipeRevisionInput, error) { var it model.RegisterDataframeRecipeRevisionInput if obj == nil { @@ -12643,409 +11180,137 @@ func (ec *executionContext) unmarshalInputRunDataframeRecipeInput(ctx context.Co } it.Name = data case "bindings": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("bindings")) - data, err := ec.unmarshalNDataframeRecipeBindingsInput2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeBindingsInput(ctx, v) - if err != nil { - return it, err - } - it.Bindings = data - case "outputs": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("outputs")) - data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) - if err != nil { - return it, err - } - it.Outputs = data - } - } - return it, nil -} - -func (ec *executionContext) unmarshalInputStartDataframeMaterializationInput(ctx context.Context, obj any) (model.StartDataframeMaterializationInput, error) { - var it model.StartDataframeMaterializationInput - if obj == nil { - return it, nil - } - - asMap := map[string]any{} - for k, v := range obj.(map[string]any) { - asMap[k] = v - } - - fieldsInOrder := [...]string{"project", "generation", "selector"} - for _, k := range fieldsInOrder { - v, ok := asMap[k] - if !ok { - continue - } - switch k { - case "project": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("project")) - data, err := ec.unmarshalNString2string(ctx, v) - if err != nil { - return it, err - } - it.Project = data - case "generation": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("generation")) - data, err := ec.unmarshalNString2string(ctx, v) - if err != nil { - return it, err - } - it.Generation = data - case "selector": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("selector")) - data, err := ec.unmarshalNDataframeSelectorInput2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeSelectorInput(ctx, v) - if err != nil { - return it, err - } - it.Selector = data - } - } - return it, nil -} - -func (ec *executionContext) unmarshalInputValidateDataframeRecipeInput(ctx context.Context, obj any) (model.ValidateDataframeRecipeInput, error) { - var it model.ValidateDataframeRecipeInput - if obj == nil { - return it, nil - } - - asMap := map[string]any{} - for k, v := range obj.(map[string]any) { - asMap[k] = v - } - - fieldsInOrder := [...]string{"name", "bindings"} - for _, k := range fieldsInOrder { - v, ok := asMap[k] - if !ok { - continue - } - switch k { - case "name": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) - data, err := ec.unmarshalNString2string(ctx, v) - if err != nil { - return it, err - } - it.Name = data - case "bindings": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("bindings")) - data, err := ec.unmarshalNDataframeRecipeBindingsInput2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeBindingsInput(ctx, v) - if err != nil { - return it, err - } - it.Bindings = data - } - } - return it, nil -} - -// endregion **************************** input.gotpl ***************************** - -// region ************************** interface.gotpl *************************** - -// endregion ************************** interface.gotpl *************************** - -// region **************************** object.gotpl **************************** - -var dataframeAggregateResultImplementors = []string{"DataframeAggregateResult"} - -func (ec *executionContext) _DataframeAggregateResult(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeAggregateResult) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, dataframeAggregateResultImplementors) - - out := graphql.NewFieldSet(fields) - deferredFieldSet := graphql.NewFieldSet(nil) - deferLabelToView := make(map[string]*graphql.FieldSetView) - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("DataframeAggregateResult") - case "materialization": - out.Values[i] = ec._DataframeAggregateResult_materialization(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "columns": - out.Values[i] = ec._DataframeAggregateResult_columns(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "rows": - out.Values[i] = ec._DataframeAggregateResult_rows(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch(ctx) - if out.Invalids > 0 { - return graphql.Null - } - - atomic.AddInt32(&ec.Deferred, int32(min(len(deferLabelToView), math.MaxInt32))) - - ec.ProcessDeferredGroup(graphql.DeferredGroup{ - Defers: deferLabelToView, - Path: graphql.GetPath(ctx), - FieldSet: deferredFieldSet, - Context: ctx, - }) - - return out -} - -var dataframeAggregationsResultImplementors = []string{"DataframeAggregationsResult"} - -func (ec *executionContext) _DataframeAggregationsResult(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeAggregationsResult) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, dataframeAggregationsResultImplementors) - - out := graphql.NewFieldSet(fields) - deferredFieldSet := graphql.NewFieldSet(nil) - deferLabelToView := make(map[string]*graphql.FieldSetView) - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("DataframeAggregationsResult") - case "materialization": - out.Values[i] = ec._DataframeAggregationsResult_materialization(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("bindings")) + data, err := ec.unmarshalNDataframeRecipeBindingsInput2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeBindingsInput(ctx, v) + if err != nil { + return it, err } - case "aggregations": - out.Values[i] = ec._DataframeAggregationsResult_aggregations(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ + it.Bindings = data + case "outputs": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("outputs")) + data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) + if err != nil { + return it, err } - default: - panic("unknown field " + strconv.Quote(field.Name)) + it.Outputs = data } } - out.Dispatch(ctx) - if out.Invalids > 0 { - return graphql.Null - } - - atomic.AddInt32(&ec.Deferred, int32(min(len(deferLabelToView), math.MaxInt32))) - - ec.ProcessDeferredGroup(graphql.DeferredGroup{ - Defers: deferLabelToView, - Path: graphql.GetPath(ctx), - FieldSet: deferredFieldSet, - Context: ctx, - }) - - return out + return it, nil } -var dataframeBuilderIntrospectionImplementors = []string{"DataframeBuilderIntrospection"} +func (ec *executionContext) unmarshalInputStartDataframeMaterializationInput(ctx context.Context, obj any) (model.StartDataframeMaterializationInput, error) { + var it model.StartDataframeMaterializationInput + if obj == nil { + return it, nil + } -func (ec *executionContext) _DataframeBuilderIntrospection(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeBuilderIntrospection) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, dataframeBuilderIntrospectionImplementors) + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } - out := graphql.NewFieldSet(fields) - deferredFieldSet := graphql.NewFieldSet(nil) - deferLabelToView := make(map[string]*graphql.FieldSetView) - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("DataframeBuilderIntrospection") + fieldsInOrder := [...]string{"project", "generation", "selector"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { case "project": - out.Values[i] = ec._DataframeBuilderIntrospection_project(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "rootResourceType": - out.Values[i] = ec._DataframeBuilderIntrospection_rootResourceType(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "authResourcePaths": - out.Values[i] = ec._DataframeBuilderIntrospection_authResourcePaths(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "root": - out.Values[i] = ec._DataframeBuilderIntrospection_root(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "relatedResources": - out.Values[i] = ec._DataframeBuilderIntrospection_relatedResources(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "traversals": - out.Values[i] = ec._DataframeBuilderIntrospection_traversals(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("project")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err } - case "fields": - out.Values[i] = ec._DataframeBuilderIntrospection_fields(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ + it.Project = data + case "generation": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("generation")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err } - case "pivotFields": - out.Values[i] = ec._DataframeBuilderIntrospection_pivotFields(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ + it.Generation = data + case "selector": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("selector")) + data, err := ec.unmarshalNDataframeSelectorInput2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeSelectorInput(ctx, v) + if err != nil { + return it, err } - default: - panic("unknown field " + strconv.Quote(field.Name)) + it.Selector = data } } - out.Dispatch(ctx) - if out.Invalids > 0 { - return graphql.Null - } - - atomic.AddInt32(&ec.Deferred, int32(min(len(deferLabelToView), math.MaxInt32))) - - ec.ProcessDeferredGroup(graphql.DeferredGroup{ - Defers: deferLabelToView, - Path: graphql.GetPath(ctx), - FieldSet: deferredFieldSet, - Context: ctx, - }) - - return out + return it, nil } -var dataframeColumnImplementors = []string{"DataframeColumn"} +func (ec *executionContext) unmarshalInputValidateDataframeRecipeInput(ctx context.Context, obj any) (model.ValidateDataframeRecipeInput, error) { + var it model.ValidateDataframeRecipeInput + if obj == nil { + return it, nil + } -func (ec *executionContext) _DataframeColumn(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeColumn) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, dataframeColumnImplementors) + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } - out := graphql.NewFieldSet(fields) - deferredFieldSet := graphql.NewFieldSet(nil) - deferLabelToView := make(map[string]*graphql.FieldSetView) - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("DataframeColumn") - case "semanticPath": - out.Values[i] = ec._DataframeColumn_semanticPath(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } + fieldsInOrder := [...]string{"name", "bindings"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { case "name": - out.Values[i] = ec._DataframeColumn_name(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "clickhouseType": - out.Values[i] = ec._DataframeColumn_clickhouseType(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "logicalType": - out.Values[i] = ec._DataframeColumn_logicalType(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "nullable": - out.Values[i] = ec._DataframeColumn_nullable(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "repeated": - out.Values[i] = ec._DataframeColumn_repeated(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "filterable": - out.Values[i] = ec._DataframeColumn_filterable(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "sortable": - out.Values[i] = ec._DataframeColumn_sortable(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err } - case "aggregatable": - out.Values[i] = ec._DataframeColumn_aggregatable(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ + it.Name = data + case "bindings": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("bindings")) + data, err := ec.unmarshalNDataframeRecipeBindingsInput2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRecipeBindingsInput(ctx, v) + if err != nil { + return it, err } - default: - panic("unknown field " + strconv.Quote(field.Name)) + it.Bindings = data } } - out.Dispatch(ctx) - if out.Invalids > 0 { - return graphql.Null - } + return it, nil +} - atomic.AddInt32(&ec.Deferred, int32(min(len(deferLabelToView), math.MaxInt32))) +// endregion **************************** input.gotpl ***************************** - ec.ProcessDeferredGroup(graphql.DeferredGroup{ - Defers: deferLabelToView, - Path: graphql.GetPath(ctx), - FieldSet: deferredFieldSet, - Context: ctx, - }) +// region ************************** interface.gotpl *************************** - return out -} +// endregion ************************** interface.gotpl *************************** -var dataframeCompilerPlanDiagnosticsImplementors = []string{"DataframeCompilerPlanDiagnostics"} +// region **************************** object.gotpl **************************** -func (ec *executionContext) _DataframeCompilerPlanDiagnostics(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeCompilerPlanDiagnostics) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, dataframeCompilerPlanDiagnosticsImplementors) +var dataframeAggregateResultImplementors = []string{"DataframeAggregateResult"} + +func (ec *executionContext) _DataframeAggregateResult(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeAggregateResult) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, dataframeAggregateResultImplementors) out := graphql.NewFieldSet(fields) deferredFieldSet := graphql.NewFieldSet(nil) deferLabelToView := make(map[string]*graphql.FieldSetView) for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("DataframeCompilerPlanDiagnostics") - case "traversalSets": - out.Values[i] = ec._DataframeCompilerPlanDiagnostics_traversalSets(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "sharedTraversalCount": - out.Values[i] = ec._DataframeCompilerPlanDiagnostics_sharedTraversalCount(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "requiredMatchReuseCount": - out.Values[i] = ec._DataframeCompilerPlanDiagnostics_requiredMatchReuseCount(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "scopedSharingCandidateGroups": - out.Values[i] = ec._DataframeCompilerPlanDiagnostics_scopedSharingCandidateGroups(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "scopedSharingCandidateSets": - out.Values[i] = ec._DataframeCompilerPlanDiagnostics_scopedSharingCandidateSets(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "potentialSharingOpportunityGroups": - out.Values[i] = ec._DataframeCompilerPlanDiagnostics_potentialSharingOpportunityGroups(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "potentialSharingOpportunitySets": - out.Values[i] = ec._DataframeCompilerPlanDiagnostics_potentialSharingOpportunitySets(ctx, field, obj) + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("DataframeAggregateResult") + case "materialization": + out.Values[i] = ec._DataframeAggregateResult_materialization(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "optimizationPolicy": - out.Values[i] = ec._DataframeCompilerPlanDiagnostics_optimizationPolicy(ctx, field, obj) + case "columns": + out.Values[i] = ec._DataframeAggregateResult_columns(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "richSourceReuse": - out.Values[i] = ec._DataframeCompilerPlanDiagnostics_richSourceReuse(ctx, field, obj) + case "rows": + out.Values[i] = ec._DataframeAggregateResult_rows(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -13070,10 +11335,10 @@ func (ec *executionContext) _DataframeCompilerPlanDiagnostics(ctx context.Contex return out } -var dataframeContractImplementors = []string{"DataframeContract"} +var dataframeAggregationsResultImplementors = []string{"DataframeAggregationsResult"} -func (ec *executionContext) _DataframeContract(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeContract) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, dataframeContractImplementors) +func (ec *executionContext) _DataframeAggregationsResult(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeAggregationsResult) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, dataframeAggregationsResultImplementors) out := graphql.NewFieldSet(fields) deferredFieldSet := graphql.NewFieldSet(nil) @@ -13081,19 +11346,14 @@ func (ec *executionContext) _DataframeContract(ctx context.Context, sel ast.Sele for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("DataframeContract") - case "recipe": - out.Values[i] = ec._DataframeContract_recipe(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "translationVersion": - out.Values[i] = ec._DataframeContract_translationVersion(ctx, field, obj) + out.Values[i] = graphql.MarshalString("DataframeAggregationsResult") + case "materialization": + out.Values[i] = ec._DataframeAggregationsResult_materialization(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "promotedAt": - out.Values[i] = ec._DataframeContract_promotedAt(ctx, field, obj) + case "aggregations": + out.Values[i] = ec._DataframeAggregationsResult_aggregations(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -13118,10 +11378,10 @@ func (ec *executionContext) _DataframeContract(ctx context.Context, sel ast.Sele return out } -var dataframeFieldHintImplementors = []string{"DataframeFieldHint"} +var dataframeColumnImplementors = []string{"DataframeColumn"} -func (ec *executionContext) _DataframeFieldHint(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeFieldHint) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, dataframeFieldHintImplementors) +func (ec *executionContext) _DataframeColumn(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeColumn) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, dataframeColumnImplementors) out := graphql.NewFieldSet(fields) deferredFieldSet := graphql.NewFieldSet(nil) @@ -13129,87 +11389,52 @@ func (ec *executionContext) _DataframeFieldHint(ctx context.Context, sel ast.Sel for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("DataframeFieldHint") - case "resourceType": - out.Values[i] = ec._DataframeFieldHint_resourceType(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "fieldRef": - out.Values[i] = ec._DataframeFieldHint_fieldRef(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "label": - out.Values[i] = ec._DataframeFieldHint_label(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "path": - out.Values[i] = ec._DataframeFieldHint_path(ctx, field, obj) + out.Values[i] = graphql.MarshalString("DataframeColumn") + case "semanticPath": + out.Values[i] = ec._DataframeColumn_semanticPath(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "selector": - out.Values[i] = ec._DataframeFieldHint_selector(ctx, field, obj) + case "name": + out.Values[i] = ec._DataframeColumn_name(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "kind": - out.Values[i] = ec._DataframeFieldHint_kind(ctx, field, obj) + case "clickhouseType": + out.Values[i] = ec._DataframeColumn_clickhouseType(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "docCount": - out.Values[i] = ec._DataframeFieldHint_docCount(ctx, field, obj) + case "logicalType": + out.Values[i] = ec._DataframeColumn_logicalType(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "sampleCount": - out.Values[i] = ec._DataframeFieldHint_sampleCount(ctx, field, obj) + case "nullable": + out.Values[i] = ec._DataframeColumn_nullable(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "distinctValues": - out.Values[i] = ec._DataframeFieldHint_distinctValues(ctx, field, obj) + case "repeated": + out.Values[i] = ec._DataframeColumn_repeated(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "distinctTruncated": - out.Values[i] = ec._DataframeFieldHint_distinctTruncated(ctx, field, obj) + case "filterable": + out.Values[i] = ec._DataframeColumn_filterable(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "pivotCandidate": - out.Values[i] = ec._DataframeFieldHint_pivotCandidate(ctx, field, obj) + case "sortable": + out.Values[i] = ec._DataframeColumn_sortable(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "pivotKind": - out.Values[i] = ec._DataframeFieldHint_pivotKind(ctx, field, obj) - if out.Values[i] == graphql.RequiredNull { - out.Invalids++ - } - case "pivotColumns": - out.Values[i] = ec._DataframeFieldHint_pivotColumns(ctx, field, obj) + case "aggregatable": + out.Values[i] = ec._DataframeColumn_aggregatable(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "pivotFamily": - out.Values[i] = ec._DataframeFieldHint_pivotFamily(ctx, field, obj) - if out.Values[i] == graphql.RequiredNull { - out.Invalids++ - } - case "defaultPivotColumnSelector": - out.Values[i] = ec._DataframeFieldHint_defaultPivotColumnSelector(ctx, field, obj) - if out.Values[i] == graphql.RequiredNull { - out.Invalids++ - } - case "defaultPivotValueSelector": - out.Values[i] = ec._DataframeFieldHint_defaultPivotValueSelector(ctx, field, obj) - if out.Values[i] == graphql.RequiredNull { - out.Invalids++ - } default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -13231,10 +11456,10 @@ func (ec *executionContext) _DataframeFieldHint(ctx context.Context, sel ast.Sel return out } -var dataframeFieldPredicateImplementors = []string{"DataframeFieldPredicate"} +var dataframeCompilerPlanDiagnosticsImplementors = []string{"DataframeCompilerPlanDiagnostics"} -func (ec *executionContext) _DataframeFieldPredicate(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeFieldPredicate) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, dataframeFieldPredicateImplementors) +func (ec *executionContext) _DataframeCompilerPlanDiagnostics(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeCompilerPlanDiagnostics) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, dataframeCompilerPlanDiagnosticsImplementors) out := graphql.NewFieldSet(fields) deferredFieldSet := graphql.NewFieldSet(nil) @@ -13242,67 +11467,49 @@ func (ec *executionContext) _DataframeFieldPredicate(ctx context.Context, sel as for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("DataframeFieldPredicate") - case "path": - out.Values[i] = ec._DataframeFieldPredicate_path(ctx, field, obj) + out.Values[i] = graphql.MarshalString("DataframeCompilerPlanDiagnostics") + case "traversalSets": + out.Values[i] = ec._DataframeCompilerPlanDiagnostics_traversalSets(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "op": - out.Values[i] = ec._DataframeFieldPredicate_op(ctx, field, obj) + case "sharedTraversalCount": + out.Values[i] = ec._DataframeCompilerPlanDiagnostics_sharedTraversalCount(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "value": - out.Values[i] = ec._DataframeFieldPredicate_value(ctx, field, obj) + case "requiredMatchReuseCount": + out.Values[i] = ec._DataframeCompilerPlanDiagnostics_requiredMatchReuseCount(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch(ctx) - if out.Invalids > 0 { - return graphql.Null - } - - atomic.AddInt32(&ec.Deferred, int32(min(len(deferLabelToView), math.MaxInt32))) - - ec.ProcessDeferredGroup(graphql.DeferredGroup{ - Defers: deferLabelToView, - Path: graphql.GetPath(ctx), - FieldSet: deferredFieldSet, - Context: ctx, - }) - - return out -} - -var dataframeFieldSelectorImplementors = []string{"DataframeFieldSelector"} - -func (ec *executionContext) _DataframeFieldSelector(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeFieldSelector) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, dataframeFieldSelectorImplementors) - - out := graphql.NewFieldSet(fields) - deferredFieldSet := graphql.NewFieldSet(nil) - deferLabelToView := make(map[string]*graphql.FieldSetView) - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("DataframeFieldSelector") - case "sourcePath": - out.Values[i] = ec._DataframeFieldSelector_sourcePath(ctx, field, obj) - if out.Values[i] == graphql.RequiredNull { + case "scopedSharingCandidateGroups": + out.Values[i] = ec._DataframeCompilerPlanDiagnostics_scopedSharingCandidateGroups(ctx, field, obj) + if out.Values[i] == graphql.Null { out.Invalids++ } - case "where": - out.Values[i] = ec._DataframeFieldSelector_where(ctx, field, obj) - if out.Values[i] == graphql.RequiredNull { + case "scopedSharingCandidateSets": + out.Values[i] = ec._DataframeCompilerPlanDiagnostics_scopedSharingCandidateSets(ctx, field, obj) + if out.Values[i] == graphql.Null { out.Invalids++ } - case "valuePath": - out.Values[i] = ec._DataframeFieldSelector_valuePath(ctx, field, obj) + case "potentialSharingOpportunityGroups": + out.Values[i] = ec._DataframeCompilerPlanDiagnostics_potentialSharingOpportunityGroups(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "potentialSharingOpportunitySets": + out.Values[i] = ec._DataframeCompilerPlanDiagnostics_potentialSharingOpportunitySets(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "optimizationPolicy": + out.Values[i] = ec._DataframeCompilerPlanDiagnostics_optimizationPolicy(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "richSourceReuse": + out.Values[i] = ec._DataframeCompilerPlanDiagnostics_richSourceReuse(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -13409,11 +11616,6 @@ func (ec *executionContext) _DataframeMaterialization(ctx context.Context, sel a if out.Values[i] == graphql.RequiredNull { out.Invalids++ } - case "activeContractVersion": - out.Values[i] = ec._DataframeMaterialization_activeContractVersion(ctx, field, obj) - if out.Values[i] == graphql.RequiredNull { - out.Invalids++ - } case "availability": out.Values[i] = ec._DataframeMaterialization_availability(ctx, field, obj) if out.Values[i] == graphql.RequiredNull { @@ -15213,130 +13415,29 @@ func (ec *executionContext) _DataframeRecipeRevision(ctx context.Context, sel as out.Values[i] = ec._DataframeRecipeRevision_projectId(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ - } - case "name": - out.Values[i] = ec._DataframeRecipeRevision_name(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "digest": - out.Values[i] = ec._DataframeRecipeRevision_digest(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "parentDigest": - out.Values[i] = ec._DataframeRecipeRevision_parentDigest(ctx, field, obj) - if out.Values[i] == graphql.RequiredNull { - out.Invalids++ - } - case "recipe": - out.Values[i] = ec._DataframeRecipeRevision_recipe(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "createdAt": - out.Values[i] = ec._DataframeRecipeRevision_createdAt(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch(ctx) - if out.Invalids > 0 { - return graphql.Null - } - - atomic.AddInt32(&ec.Deferred, int32(min(len(deferLabelToView), math.MaxInt32))) - - ec.ProcessDeferredGroup(graphql.DeferredGroup{ - Defers: deferLabelToView, - Path: graphql.GetPath(ctx), - FieldSet: deferredFieldSet, - Context: ctx, - }) - - return out -} - -var dataframeRecipeValidationImplementors = []string{"DataframeRecipeValidation"} - -func (ec *executionContext) _DataframeRecipeValidation(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeRecipeValidation) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, dataframeRecipeValidationImplementors) - - out := graphql.NewFieldSet(fields) - deferredFieldSet := graphql.NewFieldSet(nil) - deferLabelToView := make(map[string]*graphql.FieldSetView) - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("DataframeRecipeValidation") - case "name": - out.Values[i] = ec._DataframeRecipeValidation_name(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "recipeDigest": - out.Values[i] = ec._DataframeRecipeValidation_recipeDigest(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "translationVersion": - out.Values[i] = ec._DataframeRecipeValidation_translationVersion(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "outputs": - out.Values[i] = ec._DataframeRecipeValidation_outputs(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch(ctx) - if out.Invalids > 0 { - return graphql.Null - } - - atomic.AddInt32(&ec.Deferred, int32(min(len(deferLabelToView), math.MaxInt32))) - - ec.ProcessDeferredGroup(graphql.DeferredGroup{ - Defers: deferLabelToView, - Path: graphql.GetPath(ctx), - FieldSet: deferredFieldSet, - Context: ctx, - }) - - return out -} - -var dataframeRelatedResourceHintsImplementors = []string{"DataframeRelatedResourceHints"} - -func (ec *executionContext) _DataframeRelatedResourceHints(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeRelatedResourceHints) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, dataframeRelatedResourceHintsImplementors) - - out := graphql.NewFieldSet(fields) - deferredFieldSet := graphql.NewFieldSet(nil) - deferLabelToView := make(map[string]*graphql.FieldSetView) - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("DataframeRelatedResourceHints") - case "viaLabel": - out.Values[i] = ec._DataframeRelatedResourceHints_viaLabel(ctx, field, obj) + } + case "name": + out.Values[i] = ec._DataframeRecipeRevision_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "digest": + out.Values[i] = ec._DataframeRecipeRevision_digest(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "edgeCount": - out.Values[i] = ec._DataframeRelatedResourceHints_edgeCount(ctx, field, obj) + case "parentDigest": + out.Values[i] = ec._DataframeRecipeRevision_parentDigest(ctx, field, obj) + if out.Values[i] == graphql.RequiredNull { + out.Invalids++ + } + case "recipe": + out.Values[i] = ec._DataframeRecipeRevision_recipe(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "target": - out.Values[i] = ec._DataframeRelatedResourceHints_target(ctx, field, obj) + case "createdAt": + out.Values[i] = ec._DataframeRecipeRevision_createdAt(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -15361,10 +13462,10 @@ func (ec *executionContext) _DataframeRelatedResourceHints(ctx context.Context, return out } -var dataframeResourceHintsImplementors = []string{"DataframeResourceHints"} +var dataframeRecipeValidationImplementors = []string{"DataframeRecipeValidation"} -func (ec *executionContext) _DataframeResourceHints(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeResourceHints) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, dataframeResourceHintsImplementors) +func (ec *executionContext) _DataframeRecipeValidation(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeRecipeValidation) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, dataframeRecipeValidationImplementors) out := graphql.NewFieldSet(fields) deferredFieldSet := graphql.NewFieldSet(nil) @@ -15372,24 +13473,24 @@ func (ec *executionContext) _DataframeResourceHints(ctx context.Context, sel ast for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("DataframeResourceHints") - case "resourceType": - out.Values[i] = ec._DataframeResourceHints_resourceType(ctx, field, obj) + out.Values[i] = graphql.MarshalString("DataframeRecipeValidation") + case "name": + out.Values[i] = ec._DataframeRecipeValidation_name(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "fields": - out.Values[i] = ec._DataframeResourceHints_fields(ctx, field, obj) + case "recipeDigest": + out.Values[i] = ec._DataframeRecipeValidation_recipeDigest(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "pivotFields": - out.Values[i] = ec._DataframeResourceHints_pivotFields(ctx, field, obj) + case "translationVersion": + out.Values[i] = ec._DataframeRecipeValidation_translationVersion(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } - case "traversals": - out.Values[i] = ec._DataframeResourceHints_traversals(ctx, field, obj) + case "outputs": + out.Values[i] = ec._DataframeRecipeValidation_outputs(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } @@ -15578,59 +13679,6 @@ func (ec *executionContext) _DataframeSelector(ctx context.Context, sel ast.Sele return out } -var dataframeTraversalHintImplementors = []string{"DataframeTraversalHint"} - -func (ec *executionContext) _DataframeTraversalHint(ctx context.Context, sel ast.SelectionSet, obj *model.DataframeTraversalHint) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, dataframeTraversalHintImplementors) - - out := graphql.NewFieldSet(fields) - deferredFieldSet := graphql.NewFieldSet(nil) - deferLabelToView := make(map[string]*graphql.FieldSetView) - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("DataframeTraversalHint") - case "fromType": - out.Values[i] = ec._DataframeTraversalHint_fromType(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "label": - out.Values[i] = ec._DataframeTraversalHint_label(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "toType": - out.Values[i] = ec._DataframeTraversalHint_toType(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "edgeCount": - out.Values[i] = ec._DataframeTraversalHint_edgeCount(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch(ctx) - if out.Invalids > 0 { - return graphql.Null - } - - atomic.AddInt32(&ec.Deferred, int32(min(len(deferLabelToView), math.MaxInt32))) - - ec.ProcessDeferredGroup(graphql.DeferredGroup{ - Defers: deferLabelToView, - Path: graphql.GetPath(ctx), - FieldSet: deferredFieldSet, - Context: ctx, - }) - - return out -} - var fhirDataframeResultImplementors = []string{"FhirDataframeResult"} func (ec *executionContext) _FhirDataframeResult(ctx context.Context, sel ast.SelectionSet, obj *model.FhirDataframeResult) graphql.Marshaler { @@ -16071,13 +14119,6 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { out.Invalids++ } - case "promoteDataframeContract": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_promoteDataframeContract(ctx, field) - }) - if out.Values[i] == graphql.Null { - out.Invalids++ - } case "registerDataframeRecipeRevision": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_registerDataframeRecipeRevision(ctx, field) @@ -16184,50 +14225,6 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Query") - case "dataframeBuilderIntrospection": - field := field - - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_dataframeBuilderIntrospection(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, - func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) - } - - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) - case "dataframeMaterialization": - field := field - - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_dataframeMaterialization(ctx, field) - if res == graphql.RequiredNull { - atomic.AddUint32(&fs.Invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, - func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) - } - - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "dataframeDatasets": field := field @@ -17121,25 +15118,6 @@ func (ec *executionContext) marshalNDataframeAggregationsResult2ᚖgithubᚗcom return ec._DataframeAggregationsResult(ctx, sel, v) } -func (ec *executionContext) marshalNDataframeBuilderIntrospection2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeBuilderIntrospection(ctx context.Context, sel ast.SelectionSet, v model.DataframeBuilderIntrospection) graphql.Marshaler { - return ec._DataframeBuilderIntrospection(ctx, sel, &v) -} - -func (ec *executionContext) marshalNDataframeBuilderIntrospection2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeBuilderIntrospection(ctx context.Context, sel ast.SelectionSet, v *model.DataframeBuilderIntrospection) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec._DataframeBuilderIntrospection(ctx, sel, v) -} - -func (ec *executionContext) unmarshalNDataframeBuilderIntrospectionInput2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeBuilderIntrospectionInput(ctx context.Context, v any) (model.DataframeBuilderIntrospectionInput, error) { - res, err := ec.unmarshalInputDataframeBuilderIntrospectionInput(ctx, v) - return res, graphql.ErrorOnPath(ctx, err) -} - func (ec *executionContext) marshalNDataframeColumn2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeColumnᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.DataframeColumn) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) @@ -17176,61 +15154,11 @@ func (ec *executionContext) marshalNDataframeCompilerPlanDiagnostics2ᚖgithub return ec._DataframeCompilerPlanDiagnostics(ctx, sel, v) } -func (ec *executionContext) marshalNDataframeContract2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeContract(ctx context.Context, sel ast.SelectionSet, v model.DataframeContract) graphql.Marshaler { - return ec._DataframeContract(ctx, sel, &v) -} - -func (ec *executionContext) marshalNDataframeContract2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeContract(ctx context.Context, sel ast.SelectionSet, v *model.DataframeContract) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec._DataframeContract(ctx, sel, v) -} - func (ec *executionContext) unmarshalNDataframeDatasetInput2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeDatasetInput(ctx context.Context, v any) (model.DataframeDatasetInput, error) { res, err := ec.unmarshalInputDataframeDatasetInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNDataframeFieldHint2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeFieldHintᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.DataframeFieldHint) graphql.Marshaler { - ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { - fc := graphql.GetFieldContext(ctx) - fc.Result = &v[i] - return ec.marshalNDataframeFieldHint2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeFieldHint(ctx, sel, v[i]) - }) - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalNDataframeFieldHint2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeFieldHint(ctx context.Context, sel ast.SelectionSet, v *model.DataframeFieldHint) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec._DataframeFieldHint(ctx, sel, v) -} - -func (ec *executionContext) marshalNDataframeFieldSelector2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeFieldSelector(ctx context.Context, sel ast.SelectionSet, v *model.DataframeFieldSelector) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec._DataframeFieldSelector(ctx, sel, v) -} - func (ec *executionContext) unmarshalNDataframeFilterInput2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeFilterInput(ctx context.Context, v any) (*model.DataframeFilterInput, error) { res, err := ec.unmarshalInputDataframeFilterInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) @@ -17893,42 +15821,6 @@ func (ec *executionContext) marshalNDataframeRecipeValidation2ᚖgithubᚗcomᚋ return ec._DataframeRecipeValidation(ctx, sel, v) } -func (ec *executionContext) marshalNDataframeRelatedResourceHints2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRelatedResourceHintsᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.DataframeRelatedResourceHints) graphql.Marshaler { - ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { - fc := graphql.GetFieldContext(ctx) - fc.Result = &v[i] - return ec.marshalNDataframeRelatedResourceHints2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRelatedResourceHints(ctx, sel, v[i]) - }) - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalNDataframeRelatedResourceHints2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRelatedResourceHints(ctx context.Context, sel ast.SelectionSet, v *model.DataframeRelatedResourceHints) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec._DataframeRelatedResourceHints(ctx, sel, v) -} - -func (ec *executionContext) marshalNDataframeResourceHints2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeResourceHints(ctx context.Context, sel ast.SelectionSet, v *model.DataframeResourceHints) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec._DataframeResourceHints(ctx, sel, v) -} - func (ec *executionContext) marshalNDataframeRichSourceReuse2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeRichSourceReuseᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.DataframeRichSourceReuse) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) @@ -17979,32 +15871,6 @@ func (ec *executionContext) unmarshalNDataframeSelectorInput2ᚖgithubᚗcomᚋc return &res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) marshalNDataframeTraversalHint2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeTraversalHintᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.DataframeTraversalHint) graphql.Marshaler { - ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { - fc := graphql.GetFieldContext(ctx) - fc.Result = &v[i] - return ec.marshalNDataframeTraversalHint2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeTraversalHint(ctx, sel, v[i]) - }) - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalNDataframeTraversalHint2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeTraversalHint(ctx context.Context, sel ast.SelectionSet, v *model.DataframeTraversalHint) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec._DataframeTraversalHint(ctx, sel, v) -} - func (ec *executionContext) unmarshalNExplainDataframeRecipeInput2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐExplainDataframeRecipeInput(ctx context.Context, v any) (model.ExplainDataframeRecipeInput, error) { res, err := ec.unmarshalInputExplainDataframeRecipeInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -18394,11 +16260,6 @@ func (ec *executionContext) marshalNProjectReleaseState2githubᚗcomᚋcalyprᚋ return v } -func (ec *executionContext) unmarshalNPromoteDataframeContractInput2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐPromoteDataframeContractInput(ctx context.Context, v any) (model.PromoteDataframeContractInput, error) { - res, err := ec.unmarshalInputPromoteDataframeContractInput(ctx, v) - return res, graphql.ErrorOnPath(ctx, err) -} - func (ec *executionContext) unmarshalNRegisterDataframeRecipeRevisionInput2githubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐRegisterDataframeRecipeRevisionInput(ctx context.Context, v any) (model.RegisterDataframeRecipeRevisionInput, error) { res, err := ec.unmarshalInputRegisterDataframeRecipeRevisionInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -18435,20 +16296,6 @@ func (ec *executionContext) marshalODataframeAvailability2ᚖgithubᚗcomᚋcaly return v } -func (ec *executionContext) marshalODataframeFieldPredicate2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeFieldPredicate(ctx context.Context, sel ast.SelectionSet, v *model.DataframeFieldPredicate) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec._DataframeFieldPredicate(ctx, sel, v) -} - -func (ec *executionContext) marshalODataframeFieldSelector2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeFieldSelector(ctx context.Context, sel ast.SelectionSet, v *model.DataframeFieldSelector) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec._DataframeFieldSelector(ctx, sel, v) -} - func (ec *executionContext) unmarshalODataframeFilterInput2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeFilterInputᚄ(ctx context.Context, v any) ([]*model.DataframeFilterInput, error) { if v == nil { return nil, nil @@ -18529,14 +16376,6 @@ func (ec *executionContext) marshalODataframeSelector2ᚖgithubᚗcomᚋcalypr return ec._DataframeSelector(ctx, sel, v) } -func (ec *executionContext) unmarshalODataframeSelectorInput2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeSelectorInput(ctx context.Context, v any) (*model.DataframeSelectorInput, error) { - if v == nil { - return nil, nil - } - res, err := ec.unmarshalInputDataframeSelectorInput(ctx, v) - return &res, graphql.ErrorOnPath(ctx, err) -} - func (ec *executionContext) unmarshalODataframeSortInput2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐDataframeSortInput(ctx context.Context, v any) (*model.DataframeSortInput, error) { if v == nil { return nil, nil @@ -18661,22 +16500,6 @@ func (ec *executionContext) unmarshalOFhirPivotDiscoveryInput2ᚖgithubᚗcomᚋ return &res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalOFhirPivotFamily2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirPivotFamily(ctx context.Context, v any) (*model.FhirPivotFamily, error) { - if v == nil { - return nil, nil - } - var res = new(model.FhirPivotFamily) - err := res.UnmarshalGQL(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalOFhirPivotFamily2ᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirPivotFamily(ctx context.Context, sel ast.SelectionSet, v *model.FhirPivotFamily) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return v -} - func (ec *executionContext) unmarshalOFhirPivotInput2ᚕᚖgithubᚗcomᚋcalyprᚋloomᚋgeneratedᚋgraphqlᚋgraphᚋmodelᚐFhirPivotInputᚄ(ctx context.Context, v any) ([]*model.FhirPivotInput, error) { if v == nil { return nil, nil diff --git a/generated/graphql/graph/model/models.go b/generated/graphql/graph/model/models.go index c8705b24..4c18b067 100644 --- a/generated/graphql/graph/model/models.go +++ b/generated/graphql/graph/model/models.go @@ -23,13 +23,11 @@ type ActivateProjectReleaseInput struct { } type DataframeAggregateInput struct { - MaterializationID *string `json:"materializationId,omitempty"` - Selector *DataframeSelectorInput `json:"selector,omitempty"` - DataType *string `json:"dataType,omitempty"` - GroupBy []string `json:"groupBy,omitempty"` - Filters []*DataframeFilterInput `json:"filters,omitempty"` - Operation string `json:"operation"` - Column *string `json:"column,omitempty"` + Selector *DataframeSelectorInput `json:"selector"` + GroupBy []string `json:"groupBy,omitempty"` + Filters []*DataframeFilterInput `json:"filters,omitempty"` + Operation string `json:"operation"` + Column *string `json:"column,omitempty"` } type DataframeAggregateResult struct { @@ -49,8 +47,7 @@ type DataframeAggregationSpecInput struct { } type DataframeAggregationsInput struct { - Selector *DataframeSelectorInput `json:"selector,omitempty"` - DataType *string `json:"dataType,omitempty"` + Selector *DataframeSelectorInput `json:"selector"` Filters []*DataframeFilterInput `json:"filters,omitempty"` Specs []*DataframeAggregationSpecInput `json:"specs"` } @@ -60,24 +57,6 @@ type DataframeAggregationsResult struct { Aggregations json.RawMessage `json:"aggregations"` } -type DataframeBuilderIntrospection struct { - Project string `json:"project"` - RootResourceType string `json:"rootResourceType"` - AuthResourcePaths []string `json:"authResourcePaths"` - Root *DataframeResourceHints `json:"root"` - RelatedResources []*DataframeRelatedResourceHints `json:"relatedResources"` - Traversals []*DataframeTraversalHint `json:"traversals"` - Fields []*DataframeFieldHint `json:"fields"` - PivotFields []*DataframeFieldHint `json:"pivotFields"` -} - -type DataframeBuilderIntrospectionInput struct { - Project string `json:"project"` - RootResourceType string `json:"rootResourceType"` - AuthResourcePaths []string `json:"authResourcePaths,omitempty"` - IncludePivotOnlyFields *bool `json:"includePivotOnlyFields,omitempty"` -} - type DataframeColumn struct { SemanticPath string `json:"semanticPath"` Name string `json:"name"` @@ -102,46 +81,8 @@ type DataframeCompilerPlanDiagnostics struct { RichSourceReuse []*DataframeRichSourceReuse `json:"richSourceReuse"` } -type DataframeContract struct { - Recipe string `json:"recipe"` - TranslationVersion string `json:"translationVersion"` - PromotedAt string `json:"promotedAt"` -} - type DataframeDatasetInput struct { - Selector *DataframeSelectorInput `json:"selector,omitempty"` - DataType *string `json:"dataType,omitempty"` -} - -type DataframeFieldHint struct { - ResourceType string `json:"resourceType"` - FieldRef string `json:"fieldRef"` - Label string `json:"label"` - Path string `json:"path"` - Selector *DataframeFieldSelector `json:"selector"` - Kind string `json:"kind"` - DocCount int `json:"docCount"` - SampleCount int `json:"sampleCount"` - DistinctValues []string `json:"distinctValues"` - DistinctTruncated bool `json:"distinctTruncated"` - PivotCandidate bool `json:"pivotCandidate"` - PivotKind *string `json:"pivotKind,omitempty"` - PivotColumns []string `json:"pivotColumns"` - PivotFamily *FhirPivotFamily `json:"pivotFamily,omitempty"` - DefaultPivotColumnSelector *DataframeFieldSelector `json:"defaultPivotColumnSelector,omitempty"` - DefaultPivotValueSelector *DataframeFieldSelector `json:"defaultPivotValueSelector,omitempty"` -} - -type DataframeFieldPredicate struct { - Path string `json:"path"` - Op FhirFieldPredicateOperation `json:"op"` - Value string `json:"value"` -} - -type DataframeFieldSelector struct { - SourcePath *string `json:"sourcePath,omitempty"` - Where *DataframeFieldPredicate `json:"where,omitempty"` - ValuePath string `json:"valuePath"` + Selector *DataframeSelectorInput `json:"selector"` } type DataframeFilterInput struct { @@ -151,26 +92,25 @@ type DataframeFilterInput struct { } type DataframeMaterialization struct { - ID string `json:"id"` - Name string `json:"name"` - Revision string `json:"revision"` - ProjectID string `json:"projectId"` - DatasetGeneration string `json:"datasetGeneration"` - State DataframeMaterializationState `json:"state"` - Columns []*DataframeColumn `json:"columns"` - RowCount *int `json:"rowCount,omitempty"` - CreatedAt string `json:"createdAt"` - ReadyAt *string `json:"readyAt,omitempty"` - Error *string `json:"error,omitempty"` - ErrorCode *string `json:"errorCode,omitempty"` - ErrorRetryable *bool `json:"errorRetryable,omitempty"` - Selector *DataframeSelector `json:"selector,omitempty"` - ActiveContractVersion *string `json:"activeContractVersion,omitempty"` - Availability *DataframeAvailability `json:"availability,omitempty"` - Completeness *float64 `json:"completeness,omitempty"` - IncludedProjectCount *int `json:"includedProjectCount,omitempty"` - ExpectedProjectCount *int `json:"expectedProjectCount,omitempty"` - ProjectStatuses []*DataframeProjectStatus `json:"projectStatuses"` + ID string `json:"id"` + Name string `json:"name"` + Revision string `json:"revision"` + ProjectID string `json:"projectId"` + DatasetGeneration string `json:"datasetGeneration"` + State DataframeMaterializationState `json:"state"` + Columns []*DataframeColumn `json:"columns"` + RowCount *int `json:"rowCount,omitempty"` + CreatedAt string `json:"createdAt"` + ReadyAt *string `json:"readyAt,omitempty"` + Error *string `json:"error,omitempty"` + ErrorCode *string `json:"errorCode,omitempty"` + ErrorRetryable *bool `json:"errorRetryable,omitempty"` + Selector *DataframeSelector `json:"selector,omitempty"` + Availability *DataframeAvailability `json:"availability,omitempty"` + Completeness *float64 `json:"completeness,omitempty"` + IncludedProjectCount *int `json:"includedProjectCount,omitempty"` + ExpectedProjectCount *int `json:"expectedProjectCount,omitempty"` + ProjectStatuses []*DataframeProjectStatus `json:"projectStatuses"` } type DataframeOptimizationDecision struct { @@ -440,19 +380,6 @@ type DataframeRecipeValidation struct { Outputs []*DataframeRecipeOutputValidation `json:"outputs"` } -type DataframeRelatedResourceHints struct { - ViaLabel string `json:"viaLabel"` - EdgeCount int `json:"edgeCount"` - Target *DataframeResourceHints `json:"target"` -} - -type DataframeResourceHints struct { - ResourceType string `json:"resourceType"` - Fields []*DataframeFieldHint `json:"fields"` - PivotFields []*DataframeFieldHint `json:"pivotFields"` - Traversals []*DataframeTraversalHint `json:"traversals"` -} - type DataframeRichSourceReuse struct { SourceSet string `json:"sourceSet"` AggregateConsumers int `json:"aggregateConsumers"` @@ -470,14 +397,12 @@ type DataframeRowConnection struct { } type DataframeRowsInput struct { - MaterializationID *string `json:"materializationId,omitempty"` - Selector *DataframeSelectorInput `json:"selector,omitempty"` - DataType *string `json:"dataType,omitempty"` - Columns []string `json:"columns,omitempty"` - Filters []*DataframeFilterInput `json:"filters,omitempty"` - Sort *DataframeSortInput `json:"sort,omitempty"` - First *int `json:"first,omitempty"` - After *string `json:"after,omitempty"` + Selector *DataframeSelectorInput `json:"selector"` + Columns []string `json:"columns,omitempty"` + Filters []*DataframeFilterInput `json:"filters,omitempty"` + Sort *DataframeSortInput `json:"sort,omitempty"` + First *int `json:"first,omitempty"` + After *string `json:"after,omitempty"` } type DataframeSelector struct { @@ -497,13 +422,6 @@ type DataframeSortInput struct { Desc *bool `json:"desc,omitempty"` } -type DataframeTraversalHint struct { - FromType string `json:"fromType"` - Label string `json:"label"` - ToType string `json:"toType"` - EdgeCount int `json:"edgeCount"` -} - type ExplainDataframeRecipeInput struct { Name string `json:"name"` Bindings *DataframeRecipeBindingsInput `json:"bindings"` @@ -728,11 +646,6 @@ type ProjectRelease struct { State ProjectReleaseState `json:"state"` } -type PromoteDataframeContractInput struct { - Recipe string `json:"recipe"` - TranslationVersion string `json:"translationVersion"` -} - type Query struct { } @@ -1461,61 +1374,6 @@ func (e FhirFilterValueKind) MarshalJSON() ([]byte, error) { return buf.Bytes(), nil } -type FhirPivotFamily string - -const ( - FhirPivotFamilyCodeableConcept FhirPivotFamily = "CODEABLE_CONCEPT" - FhirPivotFamilyObservationCodeValue FhirPivotFamily = "OBSERVATION_CODE_VALUE" -) - -var AllFhirPivotFamily = []FhirPivotFamily{ - FhirPivotFamilyCodeableConcept, - FhirPivotFamilyObservationCodeValue, -} - -func (e FhirPivotFamily) IsValid() bool { - switch e { - case FhirPivotFamilyCodeableConcept, FhirPivotFamilyObservationCodeValue: - return true - } - return false -} - -func (e FhirPivotFamily) String() string { - return string(e) -} - -func (e *FhirPivotFamily) UnmarshalGQL(v any) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = FhirPivotFamily(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid FhirPivotFamily", str) - } - return nil -} - -func (e FhirPivotFamily) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -func (e *FhirPivotFamily) UnmarshalJSON(b []byte) error { - s, err := strconv.Unquote(string(b)) - if err != nil { - return err - } - return e.UnmarshalGQL(s) -} - -func (e FhirPivotFamily) MarshalJSON() ([]byte, error) { - var buf bytes.Buffer - e.MarshalGQL(&buf) - return buf.Bytes(), nil -} - type FhirTraversalMatchMode string const ( diff --git a/internal/api/bulk/dump/dataframe_export_route.go b/internal/api/bulk/dump/dataframe_export_route.go index 861f17f8..d10aed36 100644 --- a/internal/api/bulk/dump/dataframe_export_route.go +++ b/internal/api/bulk/dump/dataframe_export_route.go @@ -14,8 +14,7 @@ func (s *Handler) exportDataframe(c fiber.Ctx) error { if err := json.Unmarshal(c.Body(), &request); err != nil { return dataframeerrors.Wrap(err, dataframeerrors.CodeInvalidRequest, "") } - request.DataType = strings.TrimSpace(request.DataType) - if (request.Selector == nil && request.DataType == "") || (request.Selector != nil && request.DataType != "") { + if request.Selector == nil { return dataframeerrors.NewError(dataframeerrors.CodeInvalidSelector, "") } if request.Format.Normalize() == "" { diff --git a/internal/api/bulk/dump/dataframe_export_route_test.go b/internal/api/bulk/dump/dataframe_export_route_test.go index 978b2a28..60759b90 100644 --- a/internal/api/bulk/dump/dataframe_export_route_test.go +++ b/internal/api/bulk/dump/dataframe_export_route_test.go @@ -17,7 +17,7 @@ import ( type fakeDataframeExporter struct{} func (fakeDataframeExporter) ExportDataframe(_ context.Context, request dfmaterialization.ExportRequest, out io.Writer) error { - if request.DataType != "files" || request.Format.Normalize() != dfmaterialization.ExportCSV { + if request.Selector == nil || request.Format.Normalize() != dfmaterialization.ExportCSV { return dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") } _, err := io.WriteString(out, "id\n1\n") @@ -34,7 +34,7 @@ func (fakeSelectorExporter) ExportDataframe(_ context.Context, request dfmateria return err } -func TestDataframeExportRoute(t *testing.T) { +func TestDataframeExportRouteRejectsLegacyDataType(t *testing.T) { server, err := httpapi.NewHTTPServer(httpapi.HTTPConfig{Authorizer: authscope.AllowAllAuthorizer{}}) if err != nil { t.Fatal(err) @@ -47,16 +47,10 @@ func TestDataframeExportRoute(t *testing.T) { t.Fatal(err) } defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { + if resp.StatusCode != http.StatusBadRequest { body, _ := io.ReadAll(resp.Body) t.Fatalf("status = %d, body = %s", resp.StatusCode, body) } - if got := resp.Header.Get("Content-Type"); !strings.HasPrefix(got, "text/csv") { - t.Fatalf("content type = %q", got) - } - if got := resp.Header.Get("Content-Disposition"); strings.Contains(got, "../") || !strings.Contains(got, "files.csv") { - t.Fatalf("content disposition = %q", got) - } } func TestDataframeExportRouteAcceptsExactSelector(t *testing.T) { diff --git a/internal/api/graphql/errors.go b/internal/api/graphql/errors.go index 1d06cf8e..8201121d 100644 --- a/internal/api/graphql/errors.go +++ b/internal/api/graphql/errors.go @@ -34,7 +34,9 @@ func PresentGraphQLError(err error, requestID string) *gqlerror.Error { // their path/location while giving clients one stable non-retryable code. if gqlErr.Err == nil { copy := *gqlErr - copy.Extensions = map[string]any{"code": "GRAPHQL_VALIDATION_FAILED", "retryable": false} + if len(copy.Extensions) == 0 { + copy.Extensions = map[string]any{"code": "GRAPHQL_VALIDATION_FAILED", "retryable": false} + } if requestID != "" { copy.Extensions["requestId"] = requestID } diff --git a/internal/api/graphql/graph/handler.go b/internal/api/graphql/graph/handler.go index c2608b69..62ae4b59 100644 --- a/internal/api/graphql/graph/handler.go +++ b/internal/api/graphql/graph/handler.go @@ -35,10 +35,6 @@ func RegisterRoutes(router fiber.Router, cfg RouteConfig) { h := fiberadaptor.HTTPHandlerWithContext(cfg.Handler) router.Post("/graphql/graph", h) router.Post("/graphql/dataframe", h) - // Keep the historical flat URL as a compatibility alias. It uses the - // same executable schema and resolver, so the alias adds no duplicate - // transport or generated code. - router.Post("/graphql/flat", h) } } diff --git a/internal/api/graphql/graph/http_integration_test.go b/internal/api/graphql/graph/http_integration_test.go index d46060e9..a51120df 100644 --- a/internal/api/graphql/graph/http_integration_test.go +++ b/internal/api/graphql/graph/http_integration_test.go @@ -18,105 +18,6 @@ import ( publication "github.com/calypr/loom/internal/dataset" ) -func TestGraphQLIntrospectionEndpoint(t *testing.T) { - graphResolver := graphresolver.NewResolver(graphresolver.ResolverConfig{ - DataframeQuery: queryapi.Config{ - ActiveManifestResolver: testActiveManifestResolver{}, - DiscoverReferences: func(ctx context.Context, opts catalog.PopulatedReferenceOptions) ([]catalog.PopulatedReference, error) { - return []catalog.PopulatedReference{ - {FromType: "Patient", Label: "subject_Patient", ToType: "Specimen", EdgeCount: 10}, - }, nil - }, - DiscoverFields: func(ctx context.Context, opts catalog.PopulatedFieldOptions) ([]catalog.PopulatedField, error) { - if opts.PivotOnly { - return []catalog.PopulatedField{ - { - ResourceType: "Patient", - Path: "valueCodeableConcept", - Kind: "codeable_concept", - DocCount: 3, - SampleCount: 1, - PivotCandidate: true, - PivotKind: "codeable_concept_display_value", - PivotColumns: []string{"Stage IVA"}, - DistinctValues: []string{"M0"}, - DistinctTruncated: false, - }, - }, nil - } - return []catalog.PopulatedField{ - { - ResourceType: "Patient", - Path: "identifier[].value", - Kind: "scalar", - DocCount: 5, - SampleCount: 1, - DistinctValues: []string{"TCGA-01"}, - DistinctTruncated: false, - PivotCandidate: false, - PivotColumns: []string{}, - }, - }, nil - }, - }, - }) - server, err := newGraphServer(graphResolver, authscope.StaticAuthenticator{Principal: authscope.Principal{Subject: "u1", Projects: []string{"P1"}, AuthResourcePaths: []string{"pathA"}}}) - if err != nil { - t.Fatal(err) - } - - queryBody := `{"query":"query($input: DataframeBuilderIntrospectionInput!) { dataframeBuilderIntrospection(input: $input) { project rootResourceType authResourcePaths root { resourceType fields { resourceType fieldRef label path selector { sourcePath where { path op value } valuePath } kind } pivotFields { resourceType fieldRef path selector { sourcePath where { path op value } valuePath } pivotCandidate pivotKind pivotColumns } traversals { fromType label toType edgeCount } } relatedResources { viaLabel edgeCount target { resourceType fields { resourceType fieldRef path selector { sourcePath where { path op value } valuePath } kind } pivotFields { resourceType fieldRef path selector { sourcePath where { path op value } valuePath } pivotCandidate pivotKind pivotColumns } } } traversals { fromType label toType edgeCount } fields { resourceType fieldRef label path selector { sourcePath where { path op value } valuePath } kind docCount sampleCount distinctValues distinctTruncated pivotCandidate pivotKind pivotColumns } pivotFields { resourceType fieldRef path selector { sourcePath where { path op value } valuePath } pivotCandidate pivotKind pivotColumns } } }","variables":{"input":{"project":"P1","rootResourceType":"Patient"}}}` - req := httptest.NewRequest(http.MethodPost, "/graphql/graph", strings.NewReader(queryBody)) - req.Header.Set("Content-Type", "application/json") - - resp, err := server.App().Test(req) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - t.Fatalf("status = %d", resp.StatusCode) - } - - var payload struct { - Data struct { - Introspection struct { - Project string `json:"project"` - RootResourceType string `json:"rootResourceType"` - AuthResourcePaths []string `json:"authResourcePaths"` - Root map[string]any `json:"root"` - RelatedResources []map[string]any `json:"relatedResources"` - Traversals []map[string]any `json:"traversals"` - Fields []map[string]any `json:"fields"` - PivotFields []map[string]any `json:"pivotFields"` - } `json:"dataframeBuilderIntrospection"` - } `json:"data"` - Errors []map[string]any `json:"errors"` - } - if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil { - t.Fatal(err) - } - if len(payload.Errors) != 0 { - t.Fatalf("unexpected graphql errors: %#v", payload.Errors) - } - if payload.Data.Introspection.Project != "P1" || payload.Data.Introspection.RootResourceType != "Patient" { - t.Fatalf("unexpected introspection header: %#v", payload.Data.Introspection) - } - if got := payload.Data.Introspection.AuthResourcePaths; len(got) != 1 || got[0] != "pathA" { - t.Fatalf("unexpected auth resource paths: %#v", got) - } - if len(payload.Data.Introspection.Traversals) != 1 || len(payload.Data.Introspection.Fields) == 0 || len(payload.Data.Introspection.PivotFields) != 1 { - t.Fatalf("unexpected response sizes: %#v", payload.Data.Introspection) - } - if payload.Data.Introspection.Root["resourceType"] != "Patient" || len(payload.Data.Introspection.RelatedResources) != 1 { - t.Fatalf("unexpected structured introspection: %#v", payload.Data.Introspection) - } - firstField, _ := payload.Data.Introspection.Fields[0]["selector"].(map[string]any) - if firstField == nil || firstField["valuePath"] == "" { - t.Fatalf("expected structured selector payload: %#v", payload.Data.Introspection.Fields[0]) - } -} - func TestGraphQLSchemaIntrospectionEndpoint(t *testing.T) { graphResolver := graphresolver.NewResolver(graphresolver.ResolverConfig{}) server, err := newGraphServer(graphResolver, authscope.StaticAuthenticator{Principal: authscope.Principal{Subject: "u1"}}) @@ -166,8 +67,8 @@ func TestGraphQLSchemaIntrospectionEndpoint(t *testing.T) { t.Fatal(err) } defer aliasResp.Body.Close() - if aliasResp.StatusCode != http.StatusOK { - t.Fatalf("flat compatibility alias status = %d", aliasResp.StatusCode) + if aliasResp.StatusCode != http.StatusNotFound { + t.Fatalf("retired flat alias status = %d, want %d", aliasResp.StatusCode, http.StatusNotFound) } } diff --git a/internal/api/graphql/graph/materialization/export.go b/internal/api/graphql/graph/materialization/export.go index 4468d362..fb45e9b6 100644 --- a/internal/api/graphql/graph/materialization/export.go +++ b/internal/api/graphql/graph/materialization/export.go @@ -24,7 +24,7 @@ func (s *Service) ExportDataframe(ctx context.Context, request dfmaterialization if err != nil { return err } - selector, err := s.resolvePublishedSelector(request.Selector, request.DataType) + selector, err := resolvePublishedSelector(request.Selector) if err != nil { return err } diff --git a/internal/api/graphql/graph/materialization/output.go b/internal/api/graphql/graph/materialization/output.go index 935e4b4e..6812c2e0 100644 --- a/internal/api/graphql/graph/materialization/output.go +++ b/internal/api/graphql/graph/materialization/output.go @@ -44,11 +44,6 @@ func Model(value materialization.Materialization) *model.DataframeMaterializatio } if value.Selector.Valid() { result.Selector = &model.DataframeSelector{Recipe: value.Selector.Recipe, TranslationVersion: value.Selector.TranslationVersion, Output: value.Selector.Output} - activeVersion := value.ActiveContractVersion - if activeVersion == "" { - activeVersion = value.Selector.TranslationVersion - } - result.ActiveContractVersion = &activeVersion } if value.Availability != "" { availability := model.DataframeAvailability(value.Availability) @@ -130,7 +125,7 @@ func FederatedMaterialization(dataset materialization.FederatedDataset) *model.D ID: "federated:" + dataset.Selector.Key(), Name: dataset.Name, Revision: dataset.Revision, DatasetGeneration: "federated:" + dataset.Revision, State: materialization.StateReady, Columns: dataset.Columns, RowCount: dataset.RowCount, RowCountKnown: dataset.RowCountComplete, - Selector: dataset.Selector, Availability: dataset.Availability, ExpectedProjects: dataset.ExpectedProjects, ProjectStatuses: dataset.ProjectStatuses, ActiveContractVersion: dataset.ActiveContractVersion, + Selector: dataset.Selector, Availability: dataset.Availability, ExpectedProjects: dataset.ExpectedProjects, ProjectStatuses: dataset.ProjectStatuses, }) } diff --git a/internal/api/graphql/graph/materialization/output_test.go b/internal/api/graphql/graph/materialization/output_test.go index 40854791..a31a2981 100644 --- a/internal/api/graphql/graph/materialization/output_test.go +++ b/internal/api/graphql/graph/materialization/output_test.go @@ -18,11 +18,11 @@ func TestPersistedFailureRedactsLegacyText(t *testing.T) { func TestFederationMetadataMapping(t *testing.T) { value := Model(dfpublished.Materialization{ ID: "federated", Name: "DocumentReference", Selector: dfpublished.DataframeSelector{Recipe: "documents", TranslationVersion: "v2", Output: "DocumentReference"}, - ActiveContractVersion: "v1", Availability: dfpublished.FederationDegraded, ExpectedProjects: 2, + Availability: dfpublished.FederationDegraded, ExpectedProjects: 2, IncludedProjects: 1, ProjectStatuses: []dfpublished.ProjectStatus{{ProjectID: "allowed", State: dfpublished.ProjectCurrent}, {ProjectID: "missing", State: dfpublished.ProjectMissing}}, }) - if value.Selector == nil || value.Selector.TranslationVersion != "v2" || value.ActiveContractVersion == nil || *value.ActiveContractVersion != "v1" { + if value.Selector == nil || value.Selector.TranslationVersion != "v2" { t.Fatalf("selector metadata = %#v", value) } if value.Availability == nil || *value.Availability != "DEGRADED" || value.Completeness == nil || *value.Completeness != .5 { diff --git a/internal/api/graphql/graph/materialization/service.go b/internal/api/graphql/graph/materialization/service.go index 5800b1ac..34946eaf 100644 --- a/internal/api/graphql/graph/materialization/service.go +++ b/internal/api/graphql/graph/materialization/service.go @@ -18,27 +18,21 @@ import ( ) type Service struct { - reader *dfmaterialization.Reader - scopeResolver *authscope.ScopeResolver - logger *slog.Logger - maxExportRows int64 - maxExportBytes int64 - defaultRecipe string - defaultTranslationVersion string - defaultContract func() (string, string) - candidateProjects func(context.Context) ([]string, error) + reader *dfmaterialization.Reader + scopeResolver *authscope.ScopeResolver + logger *slog.Logger + maxExportRows int64 + maxExportBytes int64 + candidateProjects func(context.Context) ([]string, error) } type Config struct { - Reader *dfmaterialization.Reader - ScopeResolver *authscope.ScopeResolver - Logger *slog.Logger - MaxExportRows int64 - MaxExportBytes int64 - DefaultRecipe string - DefaultTranslationVersion string - DefaultContract func() (string, string) - CandidateProjects func(context.Context) ([]string, error) + Reader *dfmaterialization.Reader + ScopeResolver *authscope.ScopeResolver + Logger *slog.Logger + MaxExportRows int64 + MaxExportBytes int64 + CandidateProjects func(context.Context) ([]string, error) } func NewService(cfg Config) *Service { @@ -51,20 +45,7 @@ func NewService(cfg Config) *Service { if cfg.Logger == nil { cfg.Logger = slog.Default() } - if cfg.Reader != nil { - cfg.Reader.LegacyTranslationVersion = strings.TrimSpace(cfg.DefaultTranslationVersion) - } - return &Service{reader: cfg.Reader, scopeResolver: cfg.ScopeResolver, logger: cfg.Logger, maxExportRows: cfg.MaxExportRows, maxExportBytes: cfg.MaxExportBytes, defaultRecipe: strings.TrimSpace(cfg.DefaultRecipe), defaultTranslationVersion: strings.TrimSpace(cfg.DefaultTranslationVersion), defaultContract: cfg.DefaultContract, candidateProjects: cfg.CandidateProjects} -} - -func (s *Service) contract() (string, string) { - if s.defaultContract != nil { - recipe, version := s.defaultContract() - if strings.TrimSpace(recipe) != "" && strings.TrimSpace(version) != "" { - return strings.TrimSpace(recipe), strings.TrimSpace(version) - } - } - return s.defaultRecipe, s.defaultTranslationVersion + return &Service{reader: cfg.Reader, scopeResolver: cfg.ScopeResolver, logger: cfg.Logger, maxExportRows: cfg.MaxExportRows, maxExportBytes: cfg.MaxExportBytes, candidateProjects: cfg.CandidateProjects} } func (s *Service) principal(ctx context.Context) (*authscope.Principal, error) { @@ -169,21 +150,6 @@ func containsProject(projects []string, project string) bool { return false } -// Get preserves the legacy published-materialization lookup by ID. -func (s *Service) Get(ctx context.Context, id string) (*dfmaterialization.Materialization, error) { - if s.reader == nil { - return nil, readerUnavailable() - } - value, err := s.reader.DatasetByPublishedID(ctx, id) - if err != nil { - return nil, mapReaderError(err) - } - if err := s.authorizePublished(ctx, value); err != nil { - return nil, err - } - return &value, nil -} - func (s *Service) Dataset(ctx context.Context, input model.DataframeDatasetInput) (*dfmaterialization.Materialization, error) { if s.reader == nil { return nil, readerUnavailable() @@ -192,7 +158,7 @@ func (s *Service) Dataset(ctx context.Context, input model.DataframeDatasetInput if err != nil { return nil, err } - selector, err := s.resolveSelector(input.Selector, input.DataType) + selector, err := resolveSelector(input.Selector) if err != nil { return nil, err } @@ -208,27 +174,10 @@ func (s *Service) Rows(ctx context.Context, input model.DataframeRowsInput) (dfm if s.reader == nil { return dfmaterialization.Page{}, readerUnavailable() } - selector, err := s.resolveSelector(input.Selector, input.DataType) + selector, err := resolveSelector(input.Selector) if err != nil { return dfmaterialization.Page{}, err } - if input.MaterializationID != nil && *input.MaterializationID != "" { - s.logger.Debug("dataframe rows start", "path", "published", "materialization_id", *input.MaterializationID) - value, err := s.reader.DatasetByPublishedID(ctx, *input.MaterializationID) - if err != nil { - s.logReadFailure(ctx, "published_materialization_lookup", selector.Output, err, "materialization_id", *input.MaterializationID) - return dfmaterialization.Page{}, mapReaderError(err) - } - if err := s.authorizePublished(ctx, value); err != nil { - return dfmaterialization.Page{}, err - } - page, err := s.reader.PagePublishedID(ctx, value.ID, pageRequest(input)) - if err != nil { - s.logReadFailure(ctx, "published_clickhouse_rows", selector.Output, err, "materialization_id", value.ID, "physical_table", value.PhysicalTable) - return dfmaterialization.Page{}, mapReaderError(err) - } - return page, nil - } principal, err := s.principal(ctx) if err != nil { s.logReadFailure(ctx, "principal_resolution", selector.Output, err) @@ -257,29 +206,10 @@ func (s *Service) AggregateInput(ctx context.Context, input model.DataframeAggre if s.reader == nil { return dfmaterialization.AggregateResult{}, readerUnavailable() } - selector, err := s.resolveSelector(input.Selector, input.DataType) + selector, err := resolveSelector(input.Selector) if err != nil { return dfmaterialization.AggregateResult{}, err } - if input.MaterializationID != nil && *input.MaterializationID != "" { - s.logger.Debug("dataframe aggregate start", "path", "published", "materialization_id", *input.MaterializationID, "operation", input.Operation, "group_by", input.GroupBy) - value, err := s.reader.DatasetByPublishedID(ctx, *input.MaterializationID) - if err != nil { - s.logReadFailure(ctx, "published_materialization_lookup", selector.Output, err, "materialization_id", *input.MaterializationID) - return dfmaterialization.AggregateResult{}, mapReaderError(err) - } - if err := s.authorizePublished(ctx, value); err != nil { - return dfmaterialization.AggregateResult{}, err - } - result, err := s.reader.AggregatePublishedID(ctx, value.ID, dfmaterialization.AggregateRequest{ - GroupBy: input.GroupBy, Filters: convertFilters(input.Filters), Operation: input.Operation, Column: stringValue(input.Column), - }) - if err != nil { - s.logReadFailure(ctx, "published_clickhouse_aggregate", selector.Output, err, "materialization_id", value.ID, "physical_table", value.PhysicalTable) - return dfmaterialization.AggregateResult{}, mapReaderError(err) - } - return result, nil - } principal, err := s.principal(ctx) if err != nil { s.logReadFailure(ctx, "principal_resolution", selector.Output, err) @@ -308,7 +238,7 @@ func (s *Service) AggregationsInput(ctx context.Context, input model.DataframeAg if s.reader == nil { return dfmaterialization.AggregationsResult{}, readerUnavailable() } - selector, err := s.resolveSelector(input.Selector, input.DataType) + selector, err := resolveSelector(input.Selector) if err != nil { return dfmaterialization.AggregationsResult{}, err } @@ -373,7 +303,6 @@ func (s *Service) authorizedFederation(ctx context.Context, principal *authscope } else if len(statuses) > 0 { dataset.ProjectStatuses = filterAuthorizedStatuses(candidates, statuses) } - _, dataset.ActiveContractVersion = s.contract() return dataset, map[string]dfmaterialization.SourceAccess{}, reconcileErr } s.logger.Debug("dataframe publication sources discovered", "request_id", httpapi.RequestIDFromContext(ctx), "selector", selector.Key(), "projects", candidates, "source_count", len(sources), "source_ids", materializationIDs(sources), "physical_tables", physicalTables(sources)) @@ -436,7 +365,6 @@ func (s *Service) authorizedFederation(ctx context.Context, principal *authscope } } dataset.RowCountComplete = rowCountComplete - _, dataset.ActiveContractVersion = s.contract() refreshAvailability(&dataset) return dataset, access, nil } @@ -471,46 +399,27 @@ func filterAuthorizedStatuses(projects []string, statuses []dfmaterialization.Pr return result } -func (s *Service) resolveSelector(input *model.DataframeSelectorInput, dataType *string) (dfmaterialization.DataframeSelector, error) { - legacy := "" - if dataType != nil { - legacy = strings.TrimSpace(*dataType) - } - if input != nil && dataType != nil { - return dfmaterialization.DataframeSelector{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidSelector, "", dataframeerrors.WithFieldPath("input")) - } - if input != nil { - selector := dfmaterialization.DataframeSelector{Recipe: strings.TrimSpace(input.Recipe), TranslationVersion: strings.TrimSpace(input.TranslationVersion), Output: strings.TrimSpace(input.Output)} - if !selector.Valid() { - return dfmaterialization.DataframeSelector{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidSelector, "", dataframeerrors.WithFieldPath("input", "selector")) - } - return selector, nil +func resolveSelector(input *model.DataframeSelectorInput) (dfmaterialization.DataframeSelector, error) { + if input == nil { + return dfmaterialization.DataframeSelector{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidSelector, "", dataframeerrors.WithFieldPath("input", "selector")) } - defaultRecipe, defaultVersion := s.contract() - if legacy == "" || defaultRecipe == "" || defaultVersion == "" { - return dfmaterialization.DataframeSelector{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidSelector, "", dataframeerrors.WithFieldPath("input")) + selector := dfmaterialization.DataframeSelector{Recipe: strings.TrimSpace(input.Recipe), TranslationVersion: strings.TrimSpace(input.TranslationVersion), Output: strings.TrimSpace(input.Output)} + if !selector.Valid() { + return dfmaterialization.DataframeSelector{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidSelector, "", dataframeerrors.WithFieldPath("input", "selector")) } - return dfmaterialization.DataframeSelector{Recipe: defaultRecipe, TranslationVersion: defaultVersion, Output: legacy}, nil + return selector, nil } -func (s *Service) resolvePublishedSelector(input *dfmaterialization.DataframeSelector, dataType string) (dfmaterialization.DataframeSelector, error) { - legacy := strings.TrimSpace(dataType) - if input != nil && legacy != "" { +func resolvePublishedSelector(input *dfmaterialization.DataframeSelector) (dfmaterialization.DataframeSelector, error) { + if input == nil { return dfmaterialization.DataframeSelector{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidSelector, "") } - if input != nil { - selector := *input - selector.Recipe, selector.TranslationVersion, selector.Output = strings.TrimSpace(selector.Recipe), strings.TrimSpace(selector.TranslationVersion), strings.TrimSpace(selector.Output) - if !selector.Valid() { - return dfmaterialization.DataframeSelector{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidSelector, "") - } - return selector, nil - } - defaultRecipe, defaultVersion := s.contract() - if legacy == "" || defaultRecipe == "" || defaultVersion == "" { + selector := *input + selector.Recipe, selector.TranslationVersion, selector.Output = strings.TrimSpace(selector.Recipe), strings.TrimSpace(selector.TranslationVersion), strings.TrimSpace(selector.Output) + if !selector.Valid() { return dfmaterialization.DataframeSelector{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidSelector, "") } - return dfmaterialization.DataframeSelector{Recipe: defaultRecipe, TranslationVersion: defaultVersion, Output: legacy}, nil + return selector, nil } // filterProjects applies authoritative project_id equality/IN constraints @@ -645,12 +554,8 @@ func (s *Service) authorizePublished(ctx context.Context, value dfmaterializatio return nil } -func pageRequest(input model.DataframeRowsInput) dfmaterialization.PageRequest { - return dfmaterialization.PageRequest{Columns: input.Columns, Filters: convertFilters(input.Filters), Sort: convertSort(input), First: intValue(input.First), After: stringValue(input.After)} -} - func federatedMaterialization(dataset dfmaterialization.FederatedDataset) dfmaterialization.Materialization { - return dfmaterialization.Materialization{ID: "federated:" + dataset.Selector.Key(), Name: dataset.Name, Revision: dataset.Revision, DatasetGeneration: "federated:" + dataset.Revision, State: dfmaterialization.StateReady, Columns: dataset.Columns, RowCount: dataset.RowCount, RowCountKnown: dataset.RowCountComplete, Selector: dataset.Selector, Availability: dataset.Availability, IncludedProjects: len(dataset.Sources), ExpectedProjects: dataset.ExpectedProjects, ProjectStatuses: append([]dfmaterialization.ProjectStatus(nil), dataset.ProjectStatuses...), ActiveContractVersion: dataset.ActiveContractVersion} + return dfmaterialization.Materialization{ID: "federated:" + dataset.Selector.Key(), Name: dataset.Name, Revision: dataset.Revision, DatasetGeneration: "federated:" + dataset.Revision, State: dfmaterialization.StateReady, Columns: dataset.Columns, RowCount: dataset.RowCount, RowCountKnown: dataset.RowCountComplete, Selector: dataset.Selector, Availability: dataset.Availability, IncludedProjects: len(dataset.Sources), ExpectedProjects: dataset.ExpectedProjects, ProjectStatuses: append([]dfmaterialization.ProjectStatus(nil), dataset.ProjectStatuses...)} } func convertFilters(filters []*model.DataframeFilterInput) []dfmaterialization.Filter { diff --git a/internal/api/graphql/graph/materialization/service_test.go b/internal/api/graphql/graph/materialization/service_test.go index e7b24f39..a2cae642 100644 --- a/internal/api/graphql/graph/materialization/service_test.go +++ b/internal/api/graphql/graph/materialization/service_test.go @@ -43,46 +43,16 @@ func TestProjectsReportsEmptyPublicationCatalogAsDatasetNotFound(t *testing.T) { } } -func TestResolveSelectorRejectsAmbiguousInputs(t *testing.T) { - service := NewService(Config{DefaultRecipe: "default", DefaultTranslationVersion: "v1"}) - legacy := "Patient" - _, err := service.resolveSelector(&model.DataframeSelectorInput{Recipe: "other", TranslationVersion: "v2", Output: "Patient"}, &legacy) - userErr, ok := dataframeerrors.AsUserError(err) - if !ok || userErr.Code() != string(dataframeerrors.CodeInvalidSelector) { - t.Fatalf("error = %v", err) - } -} - -func TestResolveLegacyDataTypeUsesPromotedDefaultContract(t *testing.T) { - service := NewService(Config{DefaultRecipe: "default", DefaultTranslationVersion: "v7"}) - legacy := "Patient" - selector, err := service.resolveSelector(nil, &legacy) +func TestResolveSelectorRequiresCompleteExplicitSelector(t *testing.T) { + selector, err := resolveSelector(&model.DataframeSelectorInput{Recipe: "documents", TranslationVersion: "v2", Output: "Patient"}) if err != nil { t.Fatal(err) } - if selector.Recipe != "default" || selector.TranslationVersion != "v7" || selector.Output != "Patient" { + if selector.Recipe != "documents" || selector.TranslationVersion != "v2" || selector.Output != "Patient" { t.Fatalf("selector = %#v", selector) } } -func TestResolveLegacyDataTypeObservesExplicitContractPromotion(t *testing.T) { - recipeName, version := "default", "v1" - service := NewService(Config{DefaultContract: func() (string, string) { return recipeName, version }}) - legacy := "Patient" - first, err := service.resolveSelector(nil, &legacy) - if err != nil { - t.Fatal(err) - } - version = "v2" - second, err := service.resolveSelector(nil, &legacy) - if err != nil { - t.Fatal(err) - } - if first.TranslationVersion != "v1" || second.TranslationVersion != "v2" { - t.Fatalf("selectors before/after promotion = %#v %#v", first, second) - } -} - func TestProjectFilterNarrowsBeforeFederation(t *testing.T) { projects := []string{"a", "b", "c"} filtered := filterProjects(projects, []dfpublished.Filter{{Column: "project_id", Op: "IN", Value: []any{"b", "c"}}}) diff --git a/internal/api/graphql/graph/resolver/graphql_output_helpers.go b/internal/api/graphql/graph/resolver/graphql_output_helpers.go new file mode 100644 index 00000000..58b8d2f7 --- /dev/null +++ b/internal/api/graphql/graph/resolver/graphql_output_helpers.go @@ -0,0 +1,22 @@ +package resolver + +import ( + "encoding/json" + + dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" +) + +func graphqlRows(in []map[string]any) (json.RawMessage, error) { + encoded, err := json.Marshal(in) + if err != nil { + return nil, dataframeerrors.Wrap(err, dataframeerrors.CodeOutputEncodingFailed, "") + } + return json.RawMessage(encoded), nil +} + +func cloneStrings(in []string) []string { + if len(in) == 0 { + return []string{} + } + return append([]string(nil), in...) +} diff --git a/internal/api/graphql/graph/resolver/output_mapping.go b/internal/api/graphql/graph/resolver/output_mapping.go deleted file mode 100644 index c26593d6..00000000 --- a/internal/api/graphql/graph/resolver/output_mapping.go +++ /dev/null @@ -1,149 +0,0 @@ -package resolver - -import ( - "encoding/json" - "strings" - - "github.com/calypr/loom/generated/graphql/graph/model" - queryapi "github.com/calypr/loom/internal/api/graphql/graph/query" - "github.com/calypr/loom/internal/catalog" - dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" -) - -func traversalHints(in []catalog.PopulatedReference) []*model.DataframeTraversalHint { - if len(in) == 0 { - return []*model.DataframeTraversalHint{} - } - out := make([]*model.DataframeTraversalHint, 0, len(in)) - for _, item := range in { - out = append(out, &model.DataframeTraversalHint{ - FromType: item.FromType, - Label: item.Label, - ToType: item.ToType, - EdgeCount: int(item.EdgeCount), - }) - } - return out -} - -func fieldHints(in []queryapi.FieldHint) []*model.DataframeFieldHint { - if len(in) == 0 { - return []*model.DataframeFieldHint{} - } - out := make([]*model.DataframeFieldHint, 0, len(in)) - for _, item := range in { - pivotKind := item.PivotKind - var pivotKindPtr *string - if pivotKind != "" { - pivotKindPtr = &pivotKind - } - - var pivotFamily *model.FhirPivotFamily - if item.PivotFamily != "" { - family := model.FhirPivotFamily(item.PivotFamily) - pivotFamily = &family - } - - var predicate *model.DataframeFieldPredicate - if item.Selector.Where != nil { - predicate = &model.DataframeFieldPredicate{ - Path: item.Selector.Where.Path, - Op: model.FhirFieldPredicateOperation(item.Selector.Where.Op), - Value: item.Selector.Where.Value, - } - } - - out = append(out, &model.DataframeFieldHint{ - ResourceType: item.ResourceType, - FieldRef: item.FieldRef, - Label: item.Label, - Path: item.Path, - Selector: &model.DataframeFieldSelector{ - SourcePath: optionalString(item.Selector.SourcePath), - Where: predicate, - ValuePath: item.Selector.ValuePath, - }, - Kind: item.Kind, - DocCount: int(item.DocCount), - SampleCount: item.SampleCount, - DistinctValues: cloneStrings(item.DistinctValues), - DistinctTruncated: item.DistinctTruncated, - PivotCandidate: item.PivotCandidate, - PivotKind: pivotKindPtr, - PivotColumns: cloneStrings(item.PivotColumns), - PivotFamily: pivotFamily, - DefaultPivotColumnSelector: selectorModelFromExpression(item.PivotColumnSelect), - DefaultPivotValueSelector: selectorModelFromExpression(item.PivotValueSelect), - }) - } - return out -} - -func resourceHints(in queryapi.ResourceHints) *model.DataframeResourceHints { - return &model.DataframeResourceHints{ - ResourceType: in.ResourceType, - Fields: fieldHints(in.Fields), - PivotFields: fieldHints(in.PivotFields), - Traversals: traversalHints(in.Traversals), - } -} - -func relatedResourceHints(in []queryapi.RelatedResourceHints) []*model.DataframeRelatedResourceHints { - if len(in) == 0 { - return []*model.DataframeRelatedResourceHints{} - } - out := make([]*model.DataframeRelatedResourceHints, 0, len(in)) - for _, item := range in { - out = append(out, &model.DataframeRelatedResourceHints{ - ViaLabel: item.ViaLabel, - EdgeCount: int(item.EdgeCount), - Target: resourceHints(item.Target), - }) - } - return out -} - -func selectorModelFromExpression(expression string) *model.DataframeFieldSelector { - if strings.TrimSpace(expression) == "" { - return nil - } - parts := queryapi.DecomposeSelector(expression) - - var predicate *model.DataframeFieldPredicate - if parts.Where != nil { - predicate = &model.DataframeFieldPredicate{ - Path: parts.Where.Path, - Op: model.FhirFieldPredicateOperation(parts.Where.Op), - Value: parts.Where.Value, - } - } - - return &model.DataframeFieldSelector{ - SourcePath: optionalString(parts.SourcePath), - Where: predicate, - ValuePath: parts.ValuePath, - } -} - -func graphqlRows(in []map[string]any) (json.RawMessage, error) { - encoded, err := json.Marshal(in) - if err != nil { - return nil, dataframeerrors.Wrap(err, dataframeerrors.CodeOutputEncodingFailed, "") - } - return json.RawMessage(encoded), nil -} - -func cloneStrings(in []string) []string { - if len(in) == 0 { - return []string{} - } - return append([]string(nil), in...) -} - -func optionalString(in string) *string { - in = strings.TrimSpace(in) - if in == "" { - return nil - } - return &in -} diff --git a/internal/api/graphql/graph/resolver/recipe_control_test.go b/internal/api/graphql/graph/resolver/recipe_control_test.go index cecb0d7d..827c426e 100644 --- a/internal/api/graphql/graph/resolver/recipe_control_test.go +++ b/internal/api/graphql/graph/resolver/recipe_control_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/calypr/loom/generated/graphql/graph/model" - "github.com/calypr/loom/internal/authscope" materialization "github.com/calypr/loom/internal/dataframe/publication" "github.com/calypr/loom/internal/dataframe/recipe" "github.com/calypr/loom/internal/dataframe/recipe/engine" @@ -220,21 +219,4 @@ func TestStartDataframeMaterializationPassesExactSelector(t *testing.T) { } } -func TestPromoteDataframeContractRequiresOperatorAuthorization(t *testing.T) { - called := 0 - promoter := func(context.Context, string, string) (DataframeContract, error) { - called++ - return DataframeContract{Recipe: "documents", TranslationVersion: "v2"}, nil - } - input := model.PromoteDataframeContractInput{Recipe: "documents", TranslationVersion: "v2"} - denied := NewResolver(ResolverConfig{DataframeContractPromoter: promoter, DataframeContractAuthorizer: func(context.Context) error { return authscope.ErrForbidden }}) - if _, err := denied.Mutation().PromoteDataframeContract(context.Background(), input); err == nil || called != 0 { - t.Fatalf("denied promotion error=%v calls=%d", err, called) - } - allowed := NewResolver(ResolverConfig{DataframeContractPromoter: promoter, DataframeContractAuthorizer: func(context.Context) error { return nil }}) - if _, err := allowed.Mutation().PromoteDataframeContract(context.Background(), input); err != nil || called != 1 { - t.Fatalf("allowed promotion error=%v calls=%d", err, called) - } -} - func stringPtr(value string) *string { return &value } diff --git a/internal/api/graphql/graph/resolver/resolver.go b/internal/api/graphql/graph/resolver/resolver.go index 66ba5031..3c04fdce 100644 --- a/internal/api/graphql/graph/resolver/resolver.go +++ b/internal/api/graphql/graph/resolver/resolver.go @@ -3,7 +3,6 @@ package resolver import ( "context" "log/slog" - "os" "github.com/calypr/loom/generated/graphql/graph/model" materializationapi "github.com/calypr/loom/internal/api/graphql/graph/materialization" @@ -68,9 +67,11 @@ type RecipeExecutionReader func(context.Context, string) (*RecipeExecution, erro type ExactMaterializationStarter func(context.Context, dataset.DataframeSelector, recipe.RuntimeBindings) (RecipeExecution, error) type ProjectRelease struct{ ID, Project, Generation, Revision, State string } type ProjectReleaseActivator func(context.Context, string, string, string) (ProjectRelease, error) -type DataframeContract struct{ Recipe, TranslationVersion, PromotedAt string } -type DataframeContractPromoter func(context.Context, string, string) (DataframeContract, error) -type DataframeContractAuthorizer func(context.Context) error + +// ExplorerBundleMaterializer is retained as the shared publication capability +// used by the REST V2 lifecycle. GraphQL no longer owns Explorer lifecycle +// mutations. +type ExplorerBundleMaterializer func(context.Context, recipe.Bundle, recipe.RuntimeBindings) (RecipeExecution, error) // RecipeAuthorizer resolves request bindings against the caller's project // grants. GraphQL operation type is intentionally irrelevant: preview/run are @@ -89,8 +90,6 @@ type Resolver struct { recipeAuthorizer RecipeAuthorizer exactMaterializationStarter ExactMaterializationStarter projectReleaseActivator ProjectReleaseActivator - dataframeContractPromoter DataframeContractPromoter - dataframeContractAuthorizer DataframeContractAuthorizer recipeRevisions recipe.RevisionStore } @@ -102,34 +101,20 @@ type ResolverConfig struct { RecipeMaterialize RecipeMaterializeFunc RecipeExecutions RecipeExecutionReader RecipeAuthorizer RecipeAuthorizer - DefaultRecipe string - DefaultTranslationVersion string - DefaultContract func() (string, string) ExactMaterializationStarter ExactMaterializationStarter ProjectReleaseActivator ProjectReleaseActivator - DataframeContractPromoter DataframeContractPromoter - DataframeContractAuthorizer DataframeContractAuthorizer CandidateProjects func(context.Context) ([]string, error) RecipeRevisions recipe.RevisionStore } func NewResolver(cfg ResolverConfig) *Resolver { - if cfg.DefaultRecipe == "" { - cfg.DefaultRecipe = os.Getenv("LOOM_DEFAULT_RECIPE") - } - if cfg.DefaultTranslationVersion == "" { - cfg.DefaultTranslationVersion = os.Getenv("LOOM_DEFAULT_TRANSLATION_VERSION") - } return &Resolver{ query: queryapi.NewService(cfg.DataframeQuery), materializations: materializationapi.NewService(materializationapi.Config{ - Reader: cfg.MaterializationReader, - ScopeResolver: cfg.DataframeQuery.ScopeResolver, - Logger: cfg.Logger, - DefaultRecipe: cfg.DefaultRecipe, - DefaultTranslationVersion: cfg.DefaultTranslationVersion, - DefaultContract: cfg.DefaultContract, - CandidateProjects: cfg.CandidateProjects, + Reader: cfg.MaterializationReader, + ScopeResolver: cfg.DataframeQuery.ScopeResolver, + Logger: cfg.Logger, + CandidateProjects: cfg.CandidateProjects, }), recipeControl: cfg.RecipeControl, recipeMaterialize: cfg.RecipeMaterialize, @@ -137,8 +122,6 @@ func NewResolver(cfg ResolverConfig) *Resolver { recipeAuthorizer: cfg.RecipeAuthorizer, exactMaterializationStarter: cfg.ExactMaterializationStarter, projectReleaseActivator: cfg.ProjectReleaseActivator, - dataframeContractPromoter: cfg.DataframeContractPromoter, - dataframeContractAuthorizer: cfg.DataframeContractAuthorizer, recipeRevisions: cfg.RecipeRevisions, } } diff --git a/internal/api/graphql/graph/resolver/schema.resolvers.go b/internal/api/graphql/graph/resolver/schema.resolvers.go index 8c8103af..9b65af65 100644 --- a/internal/api/graphql/graph/resolver/schema.resolvers.go +++ b/internal/api/graphql/graph/resolver/schema.resolvers.go @@ -14,8 +14,6 @@ import ( "github.com/calypr/loom/generated/graphql/graph/executor" "github.com/calypr/loom/generated/graphql/graph/model" materializationapi "github.com/calypr/loom/internal/api/graphql/graph/materialization" - queryapi "github.com/calypr/loom/internal/api/graphql/graph/query" - "github.com/calypr/loom/internal/authscope" dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" "github.com/calypr/loom/internal/dataframe/recipe" "github.com/calypr/loom/internal/dataset" @@ -181,28 +179,6 @@ func (r *mutationResolver) ActivateProjectRelease(ctx context.Context, input mod return &model.ProjectRelease{ID: release.ID, Project: release.Project, Generation: release.Generation, Revision: release.Revision, State: model.ProjectReleaseState(release.State)}, nil } -// PromoteDataframeContract is the resolver for the promoteDataframeContract field. -func (r *mutationResolver) PromoteDataframeContract(ctx context.Context, input model.PromoteDataframeContractInput) (*model.DataframeContract, error) { - recipeName, version := strings.TrimSpace(input.Recipe), strings.TrimSpace(input.TranslationVersion) - if recipeName == "" || version == "" { - return nil, recipeGraphQLError(dataframeerrors.NewError(dataframeerrors.CodeInvalidSelector, "")) - } - if r.dataframeContractAuthorizer == nil { - return nil, recipeGraphQLError(authscope.ErrForbidden) - } - if err := r.dataframeContractAuthorizer(ctx); err != nil { - return nil, recipeGraphQLError(err) - } - if r.dataframeContractPromoter == nil { - return nil, recipeGraphQLError(dataframeerrors.NewError(dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true))) - } - contract, err := r.dataframeContractPromoter(ctx, recipeName, version) - if err != nil { - return nil, recipeGraphQLError(err) - } - return &model.DataframeContract{Recipe: contract.Recipe, TranslationVersion: contract.TranslationVersion, PromotedAt: contract.PromotedAt}, nil -} - // RegisterDataframeRecipeRevision is the resolver for the registerDataframeRecipeRevision field. func (r *mutationResolver) RegisterDataframeRecipeRevision(ctx context.Context, input model.RegisterDataframeRecipeRevisionInput) (*model.DataframeRecipeRevision, error) { if r.recipeRevisions == nil { @@ -226,42 +202,6 @@ func (r *mutationResolver) RegisterDataframeRecipeRevision(ctx context.Context, return recipeRevisionModel(value), nil } -// DataframeBuilderIntrospection is the resolver for the dataframeBuilderIntrospection field. -func (r *queryResolver) DataframeBuilderIntrospection(ctx context.Context, input model.DataframeBuilderIntrospectionInput) (*model.DataframeBuilderIntrospection, error) { - includePivotOnlyFields := true - if input.IncludePivotOnlyFields != nil { - includePivotOnlyFields = *input.IncludePivotOnlyFields - } - resp, err := r.query.Introspect(ctx, queryapi.IntrospectionRequest{ - Project: input.Project, - RootResourceType: input.RootResourceType, - AuthResourcePaths: input.AuthResourcePaths, - IncludePivotOnlyFields: includePivotOnlyFields, - }) - if err != nil { - return nil, err - } - return &model.DataframeBuilderIntrospection{ - Project: resp.Project, - RootResourceType: resp.RootResourceType, - AuthResourcePaths: append([]string(nil), resp.AuthResourcePaths...), - Root: resourceHints(resp.Root), - RelatedResources: relatedResourceHints(resp.RelatedResources), - Traversals: traversalHints(resp.Traversals), - Fields: fieldHints(resp.Fields), - PivotFields: fieldHints(resp.PivotFields), - }, nil -} - -// DataframeMaterialization is the resolver for the dataframeMaterialization field. -func (r *queryResolver) DataframeMaterialization(ctx context.Context, id string) (*model.DataframeMaterialization, error) { - value, err := r.materializations.Get(ctx, id) - if err != nil { - return nil, err - } - return materializationapi.Model(*value), nil -} - // DataframeDatasets is the resolver for the dataframeDatasets field. func (r *queryResolver) DataframeDatasets(ctx context.Context) ([]*model.DataframeMaterialization, error) { values, err := r.materializations.Datasets(ctx) diff --git a/internal/api/graphql/graph/schema/schema.graphqls b/internal/api/graphql/graph/schema/schema.graphqls index 3d3652dc..df72c513 100644 --- a/internal/api/graphql/graph/schema/schema.graphqls +++ b/internal/api/graphql/graph/schema/schema.graphqls @@ -1,9 +1,4 @@ type Query { - dataframeBuilderIntrospection( - input: DataframeBuilderIntrospectionInput! - ): DataframeBuilderIntrospection! - - dataframeMaterialization(id: ID!): DataframeMaterialization dataframeDatasets: [DataframeMaterialization!]! projectDataframeDatasets(projectId: String!): [DataframeMaterialization!]! dataframeDataset(input: DataframeDatasetInput!): DataframeMaterialization @@ -32,7 +27,6 @@ type Mutation { materializeDataframeRecipeBundle(input: MaterializeDataframeRecipeInput!): DataframeRecipeExecution! startDataframeMaterialization(input: StartDataframeMaterializationInput!): DataframeRecipeExecution! activateProjectRelease(input: ActivateProjectReleaseInput!): ProjectRelease! - promoteDataframeContract(input: PromoteDataframeContractInput!): DataframeContract! registerDataframeRecipeRevision(input: RegisterDataframeRecipeRevisionInput!): DataframeRecipeRevision! } @@ -58,17 +52,6 @@ type ProjectRelease { enum ProjectReleaseState { ACTIVE } -input PromoteDataframeContractInput { - recipe: String! - translationVersion: String! -} - -type DataframeContract { - recipe: String! - translationVersion: String! - promotedAt: String! -} - input RegisterDataframeRecipeRevisionInput { projectId: String! name: String! @@ -377,7 +360,6 @@ type DataframeMaterialization { errorCode: String errorRetryable: Boolean selector: DataframeSelector - activeContractVersion: String availability: DataframeAvailability completeness: Float includedProjectCount: Int @@ -424,8 +406,7 @@ type DataframeProjectStatus { } input DataframeDatasetInput { - selector: DataframeSelectorInput - dataType: String @deprecated(reason: "Use selector") + selector: DataframeSelectorInput! } input DataframeFilterInput { @@ -440,11 +421,7 @@ input DataframeSortInput { } input DataframeRowsInput { - # Legacy callers may target one published physical materialization directly. - # When omitted, the request uses the project-federated dataframe. - materializationId: ID - selector: DataframeSelectorInput - dataType: String @deprecated(reason: "Use selector") + selector: DataframeSelectorInput! columns: [String!] filters: [DataframeFilterInput!] sort: DataframeSortInput @@ -466,11 +443,7 @@ type DataframeRowConnection { } input DataframeAggregateInput { - # Legacy callers may target one published physical materialization directly. - # When omitted, the request uses the project-federated dataframe. - materializationId: ID - selector: DataframeSelectorInput - dataType: String @deprecated(reason: "Use selector") + selector: DataframeSelectorInput! groupBy: [String!] filters: [DataframeFilterInput!] operation: String! @@ -494,8 +467,7 @@ input DataframeAggregationSpecInput { } input DataframeAggregationsInput { - selector: DataframeSelectorInput - dataType: String @deprecated(reason: "Use selector") + selector: DataframeSelectorInput! filters: [DataframeFilterInput!] specs: [DataframeAggregationSpecInput!]! } @@ -505,80 +477,6 @@ type DataframeAggregationsResult { aggregations: JSON! } -input DataframeBuilderIntrospectionInput { - project: String! - rootResourceType: String! - authResourcePaths: [String!] - includePivotOnlyFields: Boolean = true -} - -type DataframeBuilderIntrospection { - project: String! - rootResourceType: String! - authResourcePaths: [String!]! - root: DataframeResourceHints! - relatedResources: [DataframeRelatedResourceHints!]! - traversals: [DataframeTraversalHint!]! - fields: [DataframeFieldHint!]! - pivotFields: [DataframeFieldHint!]! -} - -type DataframeResourceHints { - resourceType: String! - fields: [DataframeFieldHint!]! - pivotFields: [DataframeFieldHint!]! - traversals: [DataframeTraversalHint!]! -} - -type DataframeRelatedResourceHints { - viaLabel: String! - edgeCount: Int! - target: DataframeResourceHints! -} - -type DataframeTraversalHint { - fromType: String! - label: String! - toType: String! - edgeCount: Int! -} - -type DataframeFieldHint { - resourceType: String! - fieldRef: String! - label: String! - path: String! - selector: DataframeFieldSelector! - kind: String! - docCount: Int! - sampleCount: Int! - distinctValues: [String!]! - distinctTruncated: Boolean! - pivotCandidate: Boolean! - pivotKind: String - pivotColumns: [String!]! - pivotFamily: FhirPivotFamily - defaultPivotColumnSelector: DataframeFieldSelector - defaultPivotValueSelector: DataframeFieldSelector -} - -type DataframeFieldSelector { - sourcePath: String - where: DataframeFieldPredicate - valuePath: String! -} - -type DataframeFieldPredicate { - path: String! - op: FhirFieldPredicateOperation! - value: String! -} - -enum FhirPivotFamily { - CODEABLE_CONCEPT - OBSERVATION_CODE_VALUE -} - input FhirFieldSelectInput { name: String! fieldRef: String diff --git a/internal/api/http/errors.go b/internal/api/http/errors.go index 669fe4eb..150f9506 100644 --- a/internal/api/http/errors.go +++ b/internal/api/http/errors.go @@ -154,7 +154,7 @@ func normalizeHTTPCode(code string) string { code = strings.ToUpper(strings.TrimSpace(code)) code = strings.ReplaceAll(code, "-", "_") switch code { - case "PROJECT_REQUIRED", "ROOT_RESOURCE_TYPE_REQUIRED", "UNAUTHORIZED_PROJECT", "UNKNOWN_FIELD", "FIELD_NOT_POPULATED", "INVALID_TRAVERSAL", "UNSAFE_TRAVERSAL_ROUTE", "INVALID_FILTER", "UNBOUNDED_PIVOT", "INVALID_PIVOT_COLUMN", "INVALID_SLICE", "PLAN_TOO_EXPENSIVE", "INVALID_CURSOR", "STALE_CURSOR", "DATASET_GENERATION_CHANGED", "UNSUPPORTED_EXPORT_FORMAT", "CLIENT_CANCELED", "BACKEND_UNAVAILABLE", "DATASET_NOT_FOUND", "SCHEMA_CONFLICT", "INVALID_RESOURCE_TYPE", "NO_ACTIVE_GENERATION", "RESOURCE_DECODE_FAILED", "REFERENCE_NOT_RESOLVED", "QUERY_DEPTH_EXCEEDED", "INVALID_REQUEST", "INVALID_DATA", "UNAUTHENTICATED", "FORBIDDEN", "RECIPE_NOT_FOUND", "RECIPE_RESOLUTION_FAILED", "RECIPE_EXECUTION_NOT_FOUND", "EXPORT_LIMIT_EXCEEDED", "INGEST_PREFLIGHT_FAILED", "GENERATION_LOAD_INCOMPLETE", "GENERATION_ACTIVATION_UNKNOWN", "INVALID_GENERATION_FILE", "DUPLICATE_GENERATION_FILE", "PUBLICATION_IN_PROGRESS", "PUBLICATION_CONFLICT", "PUBLICATION_LEASE_LOST", "OUTPUT_ENCODING_FAILED", "NOT_FOUND", "METHOD_NOT_ALLOWED", "PAYLOAD_TOO_LARGE", "GRAPHQL_VALIDATION_FAILED": + case "PROJECT_REQUIRED", "ROOT_RESOURCE_TYPE_REQUIRED", "UNAUTHORIZED_PROJECT", "UNKNOWN_FIELD", "FIELD_NOT_POPULATED", "INVALID_TRAVERSAL", "UNSAFE_TRAVERSAL_ROUTE", "INVALID_FILTER", "UNBOUNDED_PIVOT", "INVALID_PIVOT_COLUMN", "INVALID_SLICE", "PLAN_TOO_EXPENSIVE", "INVALID_CURSOR", "STALE_CURSOR", "DATASET_GENERATION_CHANGED", "UNSUPPORTED_EXPORT_FORMAT", "CLIENT_CANCELED", "BACKEND_UNAVAILABLE", "DATASET_NOT_FOUND", "SCHEMA_CONFLICT", "INVALID_RESOURCE_TYPE", "NO_ACTIVE_GENERATION", "RESOURCE_DECODE_FAILED", "REFERENCE_NOT_RESOLVED", "QUERY_DEPTH_EXCEEDED", "INVALID_REQUEST", "INVALID_DATA", "INVALID_SELECTOR", "UNAUTHENTICATED", "FORBIDDEN", "RECIPE_NOT_FOUND", "RECIPE_RESOLUTION_FAILED", "RECIPE_EXECUTION_NOT_FOUND", "EXPORT_LIMIT_EXCEEDED", "INGEST_PREFLIGHT_FAILED", "GENERATION_LOAD_INCOMPLETE", "GENERATION_ACTIVATION_UNKNOWN", "INVALID_GENERATION_FILE", "DUPLICATE_GENERATION_FILE", "PUBLICATION_IN_PROGRESS", "PUBLICATION_CONFLICT", "PUBLICATION_LEASE_LOST", "OUTPUT_ENCODING_FAILED", "NOT_FOUND", "METHOD_NOT_ALLOWED", "PAYLOAD_TOO_LARGE", "GRAPHQL_VALIDATION_FAILED": return code default: return "INTERNAL_ERROR" @@ -173,6 +173,8 @@ func statusForCode(code string, fallback int) int { return http.StatusConflict case "INVALID_DATA", "RECIPE_RESOLUTION_FAILED", "INGEST_PREFLIGHT_FAILED", "GENERATION_LOAD_INCOMPLETE": return http.StatusUnprocessableEntity + case "INVALID_SELECTOR", "INVALID_REQUEST", "INVALID_LIMIT", "INVALID_RESOURCE_TYPE": + return http.StatusBadRequest case "GENERATION_ACTIVATION_UNKNOWN": return http.StatusConflict case "PUBLICATION_IN_PROGRESS", "PUBLICATION_CONFLICT": diff --git a/internal/api/http/recipe_execution.go b/internal/api/http/recipe_execution.go index 91a9f31e..1f0740cc 100644 --- a/internal/api/http/recipe_execution.go +++ b/internal/api/http/recipe_execution.go @@ -49,7 +49,7 @@ func RegisterRecipeExecutionRoute(app *fiber.App, catalog publication.BundleCata } columns = append(columns, fiber.Map{"name": column.Name, "semanticPath": column.SemanticPath, "clickhouseType": column.ClickHouse, "logicalType": logical, "nullable": nullable, "repeated": repeated, "filterable": filterable, "sortable": sortable, "aggregatable": aggregatable}) } - outputs = append(outputs, fiber.Map{"name": output.Name, "dataType": output.Name, "state": recipeExecutionHTTPState(output.State), "rowCount": output.RowCount, "columns": columns}) + outputs = append(outputs, fiber.Map{"name": output.Name, "state": recipeExecutionHTTPState(output.State), "rowCount": output.RowCount, "columns": columns}) } return c.JSON(fiber.Map{"id": execution.ID, "projectId": execution.Project, "datasetGeneration": execution.DatasetGeneration, "recipeDigest": execution.RecipeDigest, "schemaDigest": execution.SchemaDigest, "resolvedSchemaDigest": execution.SchemaDigest, "state": recipeExecutionHTTPState(execution.State), "outputs": outputs}) }) diff --git a/internal/dataframe/errors/errors.go b/internal/dataframe/errors/errors.go index 5e1da4d9..5e255e04 100644 --- a/internal/dataframe/errors/errors.go +++ b/internal/dataframe/errors/errors.go @@ -349,7 +349,7 @@ func defaultMessage(code ErrorCode) string { case CodeFederationIncompatible: return "published sources cannot share a logical schema" case CodeInvalidSelector: - return "exactly one dataframe selector or legacy dataType is required" + return "a complete dataframe selector is required" default: return "internal server error" } diff --git a/internal/dataframe/publication/clickhouse/clickhouse_bundle_test.go b/internal/dataframe/publication/clickhouse/clickhouse_bundle_test.go index 5df7b30c..6aa086e9 100644 --- a/internal/dataframe/publication/clickhouse/clickhouse_bundle_test.go +++ b/internal/dataframe/publication/clickhouse/clickhouse_bundle_test.go @@ -260,8 +260,8 @@ func TestClickHouseBundleStoreReconcileFinishesClaimedCleanupAfterCancellation(t func TestPublishedOutputResolutionIsProjectAndGenerationScoped(t *testing.T) { catalog := newBundleCatalogFixture() identities := []publication.BundleIdentity{ - {Name: "observation", Project: "project-a", DatasetGeneration: "generation-1"}, - {Name: "observation", Project: "project-b", DatasetGeneration: "generation-1"}, + {Name: "observation", TranslationVersion: "legacy", Project: "project-a", DatasetGeneration: "generation-1"}, + {Name: "observation", TranslationVersion: "legacy", Project: "project-b", DatasetGeneration: "generation-1"}, } for index, identity := range identities { execution := publication.BundleExecution{ @@ -272,7 +272,7 @@ func TestPublishedOutputResolutionIsProjectAndGenerationScoped(t *testing.T) { catalog.executions[execution.ID] = execution catalog.pointers[identity.PointerName()] = publication.BundlePointer{Name: identity.PointerName(), ExecutionID: execution.ID} } - reader := &dfpublished.Reader{Catalog: catalog, LegacyTranslationVersion: "legacy"} + reader := &dfpublished.Reader{Catalog: catalog} selector := dfpublished.DataframeSelector{Recipe: "observation", TranslationVersion: "legacy", Output: "Observation"} firstSources, err := reader.CurrentFederatedSources(context.Background(), []string{"project-a"}, selector) if err != nil { diff --git a/internal/dataframe/published/export.go b/internal/dataframe/published/export.go index 72075d2b..970ac2ea 100644 --- a/internal/dataframe/published/export.go +++ b/internal/dataframe/published/export.go @@ -13,7 +13,6 @@ const ( type ExportRequest struct { Selector *DataframeSelector `json:"selector,omitempty"` - DataType string `json:"dataType,omitempty"` Columns []string Filters []Filter Sort *Sort diff --git a/internal/dataframe/published/federation.go b/internal/dataframe/published/federation.go index b01e159b..1582e1a5 100644 --- a/internal/dataframe/published/federation.go +++ b/internal/dataframe/published/federation.go @@ -20,17 +20,16 @@ import ( // authorized project publications. project_id is a public, stable row column; // legacy outputs that predate it are filled from the source publication project. type FederatedDataset struct { - Selector DataframeSelector - ActiveContractVersion string - Name string - Revision string - Sources []Materialization - Columns []Column - RowCount int64 - RowCountComplete bool - Availability FederationAvailability - ExpectedProjects int - ProjectStatuses []ProjectStatus + Selector DataframeSelector + Name string + Revision string + Sources []Materialization + Columns []Column + RowCount int64 + RowCountComplete bool + Availability FederationAvailability + ExpectedProjects int + ProjectStatuses []ProjectStatus } type FederationAvailability string @@ -372,6 +371,12 @@ func (r *Reader) CurrentFederatedSources(ctx context.Context, projects []string, } executionSelector, selectorErr := r.selectorForExecution(ctx, execution, selector.Output) if selectorErr != nil { + // A stale active-release pointer must degrade that project, not make + // every other authorized project's valid publication unreadable. + // Status resolution still reports the missing project to callers. + if errors.Is(selectorErr, bundlepublication.ErrBundleNotFound) { + continue + } return nil, selectorErr } if executionSelector != selector { @@ -409,27 +414,22 @@ func (r *Reader) CurrentFederatedSources(ctx context.Context, projects []string, return result, nil } -func executionTranslationVersion(execution bundlepublication.BundleExecution, legacyDefault string) string { - if version := strings.TrimSpace(execution.TranslationVersion); version != "" { - return version - } - return strings.TrimSpace(legacyDefault) -} - func (r *Reader) selectorForExecution(ctx context.Context, execution bundlepublication.BundleExecution, output string) (DataframeSelector, error) { if resolver, ok := r.Catalog.(ExecutionSelectorResolver); ok { selector, err := resolver.DataframeSelectorForExecution(ctx, execution.ID, output) - if err == nil && selector.Valid() { - return selector, nil - } - if strings.TrimSpace(execution.TranslationVersion) != "" { - if err == nil { - return DataframeSelector{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidSelector, "") - } + if err != nil { return DataframeSelector{}, err } + if selector.Valid() { + return selector, nil + } + return DataframeSelector{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidSelector, "") + } + selector := DataframeSelector{Recipe: execution.Name, TranslationVersion: strings.TrimSpace(execution.TranslationVersion), Output: output} + if !selector.Valid() { + return DataframeSelector{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidSelector, "") } - return DataframeSelector{Recipe: execution.Name, TranslationVersion: executionTranslationVersion(execution, r.LegacyTranslationVersion), Output: output}, nil + return selector, nil } func (r *Reader) CurrentFederatedResourceTypes(ctx context.Context, projects []string) ([]string, error) { diff --git a/internal/dataframe/published/federation_test.go b/internal/dataframe/published/federation_test.go index 0a6e81e7..2c9b71cd 100644 --- a/internal/dataframe/published/federation_test.go +++ b/internal/dataframe/published/federation_test.go @@ -66,14 +66,14 @@ func TestReconcileExcludesMalformedSourceAndDegrades(t *testing.T) { func TestExactSelectorDoesNotMixRecipesSharingOutput(t *testing.T) { now := time.Now().UTC() executions := []bundlepublication.BundleExecution{ - {ID: "recipe-a", BundleIdentity: bundlepublication.BundleIdentity{Name: "recipe-a", Project: "p"}, State: bundlepublication.BundleReady, UpdatedAt: now, Outputs: []bundlepublication.BundleOutputRecord{{Name: "DocumentReference", PhysicalTable: "a"}}}, - {ID: "recipe-b", BundleIdentity: bundlepublication.BundleIdentity{Name: "recipe-b", Project: "p"}, State: bundlepublication.BundleReady, UpdatedAt: now, Outputs: []bundlepublication.BundleOutputRecord{{Name: "DocumentReference", PhysicalTable: "b"}}}, + {ID: "recipe-a", BundleIdentity: bundlepublication.BundleIdentity{Name: "recipe-a", TranslationVersion: "v1", Project: "p"}, State: bundlepublication.BundleReady, UpdatedAt: now, Outputs: []bundlepublication.BundleOutputRecord{{Name: "DocumentReference", PhysicalTable: "a"}}}, + {ID: "recipe-b", BundleIdentity: bundlepublication.BundleIdentity{Name: "recipe-b", TranslationVersion: "v1", Project: "p"}, State: bundlepublication.BundleReady, UpdatedAt: now, Outputs: []bundlepublication.BundleOutputRecord{{Name: "DocumentReference", PhysicalTable: "b"}}}, } pointers := map[string]bundlepublication.BundlePointer{} for _, execution := range executions { pointers[execution.PointerName()] = bundlepublication.BundlePointer{ExecutionID: execution.ID} } - reader := Reader{Catalog: &federationCatalog{executions: executions, pointers: pointers}, LegacyTranslationVersion: "v1"} + reader := Reader{Catalog: &federationCatalog{executions: executions, pointers: pointers}} sources, err := reader.CurrentFederatedSources(context.Background(), []string{"p"}, DataframeSelector{Recipe: "recipe-a", TranslationVersion: "v1", Output: "DocumentReference"}) if err != nil { t.Fatal(err) @@ -83,24 +83,6 @@ func TestExactSelectorDoesNotMixRecipesSharingOutput(t *testing.T) { } } -func TestLegacyReadyExecutionUsesLegacyPointerAndDefaultVersion(t *testing.T) { - now := time.Now().UTC() - execution := bundlepublication.BundleExecution{ID: "legacy", BundleIdentity: bundlepublication.BundleIdentity{Name: "documents", Project: "p", DatasetGeneration: "g"}, State: bundlepublication.BundleReady, UpdatedAt: now, Outputs: []bundlepublication.BundleOutputRecord{{Name: "DocumentReference", PhysicalTable: "legacy_table", State: bundlepublication.BundleReady}}} - catalog := &versionedFederationCatalog{federationCatalog: &federationCatalog{executions: []bundlepublication.BundleExecution{execution}, pointers: map[string]bundlepublication.BundlePointer{execution.PointerName(): {ExecutionID: execution.ID}}}, selectors: map[string]DataframeSelector{}} - reader := Reader{Catalog: catalog, LegacyTranslationVersion: "v1"} - sources, err := reader.CurrentFederatedSources(context.Background(), []string{"p"}, DataframeSelector{Recipe: "documents", TranslationVersion: "v1", Output: "DocumentReference"}) - if err != nil { - t.Fatal(err) - } - if len(sources) != 1 || sources[0].PhysicalTable != "legacy_table" { - t.Fatalf("legacy sources = %#v", sources) - } - projects, err := reader.PublishedProjects(context.Background()) - if err != nil || len(projects) != 1 || projects[0] != "p" { - t.Fatalf("legacy projects = %#v, %v", projects, err) - } -} - func TestRecipeVersionsRemainIndependentlyQueryable(t *testing.T) { now := time.Now().UTC() executions := []bundlepublication.BundleExecution{ @@ -192,6 +174,21 @@ type missingOutputSelectorCatalog struct { selectorCalls int } +type staleExecutionSelectorCatalog struct { + *federationCatalog + selectors map[string]DataframeSelector + staleID string +} + +func (c *staleExecutionSelectorCatalog) DataframeSelectorForExecution(_ context.Context, executionID, output string) (DataframeSelector, error) { + if executionID == c.staleID { + return DataframeSelector{}, bundlepublication.ErrBundleNotFound + } + selector := c.selectors[executionID] + selector.Output = output + return selector, nil +} + func (c *missingOutputSelectorCatalog) DataframeSelectorForExecution(context.Context, string, string) (DataframeSelector, error) { c.selectorCalls++ return DataframeSelector{}, bundlepublication.ErrBundleNotFound @@ -239,6 +236,23 @@ func TestActiveReleaseExecutionOverridesMutablePublicationPointer(t *testing.T) } } +func TestStaleReleaseExecutionDoesNotPoisonValidFederatedSource(t *testing.T) { + now := time.Now().UTC() + selector := DataframeSelector{Recipe: "explorer_project_default", TranslationVersion: "repository-commit", Output: "Patient"} + valid := bundlepublication.BundleExecution{ID: "valid", BundleIdentity: bundlepublication.BundleIdentity{Name: selector.Recipe, TranslationVersion: selector.TranslationVersion, Project: "valid-project", DatasetGeneration: "g1"}, State: bundlepublication.BundlePublished, UpdatedAt: now, Outputs: []bundlepublication.BundleOutputRecord{{Name: selector.Output, PhysicalTable: "patient_valid", State: bundlepublication.BundlePublished}}} + stale := bundlepublication.BundleExecution{ID: "stale", BundleIdentity: bundlepublication.BundleIdentity{Name: selector.Recipe, TranslationVersion: selector.TranslationVersion, Project: "stale-project", DatasetGeneration: "g2"}, State: bundlepublication.BundlePublished, UpdatedAt: now, Outputs: []bundlepublication.BundleOutputRecord{{Name: selector.Output, PhysicalTable: "patient_stale", State: bundlepublication.BundlePublished}}} + catalog := &staleExecutionSelectorCatalog{federationCatalog: &federationCatalog{executions: []bundlepublication.BundleExecution{valid, stale}}, selectors: map[string]DataframeSelector{valid.ID: selector}, staleID: stale.ID} + reader := Reader{Catalog: catalog, ReleaseExecutionResolver: releaseExecutionFixture{"valid-project": valid.ID, "stale-project": stale.ID}} + + sources, err := reader.CurrentFederatedSources(context.Background(), []string{"valid-project", "stale-project"}, selector) + if err != nil { + t.Fatal(err) + } + if len(sources) != 1 || sources[0].Project != "valid-project" || sources[0].PhysicalTable != "patient_valid" { + t.Fatalf("sources = %#v", sources) + } +} + func (c *federationCatalog) ListExecutions(_ context.Context, state bundlepublication.BundleState, before time.Time) ([]bundlepublication.BundleExecution, error) { result := make([]bundlepublication.BundleExecution, 0, len(c.executions)) for _, execution := range c.executions { @@ -258,55 +272,3 @@ type noActiveFederationResolver struct{} func (noActiveFederationResolver) ResolveActiveManifest(context.Context, string) (publication.Manifest, error) { return publication.Manifest{}, publication.ErrNoActiveGeneration } - -func TestFederationFallsBackToUnversionedPublicationsWithoutActiveManifest(t *testing.T) { - now := time.Now().UTC() - executions := []bundlepublication.BundleExecution{ - { - ID: "unversioned", BundleIdentity: bundlepublication.BundleIdentity{ - Name: "research-subject", Project: "project-a", - }, State: bundlepublication.BundleReady, UpdatedAt: now, - Outputs: []bundlepublication.BundleOutputRecord{ - {Name: "ResearchSubject", PhysicalTable: "loom_research_subject"}, - {Name: "patients", PhysicalTable: "loom_patients"}, - }, - }, - { - ID: "versioned", BundleIdentity: bundlepublication.BundleIdentity{ - Name: "research-subject", Project: "project-a", DatasetGeneration: "generation-a", - }, State: bundlepublication.BundleReady, UpdatedAt: now, - Outputs: []bundlepublication.BundleOutputRecord{{Name: "ResearchSubject", PhysicalTable: "loom_research_subject_v1"}}, - }, - } - pointers := map[string]bundlepublication.BundlePointer{} - for _, execution := range executions { - pointers[execution.PointerName()] = bundlepublication.BundlePointer{ - Name: execution.PointerName(), ExecutionID: execution.ID, - } - } - reader := &Reader{ - Catalog: &federationCatalog{executions: executions, pointers: pointers}, - ActiveManifestResolver: noActiveFederationResolver{}, - LegacyTranslationVersion: "legacy", - } - - sources, err := reader.CurrentFederatedSources(context.Background(), []string{"project-a"}, DataframeSelector{Recipe: "research-subject", TranslationVersion: "legacy", Output: "ResearchSubject"}) - if err != nil { - t.Fatalf("CurrentFederatedSources() error = %v", err) - } - if len(sources) != 1 || sources[0].ID != "unversioned:ResearchSubject" { - t.Fatalf("sources = %#v, want only unversioned publication", sources) - } - - resourceTypes, err := reader.CurrentFederatedResourceTypes(context.Background(), []string{"project-a"}) - if err != nil { - t.Fatalf("CurrentFederatedResourceTypes() error = %v", err) - } - if len(resourceTypes) != 1 || resourceTypes[0] != "ResearchSubject" { - t.Fatalf("resource types = %#v, want unversioned resource types", resourceTypes) - } - patients, err := reader.CurrentFederatedSources(context.Background(), []string{"project-a"}, DataframeSelector{Recipe: "research-subject", TranslationVersion: "legacy", Output: "patients"}) - if err != nil || len(patients) != 1 || patients[0].ID != "unversioned:patients" { - t.Fatalf("exact non-FHIR output sources = %#v, %v", patients, err) - } -} diff --git a/internal/dataframe/published/read.go b/internal/dataframe/published/read.go index 75eac68b..7d151b41 100644 --- a/internal/dataframe/published/read.go +++ b/internal/dataframe/published/read.go @@ -1,7 +1,6 @@ package published import ( - "context" "encoding/base64" "encoding/json" "fmt" @@ -16,14 +15,11 @@ import ( ) type Reader struct { - ClickHouse *clickhouse.Client - Catalog bundlepublication.BundleCatalog - Logger *slog.Logger - MaxPage int - ActiveManifestResolver publication.ActiveResolver - // LegacyTranslationVersion maps pre-versioned execution rows only during - // the compatibility window. New rows always carry their exact version. - LegacyTranslationVersion string + ClickHouse *clickhouse.Client + Catalog bundlepublication.BundleCatalog + Logger *slog.Logger + MaxPage int + ActiveManifestResolver publication.ActiveResolver ProjectStatusResolver ProjectStatusResolver ReleaseExecutionResolver ReleaseExecutionResolver } @@ -39,14 +35,6 @@ type Sort struct { Desc bool } -type PageRequest struct { - Columns []string - Filters []Filter - Sort *Sort - First int - After string -} - type Page struct { Materialization Materialization Columns []string @@ -62,261 +50,6 @@ type AggregateResult struct { Rows []map[string]any } -type AggregateRequest struct { - GroupBy []string - Filters []Filter - Operation string - Column string -} - -// AggregatePublishedID preserves the legacy single-materialization query -// path. Federated callers use AggregateFederatedDataset instead. -func (r *Reader) AggregatePublishedID(ctx context.Context, id string, req AggregateRequest) (AggregateResult, error) { - if r == nil || r.ClickHouse == nil || r.Catalog == nil { - return AggregateResult{}, dataframeerrors.NewError(dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) - } - m, err := r.publishedByID(ctx, id) - if err != nil { - return AggregateResult{}, err - } - return r.aggregateResolved(ctx, req, m) -} - -func (r *Reader) aggregateResolved(ctx context.Context, req AggregateRequest, m Materialization) (AggregateResult, error) { - if m.State != StateReady { - return AggregateResult{}, dataframeerrors.NewError(dataframeerrors.CodeDatasetNotFound, "") - } - allowed := make(map[string]struct{}, len(m.Columns)) - for _, column := range m.Columns { - allowed[column.Name] = struct{}{} - } - for _, column := range req.GroupBy { - if _, ok := allowed[column]; !ok { - return AggregateResult{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") - } - } - where, args, err := buildWhere(req.Filters, allowed) - if err != nil { - return AggregateResult{}, err - } - operation := strings.ToUpper(req.Operation) - if operation != "COUNT" && operation != "COUNT_DISTINCT" && operation != "SUM" && operation != "AVG" && operation != "MIN" && operation != "MAX" { - return AggregateResult{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") - } - if operation != "COUNT" { - if _, ok := allowed[req.Column]; !ok { - return AggregateResult{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") - } - } - selects := make([]string, 0, len(req.GroupBy)+1) - columns := append([]string(nil), req.GroupBy...) - for _, column := range req.GroupBy { - selects = append(selects, fmt.Sprintf("`%s`", column)) - } - metric := "count()" - metricName := "count" - switch operation { - case "COUNT_DISTINCT": - metric, metricName = fmt.Sprintf("uniqExact(`%s`)", req.Column), "count_distinct" - case "SUM": - metric, metricName = fmt.Sprintf("sum(`%s`)", req.Column), "sum" - case "AVG": - metric, metricName = fmt.Sprintf("avg(`%s`)", req.Column), "avg" - case "MIN": - metric, metricName = fmt.Sprintf("min(`%s`)", req.Column), "min" - case "MAX": - metric, metricName = fmt.Sprintf("max(`%s`)", req.Column), "max" - } - selects = append(selects, metric+" AS `"+metricName+"`") - columns = append(columns, metricName) - query := fmt.Sprintf("SELECT %s FROM `%s`", strings.Join(selects, ", "), m.PhysicalTable) - if len(where) > 0 { - query += " WHERE " + strings.Join(where, " AND ") - } - if len(req.GroupBy) > 0 { - query += " GROUP BY " + strings.Join(selects[:len(req.GroupBy)], ", ") + " ORDER BY " + strings.Join(selects[:len(req.GroupBy)], ", ") - } - rows, err := r.ClickHouse.QueryRowsArgs(ctx, query, columns, args...) - if err != nil { - return AggregateResult{}, backendCallError(err) - } - return AggregateResult{Materialization: m, Columns: columns, Rows: rows}, nil -} - -// PagePublishedID preserves the legacy single-materialization row query path. -func (r *Reader) PagePublishedID(ctx context.Context, id string, req PageRequest) (Page, error) { - if r == nil || r.ClickHouse == nil || r.Catalog == nil { - return Page{}, dataframeerrors.NewError(dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) - } - m, err := r.publishedByID(ctx, id) - if err != nil { - return Page{}, err - } - return r.pageResolved(ctx, req, m) -} - -func (r *Reader) DatasetByPublishedID(ctx context.Context, id string) (Materialization, error) { - if r == nil || r.Catalog == nil { - return Materialization{}, fmt.Errorf("bundle catalog dependency is required") - } - return r.publishedByID(ctx, id) -} - -func (r *Reader) publishedByID(ctx context.Context, id string) (Materialization, error) { - parts := strings.SplitN(id, ":", 2) - if len(parts) != 2 || parts[0] == "" || parts[1] == "" { - return Materialization{}, fmt.Errorf("invalid published dataset id %q", id) - } - execution, err := r.Catalog.GetExecution(ctx, parts[0]) - if err != nil { - return Materialization{}, err - } - if !execution.State.Successful() { - return Materialization{}, dataframeerrors.NewError(dataframeerrors.CodeDatasetNotFound, "") - } - pointer, err := r.Catalog.GetPointer(ctx, execution.PointerName()) - if err != nil { - return Materialization{}, fmt.Errorf("resolve dataframe pointer: %w", err) - } - if pointer.ExecutionID != execution.ID { - return Materialization{}, dataframeerrors.NewError(dataframeerrors.CodeDatasetNotFound, "") - } - for _, output := range execution.Outputs { - if output.Name == parts[1] { - return publishedMaterialization(execution, output, output.Name), nil - } - } - return Materialization{}, dataframeerrors.NewError(dataframeerrors.CodeDatasetNotFound, "") -} - -func (r *Reader) pageResolved(ctx context.Context, req PageRequest, m Materialization) (Page, error) { - if m.State != StateReady { - return Page{}, dataframeerrors.NewError(dataframeerrors.CodeDatasetNotFound, "") - } - allowed := make(map[string]struct{}, len(m.Columns)) - for _, column := range m.Columns { - allowed[column.Name] = struct{}{} - } - columns := append([]string(nil), req.Columns...) - if len(columns) == 0 { - for _, column := range m.Columns { - if column.Name != "__loom_row_id" { - columns = append(columns, column.Name) - } - } - } - for _, column := range columns { - if column == "__loom_row_id" { - return Page{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") - } - if _, ok := allowed[column]; !ok { - return Page{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") - } - } - if req.Sort != nil { - if _, ok := allowed[req.Sort.Column]; !ok || req.Sort.Column == "__loom_row_id" { - return Page{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") - } - } - first := req.First - if first <= 0 { - first = 100 - } - if r.MaxPage > 0 && first > r.MaxPage { - first = r.MaxPage - } - cursor, err := decodeCursor(req.After) - if err != nil { - return Page{}, err - } - where, whereArgs, err := buildWhere(req.Filters, allowed) - if err != nil { - return Page{}, err - } - countQuery := fmt.Sprintf("SELECT count() AS `__loom_total` FROM `%s`", m.PhysicalTable) - if len(where) > 0 { - countQuery += " WHERE " + strings.Join(where, " AND ") - } - countRows, err := r.ClickHouse.QueryRowsArgs(ctx, countQuery, []string{"__loom_total"}, whereArgs...) - if err != nil { - return Page{}, backendCallError(err) - } - if len(countRows) == 0 { - return Page{}, fmt.Errorf("ClickHouse count query returned no rows") - } - totalCount, err := numericCount(countRows[0]["__loom_total"]) - if err != nil { - return Page{}, err - } - queryColumns := append([]string(nil), columns...) - if req.Sort != nil && !contains(queryColumns, req.Sort.Column) { - queryColumns = append(queryColumns, req.Sort.Column) - } - if !contains(queryColumns, "__loom_row_id") { - queryColumns = append(queryColumns, "__loom_row_id") - } - selects := make([]string, len(queryColumns)) - for i, column := range queryColumns { - selects[i] = fmt.Sprintf("`%s`", column) - } - query := fmt.Sprintf("SELECT %s FROM `%s`", strings.Join(selects, ", "), m.PhysicalTable) - if len(where) > 0 { - query += " WHERE " + strings.Join(where, " AND ") - } - if cursor != nil { - cursorWhere, cursorArgs, err := cursorPredicate(cursor, req.Sort) - if err != nil { - return Page{}, err - } - whereArgs = append(whereArgs, cursorArgs...) - if strings.Contains(query, " WHERE ") { - query += " AND " + cursorWhere - } else { - query += " WHERE " + cursorWhere - } - } - if req.Sort != nil { - direction := "ASC" - if req.Sort.Desc { - direction = "DESC" - } - query += fmt.Sprintf(" ORDER BY `%s` %s, toString(`__loom_row_id`) ASC", req.Sort.Column, direction) - } else { - // Published recipe identities are deterministic strings, while legacy - // tables may use UInt64. Ordering through the shared string - // representation keeps keyset pagination valid for both schemas. - query += " ORDER BY toString(`__loom_row_id`) ASC" - } - query += fmt.Sprintf(" LIMIT %d", first+1) - rows, err := r.ClickHouse.QueryRowsArgs(ctx, query, queryColumns, whereArgs...) - if err != nil { - return Page{}, backendCallError(err) - } - hasNext := len(rows) > first - if hasNext { - rows = rows[:first] - } - next := "" - if hasNext && len(rows) > 0 { - last := rows[len(rows)-1] - var sortValue any - if req.Sort != nil { - sortValue = last[req.Sort.Column] - if sortValue == nil { - return Page{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidCursor, "") - } - } - next = encodeCursor(fmt.Sprint(last["__loom_row_id"]), sortValue) - } - for _, row := range rows { - delete(row, "__loom_row_id") - if req.Sort != nil && !contains(columns, req.Sort.Column) { - delete(row, req.Sort.Column) - } - } - return Page{Materialization: m, Columns: columns, Rows: rows, TotalCount: totalCount, HasNext: hasNext, NextCursor: next}, nil -} - func numericCount(value any) (int64, error) { switch typed := value.(type) { case int: diff --git a/internal/dataframe/published/types.go b/internal/dataframe/published/types.go index f28cb0c7..c0c3e7a7 100644 --- a/internal/dataframe/published/types.go +++ b/internal/dataframe/published/types.go @@ -26,30 +26,29 @@ type Column struct { type DataframeSelector = dataset.DataframeSelector type Materialization struct { - ID string `json:"id"` - Name string `json:"name"` - Revision string `json:"revision,omitempty"` - Project string `json:"project"` - DatasetGeneration string `json:"datasetGeneration"` - State State `json:"state"` - ScopeUnrestricted bool `json:"scopeUnrestricted"` - AuthResourcePaths []string `json:"authResourcePaths,omitempty"` - Columns []Column `json:"columns"` - PhysicalTable string `json:"physicalTable"` - RowCount int64 `json:"rowCount"` - RowCountKnown bool `json:"-"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - ReadyAt *time.Time `json:"readyAt,omitempty"` - Error string `json:"error,omitempty"` - FailureCode string `json:"failureCode,omitempty"` - FailureRetryable bool `json:"failureRetryable,omitempty"` - Selector DataframeSelector `json:"selector"` - Availability FederationAvailability `json:"availability,omitempty"` - IncludedProjects int `json:"includedProjects,omitempty"` - ExpectedProjects int `json:"expectedProjects,omitempty"` - ProjectStatuses []ProjectStatus `json:"projectStatuses,omitempty"` - ActiveContractVersion string `json:"activeContractVersion,omitempty"` + ID string `json:"id"` + Name string `json:"name"` + Revision string `json:"revision,omitempty"` + Project string `json:"project"` + DatasetGeneration string `json:"datasetGeneration"` + State State `json:"state"` + ScopeUnrestricted bool `json:"scopeUnrestricted"` + AuthResourcePaths []string `json:"authResourcePaths,omitempty"` + Columns []Column `json:"columns"` + PhysicalTable string `json:"physicalTable"` + RowCount int64 `json:"rowCount"` + RowCountKnown bool `json:"-"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + ReadyAt *time.Time `json:"readyAt,omitempty"` + Error string `json:"error,omitempty"` + FailureCode string `json:"failureCode,omitempty"` + FailureRetryable bool `json:"failureRetryable,omitempty"` + Selector DataframeSelector `json:"selector"` + Availability FederationAvailability `json:"availability,omitempty"` + IncludedProjects int `json:"includedProjects,omitempty"` + ExpectedProjects int `json:"expectedProjects,omitempty"` + ProjectStatuses []ProjectStatus `json:"projectStatuses,omitempty"` } func publishedMaterialization(execution publication.BundleExecution, output publication.BundleOutputRecord, resourceType string) Materialization { diff --git a/internal/dataframe/recipe/engine/engine.go b/internal/dataframe/recipe/engine/engine.go index 42749af7..fcd73bb3 100644 --- a/internal/dataframe/recipe/engine/engine.go +++ b/internal/dataframe/recipe/engine/engine.go @@ -152,6 +152,42 @@ func (e *Engine) ResolveVersion(ctx context.Context, name, translationVersion st return e.resolveEntry(ctx, entry, bindings) } +// ResolveBundle runs an unregistered immutable bundle through the identical +// schema, semantic, optimization, and lowering pipeline as a registry entry. +// Explorer uses this to avoid creating recipe drafts/revisions for authored UI +// intent. +func (e *Engine) ResolveBundle(ctx context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (Resolved, error) { + if strings.TrimSpace(bindings.Project) == "" { + return Resolved{}, fmt.Errorf("recipe project is required") + } + digest, err := bundle.Digest() + if err != nil { + return Resolved{}, fmt.Errorf("digest bundle: %w", err) + } + return e.resolveEntry(ctx, exec.Entry{Bundle: bundle, Digest: digest}, bindings) +} + +func (e *Engine) PreviewBundle(ctx context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (map[string][]map[string]any, error) { + resolved, err := e.ResolveBundle(ctx, bundle, bindings) + if err != nil { + return nil, &ResolutionError{Err: err} + } + return e.Preview(ctx, resolved, bindings.PreviewLimit) +} + +func (e *Engine) MaterializeBundle(ctx context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings, publish func(context.Context, Resolved) error) (Resolved, error) { + resolved, err := e.ResolveBundle(ctx, bundle, bindings) + if err != nil { + return Resolved{}, &ResolutionError{Err: err} + } + if publish != nil { + if err := publish(ctx, resolved); err != nil { + return Resolved{}, err + } + } + return resolved, nil +} + func (e *Engine) resolveEntry(ctx context.Context, entry exec.Entry, bindings recipe.RuntimeBindings) (Resolved, error) { if strings.TrimSpace(bindings.Project) == "" { return Resolved{}, fmt.Errorf("recipe project is required") diff --git a/internal/dataset/arango/document_codec.go b/internal/dataset/arango/document_codec.go index 15b7f20b..cf566e49 100644 --- a/internal/dataset/arango/document_codec.go +++ b/internal/dataset/arango/document_codec.go @@ -153,7 +153,13 @@ func manifestDocumentKey(ref publication.Ref) string { return documentKey("manifest", ref.Project, ref.Generation) } +// ManifestDocumentKey and ActiveDocumentKey deliberately expose only the +// minimum composite-transaction identities needed by Loom-owned aggregates. +// Callers must not reimplement the private document-key algorithm. +func ManifestDocumentKey(ref publication.Ref) string { return manifestDocumentKey(ref) } + func activeDocumentKey(project string) string { return documentKey("active", project) } +func ActiveDocumentKey(project string) string { return activeDocumentKey(project) } func documentKey(kind string, values ...string) string { hash := sha256.New() diff --git a/internal/explorer/arango/collections.go b/internal/explorer/arango/collections.go new file mode 100644 index 00000000..e30a9b85 --- /dev/null +++ b/internal/explorer/arango/collections.go @@ -0,0 +1,21 @@ +// Package arango persists Loom Explorer aggregate records. +package arango + +import store "github.com/calypr/loom/internal/store/arango" + +const ( + ExplorersCollection = "loom_explorers" + RevisionsCollection = "loom_explorer_revisions" + RepositoryConfigsCollection = "loom_repository_explorer_configs" +) + +// CollectionSpecs is deliberately non-truncating: both draft history pointers +// and immutable revision/share URLs must survive normal server bootstrap. +func CollectionSpecs() []store.CollectionSpec { + return []store.CollectionSpec{ + {Name: ExplorersCollection, Indexes: [][]string{{"project", "explorerId"}}}, + {Name: RevisionsCollection, Indexes: [][]string{{"project", "explorerId", "createdAt"}, {"project", "status"}, {"project", "explorerId", "sourceCommit", "definitionDigest", "sourceGeneration"}}}, + {Name: RepositoryConfigsCollection, Indexes: [][]string{{"project"}}}, + } +} +func BootstrapSpec() store.BootstrapSpec { return store.BootstrapSpec{Collections: CollectionSpecs()} } diff --git a/internal/explorer/arango/collections_test.go b/internal/explorer/arango/collections_test.go new file mode 100644 index 00000000..03d0a6fd --- /dev/null +++ b/internal/explorer/arango/collections_test.go @@ -0,0 +1,18 @@ +package arango + +import "testing" + +func TestCollectionSpecsArePersistentAndIndexed(t *testing.T) { + s := CollectionSpecs() + if len(s) != 3 { + t.Fatalf("specs=%#v", s) + } + for _, spec := range s { + if spec.Truncate { + t.Fatalf("%s truncates persisted Explorer state", spec.Name) + } + if len(spec.Indexes) == 0 { + t.Fatalf("%s has no indexes", spec.Name) + } + } +} diff --git a/internal/explorer/arango/store.go b/internal/explorer/arango/store.go new file mode 100644 index 00000000..4f0d5c87 --- /dev/null +++ b/internal/explorer/arango/store.go @@ -0,0 +1,470 @@ +package arango + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "time" + + publicationarango "github.com/calypr/loom/internal/dataframe/publication/arango" + dataset "github.com/calypr/loom/internal/dataset" + datasetarango "github.com/calypr/loom/internal/dataset/arango" + "github.com/calypr/loom/internal/explorer" + store "github.com/calypr/loom/internal/store/arango" +) + +type client interface { + QueryRows(context.Context, string, int, map[string]any, store.RowVisitor) error + WithTransaction(context.Context, store.TransactionCollections, store.TransactionFunc) error +} +type Store struct{ client client } + +func New(client client) (*Store, error) { + if client == nil { + return nil, fmt.Errorf("Explorer Arango client is required") + } + return &Store{client: client}, nil +} +func key(parts ...string) string { + h := sha256.New() + for _, p := range parts { + _, _ = h.Write([]byte{0}) + _, _ = h.Write([]byte(p)) + } + return hex.EncodeToString(h.Sum(nil)) +} +func explorerKey(project, id string) string { return "explorer_" + key(project, id) } +func repositoryConfigKey(project string) string { + return "repository_config_" + key(project, "default") +} +func configKey(project, id string) string { return "explorer_config_" + key(project, id) } +func (s *Store) ListConfigs(ctx context.Context, project string) ([]explorer.RepositoryConfig, error) { + out := []explorer.RepositoryConfig{} + err := s.client.QueryRows(ctx, `FOR d IN @@c FILTER d.project == @project SORT d.explorerId RETURN d`, 1000, map[string]any{"@c": RepositoryConfigsCollection, "project": project}, func(row map[string]any) error { + v, err := decode[explorer.RepositoryConfig](row) + if err == nil { + out = append(out, v) + } + return err + }) + for i := range out { + if out[i].ExplorerID == "" { + out[i].ExplorerID, out[i].Management = "default", explorer.ManagementRepository + } + } + return out, err +} +func (s *Store) GetConfig(ctx context.Context, project, id string) (*explorer.RepositoryConfig, error) { + var out *explorer.RepositoryConfig + keys := []string{configKey(project, id)} + if id == "default" { + keys = append(keys, repositoryConfigKey(project)) + } + err := s.client.QueryRows(ctx, `FOR d IN @@c FILTER d._key IN @keys SORT d.updatedAt DESC RETURN d`, 1, map[string]any{"@c": RepositoryConfigsCollection, "keys": keys}, func(row map[string]any) error { v, err := decode[explorer.RepositoryConfig](row); out = &v; return err }) + if err != nil { + return nil, err + } + if out == nil { + return nil, explorer.ErrNotFound + } + if out.ExplorerID == "" { + out.ExplorerID, out.Management = "default", explorer.ManagementRepository + } + return out, nil +} +func (s *Store) SaveConfig(ctx context.Context, value explorer.RepositoryConfig) (*explorer.RepositoryConfig, error) { + value.UpdatedAt = time.Now().UTC() + doc, err := document(value, configKey(value.Project, value.ExplorerID)) + if err != nil { + return nil, err + } + var out *explorer.RepositoryConfig + err = s.client.QueryRows(ctx, `UPSERT { _key: @key } INSERT @doc UPDATE @doc IN @@c RETURN NEW`, 1, map[string]any{"@c": RepositoryConfigsCollection, "key": configKey(value.Project, value.ExplorerID), "doc": doc}, func(row map[string]any) error { v, err := decode[explorer.RepositoryConfig](row); out = &v; return err }) + if err != nil { + return nil, err + } + return out, nil +} +func (s *Store) GetRepositoryConfig(ctx context.Context, project string) (*explorer.RepositoryConfig, error) { + return s.GetConfig(ctx, project, "default") +} +func (s *Store) SaveRepositoryConfig(ctx context.Context, value explorer.RepositoryConfig) (*explorer.RepositoryConfig, error) { + value.ExplorerID, value.Management = "default", explorer.ManagementRepository + return s.SaveConfig(ctx, value) +} +func (s *Store) List(ctx context.Context, project string) ([]explorer.Explorer, error) { + out := []explorer.Explorer{} + err := s.client.QueryRows(ctx, `FOR d IN @@c FILTER d.project == @project SORT d.explorerId RETURN d`, 1000, map[string]any{"@c": ExplorersCollection, "project": project}, func(row map[string]any) error { + v, err := decode[explorer.Explorer](row) + if err == nil { + out = append(out, v) + } + return err + }) + return out, err +} +func (s *Store) Get(ctx context.Context, project, id string) (*explorer.Explorer, error) { + var out *explorer.Explorer + err := s.client.QueryRows(ctx, `FOR d IN @@c FILTER d._key == @key AND d.project == @project RETURN d`, 1, map[string]any{"@c": ExplorersCollection, "key": explorerKey(project, id), "project": project}, func(row map[string]any) error { v, err := decode[explorer.Explorer](row); out = &v; return err }) + if err != nil { + return nil, err + } + if out == nil { + return nil, explorer.ErrNotFound + } + return out, nil +} +func (s *Store) CreateInteractive(ctx context.Context, e explorer.Explorer) (*explorer.Explorer, error) { + raw, err := document(e, explorerKey(e.Project, e.ExplorerID)) + if err != nil { + return nil, err + } + var out *explorer.Explorer + err = s.client.QueryRows(ctx, `INSERT @doc INTO @@c OPTIONS { overwriteMode: "ignore" } RETURN NEW`, 1, map[string]any{"@c": ExplorersCollection, "doc": raw}, func(row map[string]any) error { v, err := decode[explorer.Explorer](row); out = &v; return err }) + if err != nil { + return nil, err + } + if out == nil { + return nil, explorer.ErrDraftConflict + } + return out, nil +} +func (s *Store) CreateRepository(ctx context.Context, e explorer.Explorer) (*explorer.Explorer, error) { + return s.CreateInteractive(ctx, e) +} +func (s *Store) SaveDraft(ctx context.Context, e explorer.Explorer, expected int64, expectedDigest ...string) (*explorer.Explorer, error) { + e.DraftVersion = expected + 1 + e.UpdatedAt = time.Now().UTC() + raw, err := document(e, explorerKey(e.Project, e.ExplorerID)) + if err != nil { + return nil, err + } + var out *explorer.Explorer + digest := "" + if len(expectedDigest) > 0 { + digest = expectedDigest[0] + } + err = s.client.QueryRows(ctx, `FOR d IN @@c FILTER d._key == @key AND d.draftVersion == @expected AND (@expectedDigest == "" OR d.draftDigest == @expectedDigest) UPDATE d WITH @doc IN @@c RETURN NEW`, 1, map[string]any{"@c": ExplorersCollection, "key": explorerKey(e.Project, e.ExplorerID), "expected": expected, "expectedDigest": digest, "doc": raw}, func(row map[string]any) error { v, err := decode[explorer.Explorer](row); out = &v; return err }) + if err != nil { + return nil, err + } + if out == nil { + return nil, explorer.ErrDraftConflict + } + return out, nil +} + +func (s *Store) InsertRevision(ctx context.Context, revision explorer.Revision) (*explorer.Revision, error) { + if revision.ID == "" { + return nil, fmt.Errorf("revision ID is required") + } + doc, err := document(revision, revision.ID) + if err != nil { + return nil, err + } + var out *explorer.Revision + err = s.client.QueryRows(ctx, `UPSERT { _key: @key } INSERT @doc UPDATE {} IN @@c RETURN NEW`, 1, map[string]any{"@c": RevisionsCollection, "key": revision.ID, "doc": doc}, func(row map[string]any) error { value, err := decode[explorer.Revision](row); out = &value; return err }) + if err != nil { + return nil, err + } + if out == nil { + return nil, explorer.ErrNotFound + } + return out, nil +} + +func (s *Store) GetRevision(ctx context.Context, id string) (*explorer.Revision, error) { + var out *explorer.Revision + err := s.client.QueryRows(ctx, `FOR d IN @@c FILTER d._key == @key RETURN d`, 1, map[string]any{"@c": RevisionsCollection, "key": id}, func(row map[string]any) error { value, err := decode[explorer.Revision](row); out = &value; return err }) + if err != nil { + return nil, err + } + if out == nil { + return nil, explorer.ErrNotFound + } + return out, nil +} + +// TransitionRevision updates lifecycle fields only. The AQL never accepts a +// replacement definition/recipe document, preserving revision immutability. +func (s *Store) TransitionRevision(ctx context.Context, id string, status explorer.RevisionStatus, diagnostics []explorer.Diagnostic) (*explorer.Revision, error) { + now := time.Now().UTC() + patch := map[string]any{"status": status, "diagnostics": diagnostics} + if status == explorer.RevisionReady { + patch["readyAt"] = now + } + if status == explorer.RevisionFailed { + patch["failedAt"] = now + } + var out *explorer.Revision + err := s.client.QueryRows(ctx, `FOR d IN @@c FILTER d._key == @key UPDATE d WITH @patch IN @@c RETURN NEW`, 1, map[string]any{"@c": RevisionsCollection, "key": id, "patch": patch}, func(row map[string]any) error { value, err := decode[explorer.Revision](row); out = &value; return err }) + if err != nil { + return nil, err + } + if out == nil { + return nil, explorer.ErrNotFound + } + return out, nil +} + +const activationReadAQL = `LET owner = DOCUMENT(@@explorers, @explorerKey) +LET candidate = DOCUMENT(@@revisions, @revisionKey) +FILTER owner != null AND candidate != null AND owner.project == @project AND owner.explorerId == @explorerId AND owner.managementMode == @management AND candidate.project == @project AND candidate.explorerId == @explorerId +FILTER candidate.status == "READY" OR (candidate.status == "ACTIVE" AND owner.activeRevisionId == @revisionKey) +LET prior = owner.activeRevisionId == null ? null : DOCUMENT(@@revisions, owner.activeRevisionId) +RETURN {owner: owner, candidate: candidate, prior: prior}` + +const compositeActivationReadAQL = `LET manifest = DOCUMENT(@@lifecycle, @manifestKey) +LET active = DOCUMENT(@@lifecycle, @activeKey) +LET owner = DOCUMENT(@@explorers, @explorerKey) +LET candidate = DOCUMENT(@@revisions, @revisionKey) +LET execution = candidate == null OR LENGTH(candidate.materializations) == 0 ? null : DOCUMENT(@@executions, candidate.materializations[0].materializationId) +FILTER manifest != null AND manifest.recordType == "manifest" AND manifest.dataset.project == @project AND manifest.dataset.generation == @generation AND manifest.state IN ["STAGED", "READY"] +FILTER active != null AND active.recordType == "active_generation" AND active.project == @project +FILTER owner != null AND owner.project == @project AND owner.explorerId == "default" AND owner.managementMode == "REPOSITORY" +FILTER candidate != null AND candidate.project == @project AND candidate.explorerId == "default" AND candidate.sourceGeneration == @generation +FILTER candidate.status == "READY" OR (candidate.status == "ACTIVE" AND owner.activeRevisionId == @revisionKey) +FILTER execution != null AND execution.project == @project AND execution.datasetGeneration == @generation AND execution.state == "PUBLISHED" +LET prior = owner.activeRevisionId == null ? null : DOCUMENT(@@revisions, owner.activeRevisionId) +RETURN {manifest: manifest, active: active, owner: owner, candidate: candidate, prior: prior}` + +const activationUpdateAQL = `FOR d IN @@c +FILTER d._key == @key +UPDATE d WITH @patch IN @@c +RETURN NEW` + +type activationState struct { + owner map[string]any + candidate map[string]any + prior map[string]any +} + +func (s *Store) ActivateInteractive(ctx context.Context, project, explorerID, revisionID string) error { + return s.activateOwnerRevision(ctx, project, explorerID, revisionID, explorer.ManagementInteractive, []string{ExplorersCollection, RevisionsCollection}) +} + +func (s *Store) ActivateRepository(ctx context.Context, project, revisionID string) error { + return s.activateOwnerRevision(ctx, project, "default", revisionID, explorer.ManagementRepository, []string{ExplorersCollection, RevisionsCollection}) +} + +func (s *Store) activateOwnerRevision(ctx context.Context, project, explorerID, revisionID string, management explorer.ManagementMode, writeCollections []string) error { + return s.client.WithTransaction(ctx, store.TransactionCollections{Write: writeCollections}, func(txCtx context.Context, tx store.Transaction) error { + row, found, err := readActivationRow(txCtx, tx, activationReadAQL, map[string]any{ + "@explorers": ExplorersCollection, "@revisions": RevisionsCollection, + "explorerKey": explorerKey(project, explorerID), "revisionKey": revisionID, + "project": project, "explorerId": explorerID, "management": management, + }) + if err != nil { + return err + } + if !found { + return explorer.ErrDraftConflict + } + state, err := activationStateFromRow(row) + if err != nil { + return err + } + return activateRevisionAndOwner(txCtx, tx, state, time.Now().UTC()) + }) +} + +// ActivateRepositoryGeneration is the repository-only composite visibility +// switch. It validates all pointers first, then performs each single-collection +// modification inside one Arango transaction so no partial activation is +// visible if any update fails. +func (s *Store) ActivateRepositoryGeneration(ctx context.Context, project, generation, revisionID string) error { + return s.client.WithTransaction(ctx, store.TransactionCollections{ + Read: []string{publicationarango.BundleExecutionsCollection}, + Write: []string{datasetarango.LifecycleCollection, ExplorersCollection, RevisionsCollection}, + }, func(txCtx context.Context, tx store.Transaction) error { + row, found, err := readActivationRow(txCtx, tx, compositeActivationReadAQL, map[string]any{ + "@lifecycle": datasetarango.LifecycleCollection, "@explorers": ExplorersCollection, + "@revisions": RevisionsCollection, "@executions": publicationarango.BundleExecutionsCollection, + "manifestKey": datasetarango.ManifestDocumentKey(dataset.Ref{Project: project, Generation: generation}), + "activeKey": datasetarango.ActiveDocumentKey(project), "explorerKey": explorerKey(project, "default"), + "revisionKey": revisionID, "project": project, "generation": generation, + }) + if err != nil { + return err + } + if !found { + return explorer.ErrDraftConflict + } + state, err := activationStateFromRow(row) + if err != nil { + return err + } + manifest, err := requiredActivationDocument(row, "manifest") + if err != nil { + return err + } + active, err := requiredActivationDocument(row, "active") + if err != nil { + return err + } + activeKey, err := activationDocumentKey(active) + if err != nil { + return err + } + manifestKey, err := activationDocumentKey(manifest) + if err != nil { + return err + } + dataset, ok := manifest["dataset"] + if !ok { + return fmt.Errorf("activation manifest has no dataset") + } + if err := updateActivationDocument(txCtx, tx, datasetarango.LifecycleCollection, activeKey, map[string]any{"dataset": dataset, "manifestKey": manifestKey}); err != nil { + return err + } + return activateRevisionAndOwner(txCtx, tx, state, time.Now().UTC()) + }) +} + +func readActivationRow(ctx context.Context, tx store.Transaction, query string, binds map[string]any) (map[string]any, bool, error) { + var row map[string]any + err := tx.QueryRows(ctx, query, 1, binds, func(value map[string]any) error { + if row != nil { + return fmt.Errorf("activation guard returned more than one row") + } + row = value + return nil + }) + return row, row != nil, err +} + +func activationStateFromRow(row map[string]any) (activationState, error) { + owner, err := requiredActivationDocument(row, "owner") + if err != nil { + return activationState{}, err + } + candidate, err := requiredActivationDocument(row, "candidate") + if err != nil { + return activationState{}, err + } + prior, err := optionalActivationDocument(row, "prior") + if err != nil { + return activationState{}, err + } + return activationState{owner: owner, candidate: candidate, prior: prior}, nil +} + +func requiredActivationDocument(row map[string]any, field string) (map[string]any, error) { + document, err := optionalActivationDocument(row, field) + if err != nil { + return nil, err + } + if document == nil { + return nil, fmt.Errorf("activation guard returned no %s document", field) + } + return document, nil +} + +func optionalActivationDocument(row map[string]any, field string) (map[string]any, error) { + value := row[field] + if value == nil { + return nil, nil + } + document, ok := value.(map[string]any) + if !ok { + return nil, fmt.Errorf("activation guard returned invalid %s document", field) + } + return document, nil +} + +func activationDocumentKey(document map[string]any) (string, error) { + key, ok := document["_key"].(string) + if !ok || key == "" { + return "", fmt.Errorf("activation document has no _key") + } + return key, nil +} + +func activateRevisionAndOwner(ctx context.Context, tx store.Transaction, state activationState, now time.Time) error { + candidateKey, err := activationDocumentKey(state.candidate) + if err != nil { + return err + } + candidate, err := decode[explorer.Revision](state.candidate) + if err != nil { + return fmt.Errorf("decode activation candidate: %w", err) + } + if state.prior != nil { + priorKey, err := activationDocumentKey(state.prior) + if err != nil { + return err + } + if priorKey != candidateKey { + if err := updateActivationDocument(ctx, tx, RevisionsCollection, priorKey, map[string]any{"status": explorer.RevisionSuperseded}); err != nil { + return err + } + } + } + if err := updateActivationDocument(ctx, tx, RevisionsCollection, candidateKey, map[string]any{"status": explorer.RevisionActive, "activatedAt": now}); err != nil { + return err + } + ownerKey, err := activationDocumentKey(state.owner) + if err != nil { + return err + } + return updateActivationDocument(ctx, tx, ExplorersCollection, ownerKey, activeExplorerPatch(candidate, candidateKey, now)) +} + +func activeExplorerPatch(candidate explorer.Revision, revisionKey string, now time.Time) map[string]any { + publication := candidate.Publication + materializations, dataset := explorer.WithDataframeSelectors(candidate.Recipe, candidate.Materializations, candidate.Dataset) + publication.State = string(explorer.RevisionActive) + publication.RevisionID = revisionKey + publication.UpdatedAt = now + return map[string]any{ + "activeRevisionId": revisionKey, "activeConfig": candidate.Config, + "recipeDigest": candidate.RecipeDigest, "resolvedSchemaDigest": candidate.ResolvedSchemaDigest, + "sourceGeneration": candidate.SourceGeneration, "dataset": dataset, + "publication": publication, "emittedColumns": candidate.EmittedColumns, + "materializations": materializations, "diagnostics": candidate.Diagnostics, + } +} + +func updateActivationDocument(ctx context.Context, tx store.Transaction, collection, key string, patch map[string]any) error { + var updated bool + err := tx.QueryRows(ctx, activationUpdateAQL, 1, map[string]any{"@c": collection, "key": key, "patch": patch}, func(map[string]any) error { + if updated { + return fmt.Errorf("activation update returned more than one document") + } + updated = true + return nil + }) + if err != nil { + return err + } + if !updated { + return explorer.ErrDraftConflict + } + return nil +} + +var _ explorer.Store = (*Store)(nil) + +func decode[T any](value any) (T, error) { + var out T + raw, err := json.Marshal(value) + if err != nil { + return out, err + } + err = json.Unmarshal(raw, &out) + return out, err +} +func document(value any, k string) (map[string]any, error) { + raw, err := json.Marshal(value) + if err != nil { + return nil, err + } + var doc map[string]any + if err = json.Unmarshal(raw, &doc); err != nil { + return nil, err + } + doc["_key"] = k + return doc, nil +} diff --git a/internal/explorer/arango/store_test.go b/internal/explorer/arango/store_test.go new file mode 100644 index 00000000..f386aa79 --- /dev/null +++ b/internal/explorer/arango/store_test.go @@ -0,0 +1,138 @@ +package arango + +import ( + "context" + "strings" + "testing" + + storepkg "github.com/calypr/loom/internal/store/arango" +) + +type queryCall struct { + query string + binds map[string]any +} +type activationClient struct{ calls []queryCall } + +func (c *activationClient) WithTransaction(ctx context.Context, _ storepkg.TransactionCollections, fn storepkg.TransactionFunc) error { + return fn(ctx, c) +} + +func (c *activationClient) QueryRows(_ context.Context, query string, _ int, binds map[string]any, visit storepkg.RowVisitor) error { + c.calls = append(c.calls, queryCall{query: query, binds: binds}) + if strings.Contains(query, "RETURN {manifest:") { + return visit(compositeActivationRow()) + } + if strings.Contains(query, "RETURN {owner:") { + return visit(ownerActivationRow()) + } + return visit(map[string]any{"ok": true}) +} + +func ownerActivationRow() map[string]any { + return map[string]any{ + "owner": map[string]any{"_key": "owner-key", "project": "project-a", "explorerId": "default", "managementMode": "REPOSITORY"}, + "candidate": map[string]any{ + "_key": "revision-a", "id": "revision-a", "project": "project-a", "explorerId": "default", "status": "READY", + "config": map[string]any{}, "sourceGeneration": "generation-a", "publication": map[string]any{}, + "materializations": []any{}, "emittedColumns": []any{}, "diagnostics": []any{}, + }, + "prior": nil, + } +} + +func compositeActivationRow() map[string]any { + row := ownerActivationRow() + row["manifest"] = map[string]any{"_key": "manifest-key", "recordType": "manifest", "state": "STAGED", "dataset": map[string]any{"project": "project-a", "generation": "generation-a"}} + row["active"] = map[string]any{"_key": "active-key", "recordType": "active_generation", "project": "project-a"} + row["execution"] = map[string]any{"project": "project-a", "datasetGeneration": "generation-a", "state": "PUBLISHED"} + return row +} + +func TestActivateRepositoryGenerationUsesCompositeGuards(t *testing.T) { + client := &activationClient{} + adapter, err := New(client) + if err != nil { + t.Fatal(err) + } + if err := adapter.ActivateRepositoryGeneration(context.Background(), "project-a", "generation-a", "revision-a"); err != nil { + t.Fatal(err) + } + if len(client.calls) != 4 { + t.Fatalf("calls=%d", len(client.calls)) + } + query := client.calls[0].query + for _, required := range []string{ + "@@lifecycle", "@@explorers", "@@revisions", "@@executions", + "manifest.state IN [\"STAGED\", \"READY\"]", + "candidate.status == \"ACTIVE\" AND owner.activeRevisionId == @revisionKey", + "execution.project == @project", "execution.datasetGeneration == @generation", "execution.state == \"PUBLISHED\"", + } { + if !strings.Contains(query, required) { + t.Fatalf("query missing %q:\n%s", required, query) + } + } + allQueries := "" + for _, call := range client.calls { + allQueries += call.query + } + if got := strings.Count(allQueries, "UPDATE d WITH"); got != 3 { + t.Fatalf("composite activation updates=%d, want 3:\n%s", got, allQueries) + } + if got := client.calls[0].binds["generation"]; got != "generation-a" { + t.Fatalf("generation bind=%v", got) + } +} + +func TestActivationUsesTransactionsAndSingleModificationQueries(t *testing.T) { + tests := []struct { + name string + call func(context.Context, *Store) error + }{ + { + name: "interactive", + call: func(ctx context.Context, store *Store) error { + return store.ActivateInteractive(ctx, "project-a", "explorer-a", "revision-a") + }, + }, + { + name: "repository", + call: func(ctx context.Context, store *Store) error { + return store.ActivateRepository(ctx, "project-a", "revision-a") + }, + }, + { + name: "repository generation", + call: func(ctx context.Context, store *Store) error { + return store.ActivateRepositoryGeneration(ctx, "project-a", "generation-a", "revision-a") + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + client := &activationClient{} + store, err := New(client) + if err != nil { + t.Fatal(err) + } + if err := test.call(context.Background(), store); err != nil { + t.Fatal(err) + } + if len(client.calls) < 3 { + t.Fatalf("calls=%d, want read plus updates", len(client.calls)) + } + for _, call := range client.calls { + for _, invalid := range []string{ + "? null : UPDATE", "LET active = UPDATE", "LET explorer = UPDATE", "LET owner = UPDATE", + "LET activateDataset = UPDATE", "LET activateRevision = UPDATE", "LET activateExplorer = UPDATE", + "FOR priorDoc IN [prior]", + } { + if strings.Contains(call.query, invalid) { + t.Fatalf("invalid AQL activation form %q:\n%s", invalid, call.query) + } + } + } + }) + } +} diff --git a/internal/explorer/catalog.go b/internal/explorer/catalog.go new file mode 100644 index 00000000..593f2a44 --- /dev/null +++ b/internal/explorer/catalog.go @@ -0,0 +1,87 @@ +package explorer + +import ( + "crypto/sha256" + "encoding/hex" + "encoding/json" + "sort" +) + +// Catalog is assembled server-side from scoped Loom catalog discovery. The +// browser receives only opaque IDs; source selectors never cross this seam. +type Catalog struct { + Nodes []CatalogNode + Edges []CatalogEdge + Selections map[string]CatalogSelection +} + +type CatalogNode struct { + ID string + ResourceType string +} + +type CatalogEdge struct{ ID, FromNodeID, ToNodeID, Label string } + +type CatalogSelection struct { + ID string + NodeID string + FieldRef string + Select string + LogicalType string + Filterable bool + Chartable bool +} + +// DiscoveryResult makes incomplete discovery explicit. Production catalog +// adapters must never silently translate an upstream failure into an empty, +// apparently complete catalog. +type DiscoveryResult[T any] struct { + Values []T + Complete bool + Truncated bool + Diagnostics []Diagnostic +} +type CatalogSnapshot struct { + Project, Generation, AuthorizationScopeDigest string + Catalog Catalog + ResolvedSchemaDigest string + Complete bool + Truncated bool + Diagnostics []Diagnostic + Token string +} + +func NewCatalogSnapshot(project, generation, scope string, catalog Catalog, complete, truncated bool, diagnostics []Diagnostic) (CatalogSnapshot, error) { + nodes := append([]CatalogNode(nil), catalog.Nodes...) + sort.Slice(nodes, func(i, j int) bool { return nodes[i].ID < nodes[j].ID }) + selectionIDs := make([]string, 0, len(catalog.Selections)) + for id := range catalog.Selections { + selectionIDs = append(selectionIDs, id) + } + sort.Strings(selectionIDs) + identity := struct { + Project, Generation, Scope string + Nodes []CatalogNode + Edges []CatalogEdge + Selections []CatalogSelection + Complete, Truncated bool + }{Project: project, Generation: generation, Scope: scope, Nodes: nodes, Edges: append([]CatalogEdge(nil), catalog.Edges...), Complete: complete, Truncated: truncated} + for _, id := range selectionIDs { + identity.Selections = append(identity.Selections, catalog.Selections[id]) + } + raw, err := json.Marshal(identity) + if err != nil { + return CatalogSnapshot{}, err + } + sum := sha256.Sum256(raw) + return CatalogSnapshot{Project: project, Generation: generation, AuthorizationScopeDigest: scope, Catalog: catalog, Complete: complete, Truncated: truncated, Diagnostics: append([]Diagnostic(nil), diagnostics...), Token: "sha256:" + hex.EncodeToString(sum[:])}, nil +} +func (s CatalogSnapshot) ValidateToken(token string) error { + if token == "" || token != s.Token { + return ErrStaleCatalog + } + if !s.Complete || s.Truncated { + return ErrIncompleteCatalog + } + return nil +} diff --git a/internal/explorer/catalog_test.go b/internal/explorer/catalog_test.go new file mode 100644 index 00000000..6be288c6 --- /dev/null +++ b/internal/explorer/catalog_test.go @@ -0,0 +1,22 @@ +package explorer + +import "testing" + +func TestCatalogSnapshotBindsIdentityAndBlocksIncompleteDiscovery(t *testing.T) { + catalog := Catalog{Nodes: []CatalogNode{{ID: "n", ResourceType: "Patient"}}, Selections: map[string]CatalogSelection{"s": {ID: "s", NodeID: "n"}}} + a, err := NewCatalogSnapshot("p", "g", "scope", catalog, true, false, nil) + if err != nil { + t.Fatal(err) + } + if err := a.ValidateToken(a.Token); err != nil { + t.Fatal(err) + } + b, _ := NewCatalogSnapshot("p", "other", "scope", catalog, true, false, nil) + if a.Token == b.Token { + t.Fatal("generation did not affect snapshot") + } + incomplete, _ := NewCatalogSnapshot("p", "g", "scope", catalog, false, true, nil) + if err := incomplete.ValidateToken(incomplete.Token); err != ErrIncompleteCatalog { + t.Fatalf("err=%v", err) + } +} diff --git a/internal/explorer/compilation.go b/internal/explorer/compilation.go new file mode 100644 index 00000000..a8803d22 --- /dev/null +++ b/internal/explorer/compilation.go @@ -0,0 +1,28 @@ +package explorer + +import ( + "crypto/sha256" + "encoding/hex" + + "github.com/calypr/loom/internal/dataframe/recipe" +) + +// Compilation is the transport-neutral result shared by the V2 compiler and +// publication lifecycle. It contains executable recipe data and derived +// physical columns; the lossless ExplorerConfigV2 packet is stored separately. +type Compilation struct { + Bundle recipe.Bundle + RecipeDigest string + EmittedColumns []EmittedColumn +} + +type EmittedColumn struct { + OutputID, NodeID, SelectionID, PublicColumn string + LogicalType string + Filterable, Chartable bool +} + +func OpaqueID(prefix, identity string) string { + sum := sha256.Sum256([]byte(identity)) + return prefix + hex.EncodeToString(sum[:]) +} diff --git a/internal/explorer/config_v2.go b/internal/explorer/config_v2.go new file mode 100644 index 00000000..f73e230e --- /dev/null +++ b/internal/explorer/config_v2.go @@ -0,0 +1,190 @@ +package explorer + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "regexp" + "strings" + + "github.com/calypr/loom/internal/dataframe/recipe" +) + +// ConfigV2 is the portable Explorer artifact. Both repository and interactive +// packets may carry the complete human-facing presentation layer. A repository +// packet may also be baseline-only, in which case the presentation fields are +// omitted and the frontend derives a layout from live dataset metadata. It +// contains no catalog, selector, join, or other Builder implementation ID. +const ConfigV2APIVersion = "loom.calypr.org/explorer-config/v2" + +var idPattern = regexp.MustCompile(`^[a-z][a-z0-9-]{0,63}$`) + +type ConfigV2 struct { + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Project string `json:"project"` + Explorer ConfigExplorer `json:"explorer"` + Recipe json.RawMessage `json:"recipe"` + Views []ConfigView `json:"views,omitempty"` + SharedFilters map[string][]SharedFilter `json:"sharedFilters,omitempty"` + FileActions FileActions `json:"fileActions,omitempty"` +} + +type ConfigExplorer struct { + ID string `json:"id"` + Title string `json:"title"` + Description string `json:"description,omitempty"` + Management string `json:"management"` +} +type ConfigView struct { + ID string `json:"id"` + Title string `json:"title"` + Output string `json:"output"` + RowLabel string `json:"rowLabel,omitempty"` + Table ConfigTable `json:"table"` + Filters []ConfigFilter `json:"filters,omitempty"` + Charts []ConfigChart `json:"charts,omitempty"` + FixedFilters map[string][]string `json:"fixedFilters,omitempty"` + Actions []ConfigAction `json:"actions,omitempty"` +} +type ConfigTable struct { + Columns []ConfigColumn `json:"columns"` +} +type ConfigColumn struct { + Column string `json:"column"` + Label string `json:"label,omitempty"` + Visible bool `json:"visible"` +} +type ConfigFilter struct { + Column string `json:"column"` + Label string `json:"label,omitempty"` +} +type ConfigChart struct { + Column string `json:"column"` + Type string `json:"type"` + Title string `json:"title,omitempty"` +} +type ConfigAction struct { + Type string `json:"type"` + Title string `json:"title"` + FileName string `json:"fileName,omitempty"` + Output string `json:"output,omitempty"` + Columns []string `json:"columns,omitempty"` +} +type SharedFilter struct { + Output string `json:"output"` + Column string `json:"column"` +} +type FileActions struct { + Extensions map[string][]string `json:"extensions,omitempty"` + Actions map[string]string `json:"actions,omitempty"` +} + +// DecodeConfigV2 rejects the legacy explorerConfig/tabs envelope and every +// unknown field. The recipe gets its own strict decoder and validator. +func DecodeConfigV2(raw []byte, project string) (ConfigV2, recipe.Bundle, error) { + return DecodeDefaultConfigV2(raw, project) +} + +// DecodeDefaultConfigV2 validates the repository contract. Repository packets +// may be baseline-only or may include a complete presentation layer authored +// by ETL. In the latter case the packet is preserved losslessly and exposed as +// the default's activeConfig after publication. +func DecodeDefaultConfigV2(raw []byte, project string) (ConfigV2, recipe.Bundle, error) { + return decodeConfigV2(raw, project, "default", "repository") +} + +// DecodeInteractiveConfigV2 validates a complete interactive V2 document. It +// shares the exact recipe/presentation validator used by repository deployment +// while keeping ownership mode explicit. +func DecodeInteractiveConfigV2(raw []byte, project, explorerID string) (ConfigV2, recipe.Bundle, error) { + return decodeConfigV2(raw, project, explorerID, "interactive") +} + +// CanonicalConfigV2 validates raw and returns deterministic JSON plus its +// content digest. Generic JSON canonicalization preserves every V2 field, +// including presentation data that is not represented in recipe.Bundle. +func CanonicalConfigV2(raw []byte, project, explorerID, management string) (ConfigV2, recipe.Bundle, []byte, string, error) { + var cfg ConfigV2 + var bundle recipe.Bundle + var err error + if management == "interactive" { + cfg, bundle, err = DecodeInteractiveConfigV2(raw, project, explorerID) + } else { + cfg, bundle, err = decodeConfigV2(raw, project, explorerID, management) + } + if err != nil { + return cfg, bundle, nil, "", err + } + decoder := json.NewDecoder(bytes.NewReader(raw)) + decoder.UseNumber() + var value any + if err := decoder.Decode(&value); err != nil { + return cfg, bundle, nil, "", fmt.Errorf("canonicalize ExplorerConfigV2: %w", err) + } + canonical, err := json.Marshal(value) + if err != nil { + return cfg, bundle, nil, "", fmt.Errorf("canonicalize ExplorerConfigV2: %w", err) + } + sum := sha256.Sum256(canonical) + return cfg, bundle, canonical, "sha256:" + hex.EncodeToString(sum[:]), nil +} + +func decodeConfigV2(raw []byte, project, explorerID, management string) (ConfigV2, recipe.Bundle, error) { + var cfg ConfigV2 + decoder := json.NewDecoder(bytes.NewReader(raw)) + decoder.DisallowUnknownFields() + if err := decoder.Decode(&cfg); err != nil { + return cfg, recipe.Bundle{}, fmt.Errorf("decode ExplorerConfigV2: %w", err) + } + var trailing any + if err := decoder.Decode(&trailing); err != io.EOF { + return cfg, recipe.Bundle{}, fmt.Errorf("decode ExplorerConfigV2: multiple JSON values") + } + if cfg.APIVersion != ConfigV2APIVersion || cfg.Kind != "ExplorerConfig" { + return cfg, recipe.Bundle{}, fmt.Errorf("apiVersion must be %q and kind must be ExplorerConfig", ConfigV2APIVersion) + } + if cfg.Project != project { + return cfg, recipe.Bundle{}, fmt.Errorf("config project must match deployment project") + } + if cfg.Explorer.ID != explorerID || !strings.EqualFold(cfg.Explorer.Management, management) { + return cfg, recipe.Bundle{}, fmt.Errorf("config explorer identity or management mode does not match deployment") + } + if strings.TrimSpace(cfg.Explorer.Title) == "" { + return cfg, recipe.Bundle{}, fmt.Errorf("ExplorerConfigV2 requires a title") + } + hasPresentation := len(cfg.Views) > 0 || len(cfg.SharedFilters) > 0 || len(cfg.FileActions.Extensions) > 0 || len(cfg.FileActions.Actions) > 0 + if strings.EqualFold(management, "interactive") && len(cfg.Views) == 0 { + return cfg, recipe.Bundle{}, fmt.Errorf("interactive ExplorerConfigV2 requires at least one view") + } + if strings.EqualFold(management, "repository") && hasPresentation && len(cfg.Views) == 0 { + return cfg, recipe.Bundle{}, fmt.Errorf("repository ExplorerConfigV2 presentation requires at least one view") + } + bundle, err := recipe.Parse(cfg.Recipe) + if err != nil { + return cfg, recipe.Bundle{}, fmt.Errorf("invalid recipe: %w", err) + } + outputs := map[string]bool{} + for _, output := range bundle.Outputs { + outputs[output.Name] = true + } + views := map[string]bool{} + for i, view := range cfg.Views { + if !idPattern.MatchString(view.ID) || views[view.ID] || strings.TrimSpace(view.Title) == "" || !outputs[view.Output] { + return cfg, recipe.Bundle{}, fmt.Errorf("views[%d] must have a unique id, title, and recipe output", i) + } + views[view.ID] = true + if len(view.Table.Columns) == 0 { + return cfg, recipe.Bundle{}, fmt.Errorf("views[%d].table.columns is required", i) + } + for _, column := range view.Table.Columns { + if strings.TrimSpace(column.Column) == "" { + return cfg, recipe.Bundle{}, fmt.Errorf("views[%d] has an empty table column", i) + } + } + } + return cfg, bundle, nil +} diff --git a/internal/explorer/config_v2_test.go b/internal/explorer/config_v2_test.go new file mode 100644 index 00000000..c84f5460 --- /dev/null +++ b/internal/explorer/config_v2_test.go @@ -0,0 +1,48 @@ +package explorer + +import "testing" + +func TestDecodeDefaultConfigV2AcceptsExecutableRecipeWithoutPresentation(t *testing.T) { + raw := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Default","management":"repository"},"recipe":{"recipeSchemaVersion":1,"name":"repository","translationVersion":"v1","outputs":[{"name":"Patient","rootResourceType":"Patient","rowGrain":"patient","fields":[{"name":"id","expr":{"select":"root.id"}}]}]}}`) + cfg, bundle, err := DecodeDefaultConfigV2(raw, "project-a") + if err != nil { + t.Fatal(err) + } + if len(cfg.Views) != 0 || bundle.Outputs[0].Name != "Patient" { + t.Fatalf("decoded %#v %#v", cfg, bundle) + } +} + +func TestDecodeInteractiveConfigV2AcceptsPresentation(t *testing.T) { + raw := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"custom","title":"Custom","management":"interactive"},"recipe":{"recipeSchemaVersion":1,"name":"repository","translationVersion":"v1","outputs":[{"name":"Patient","rootResourceType":"Patient","rowGrain":"patient","fields":[{"name":"id","expr":{"select":"root.id"}}]}]},"views":[{"id":"patient","title":"Patients","output":"Patient","table":{"columns":[{"column":"id","visible":true}]}}]}`) + cfg, bundle, err := DecodeInteractiveConfigV2(raw, "project-a", "custom") + if err != nil { + t.Fatal(err) + } + if cfg.Views[0].Output != "Patient" || bundle.Outputs[0].Name != "Patient" { + t.Fatalf("decoded %#v %#v", cfg, bundle) + } +} + +func TestDecodeDefaultConfigV2AcceptsCompletePresentation(t *testing.T) { + raw := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Default","management":"repository"},"recipe":{"recipeSchemaVersion":1,"name":"repository","translationVersion":"v1","outputs":[{"name":"Patient","rootResourceType":"Patient","rowGrain":"patient","fields":[{"name":"id","expr":{"select":"root.id"}}]}]},"views":[{"id":"patient","title":"Patients","output":"Patient","table":{"columns":[{"column":"id","visible":true}]}}],"sharedFilters":{"patient":[{"output":"Patient","column":"id"}]}}`) + cfg, bundle, err := DecodeDefaultConfigV2(raw, "project-a") + if err != nil { + t.Fatal(err) + } + if len(cfg.Views) != 1 || len(cfg.SharedFilters["patient"]) != 1 || bundle.Outputs[0].Name != "Patient" { + t.Fatalf("decoded %#v %#v", cfg, bundle) + } +} + +func TestDecodeConfigV2RejectsLegacyAndUnknownFields(t *testing.T) { + for _, raw := range [][]byte{ + []byte(`{"explorerConfig":[]}`), + []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Default","management":"repository"},"recipe":{},"views":[],"tabs":[]}`), + []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Default","management":"repository"},"recipe":{"recipeSchemaVersion":1,"name":"repository","translationVersion":"v1","outputs":[]},"sharedFilters":{"patient":[{"output":"Patient","column":"id"}]}}`), + } { + if _, _, err := DecodeConfigV2(raw, "project-a"); err == nil { + t.Fatalf("accepted %s", raw) + } + } +} diff --git a/internal/explorer/identity.go b/internal/explorer/identity.go new file mode 100644 index 00000000..38ea34d2 --- /dev/null +++ b/internal/explorer/identity.go @@ -0,0 +1,34 @@ +package explorer + +import ( + "strings" +) + +// StableExplorerID turns a user-facing name into the durable URL identity +// used by the V2 lifecycle. Collisions remain store-level conflicts. +func StableExplorerID(name string) string { + var b strings.Builder + lastDash := false + for _, r := range strings.ToLower(strings.TrimSpace(name)) { + if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') { + b.WriteByte(byte(r)) + lastDash = false + continue + } + if b.Len() > 0 && !lastDash { + b.WriteByte('-') + lastDash = true + } + } + id := strings.Trim(b.String(), "-") + if id == "" { + id = "explorer" + } + if id[0] < 'a' || id[0] > 'z' { + id = "explorer-" + id + } + if len(id) > 64 { + id = strings.TrimRight(id[:64], "-") + } + return id +} diff --git a/internal/explorer/memory_store.go b/internal/explorer/memory_store.go new file mode 100644 index 00000000..3d5a44f0 --- /dev/null +++ b/internal/explorer/memory_store.go @@ -0,0 +1,232 @@ +package explorer + +import ( + "context" + "sort" + "sync" + "time" +) + +// MemoryStore is used by service tests and local wiring; durable deployments +// use the Arango implementation. +type MemoryStore struct { + mu sync.Mutex + explorers map[string]Explorer + revisions map[string]Revision + configs map[string]RepositoryConfig +} + +func NewMemoryStore() *MemoryStore { + return &MemoryStore{explorers: map[string]Explorer{}, revisions: map[string]Revision{}, configs: map[string]RepositoryConfig{}} +} +func configKey(project, id string) string { return project + "\x00" + id } +func (s *MemoryStore) ListConfigs(_ context.Context, project string) ([]RepositoryConfig, error) { + s.mu.Lock() + defer s.mu.Unlock() + out := []RepositoryConfig{} + for _, value := range s.configs { + if value.Project == project { + out = append(out, value) + } + } + sort.Slice(out, func(i, j int) bool { return out[i].ExplorerID < out[j].ExplorerID }) + return out, nil +} +func (s *MemoryStore) GetConfig(_ context.Context, project, id string) (*RepositoryConfig, error) { + s.mu.Lock() + defer s.mu.Unlock() + v, ok := s.configs[configKey(project, id)] + if !ok { + return nil, ErrNotFound + } + return &v, nil +} +func (s *MemoryStore) SaveConfig(_ context.Context, value RepositoryConfig) (*RepositoryConfig, error) { + s.mu.Lock() + defer s.mu.Unlock() + value.UpdatedAt = time.Now().UTC() + value.Config = append([]byte(nil), value.Config...) + s.configs[configKey(value.Project, value.ExplorerID)] = value + return &value, nil +} +func (s *MemoryStore) GetRepositoryConfig(ctx context.Context, project string) (*RepositoryConfig, error) { + return s.GetConfig(ctx, project, "default") +} +func (s *MemoryStore) SaveRepositoryConfig(ctx context.Context, value RepositoryConfig) (*RepositoryConfig, error) { + value.ExplorerID, value.Management = "default", ManagementRepository + return s.SaveConfig(ctx, value) +} +func explorerKey(project, id string) string { return project + "\x00" + id } +func (s *MemoryStore) List(_ context.Context, project string) ([]Explorer, error) { + s.mu.Lock() + defer s.mu.Unlock() + out := []Explorer{} + for _, e := range s.explorers { + if e.Project == project { + out = append(out, e) + } + } + sort.Slice(out, func(i, j int) bool { return out[i].ExplorerID < out[j].ExplorerID }) + return out, nil +} +func (s *MemoryStore) Get(_ context.Context, p, id string) (*Explorer, error) { + s.mu.Lock() + defer s.mu.Unlock() + e, ok := s.explorers[explorerKey(p, id)] + if !ok { + return nil, ErrNotFound + } + return &e, nil +} +func (s *MemoryStore) CreateInteractive(_ context.Context, e Explorer) (*Explorer, error) { + s.mu.Lock() + defer s.mu.Unlock() + k := explorerKey(e.Project, e.ExplorerID) + if _, ok := s.explorers[k]; ok { + return nil, ErrDraftConflict + } + s.explorers[k] = e + return &e, nil +} +func (s *MemoryStore) CreateRepository(ctx context.Context, e Explorer) (*Explorer, error) { + return s.CreateInteractive(ctx, e) +} +func (s *MemoryStore) SaveDraft(_ context.Context, e Explorer, expected int64, expectedDigest ...string) (*Explorer, error) { + s.mu.Lock() + defer s.mu.Unlock() + k := explorerKey(e.Project, e.ExplorerID) + old, ok := s.explorers[k] + if !ok { + return nil, ErrNotFound + } + if old.DraftVersion != expected { + return nil, ErrDraftConflict + } + if len(expectedDigest) > 0 && expectedDigest[0] != "" && old.DraftDigest != expectedDigest[0] { + return nil, ErrDraftConflict + } + e.DraftVersion = old.DraftVersion + 1 + e.UpdatedAt = time.Now().UTC() + e.DraftConfig = append([]byte(nil), e.DraftConfig...) + e.ActiveConfig = append([]byte(nil), e.ActiveConfig...) + s.explorers[k] = e + return &e, nil +} +func (s *MemoryStore) InsertRevision(_ context.Context, r Revision) (*Revision, error) { + s.mu.Lock() + defer s.mu.Unlock() + if old, ok := s.revisions[r.ID]; ok { + return &old, nil + } + s.revisions[r.ID] = r + return &r, nil +} +func (s *MemoryStore) GetRevision(_ context.Context, id string) (*Revision, error) { + s.mu.Lock() + defer s.mu.Unlock() + r, ok := s.revisions[id] + if !ok { + return nil, ErrNotFound + } + return &r, nil +} +func (s *MemoryStore) TransitionRevision(_ context.Context, id string, status RevisionStatus, diags []Diagnostic) (*Revision, error) { + s.mu.Lock() + defer s.mu.Unlock() + r, ok := s.revisions[id] + if !ok { + return nil, ErrNotFound + } + r.Status = status + r.Diagnostics = append([]Diagnostic(nil), diags...) + now := time.Now().UTC() + if status == RevisionReady { + r.ReadyAt = &now + } + if status == RevisionFailed { + r.FailedAt = &now + } + s.revisions[id] = r + return &r, nil +} +func (s *MemoryStore) ActivateInteractive(_ context.Context, p, id, revisionID string) error { + s.mu.Lock() + defer s.mu.Unlock() + k := explorerKey(p, id) + e, ok := s.explorers[k] + if !ok { + return ErrNotFound + } + r, ok := s.revisions[revisionID] + if !ok { + return ErrNotFound + } + if r.Status != RevisionReady { + return ErrImmutableRevision + } + if e.ActiveRevisionID != "" { + prior := s.revisions[e.ActiveRevisionID] + prior.Status = RevisionSuperseded + s.revisions[prior.ID] = prior + } + now := time.Now().UTC() + r.Status = RevisionActive + r.ActivatedAt = &now + s.revisions[r.ID] = r + e.ActiveRevisionID = r.ID + e.ActiveConfig = append([]byte(nil), r.Config...) + e.RecipeDigest = r.RecipeDigest + e.ResolvedSchemaDigest = r.ResolvedSchemaDigest + e.SourceGeneration = r.SourceGeneration + e.Dataset = r.Dataset + e.Publication = r.Publication + e.Publication.State = string(RevisionActive) + e.Publication.RevisionID = r.ID + e.Publication.UpdatedAt = now + e.EmittedColumns = append([]EmittedColumn(nil), r.EmittedColumns...) + e.Materializations = append([]Materialization(nil), r.Materializations...) + e.Diagnostics = append([]Diagnostic(nil), r.Diagnostics...) + s.explorers[k] = e + return nil +} +func (s *MemoryStore) ActivateRepository(_ context.Context, project, revisionID string) error { + s.mu.Lock() + defer s.mu.Unlock() + e, ok := s.explorers[explorerKey(project, "default")] + if !ok { + return ErrNotFound + } + r, ok := s.revisions[revisionID] + if !ok { + return ErrNotFound + } + if e.ManagementMode != ManagementRepository || (r.Status != RevisionReady && !(r.Status == RevisionActive && e.ActiveRevisionID == revisionID)) { + return ErrImmutableRevision + } + if e.ActiveRevisionID != "" && e.ActiveRevisionID != revisionID { + prior := s.revisions[e.ActiveRevisionID] + prior.Status = RevisionSuperseded + s.revisions[prior.ID] = prior + } + now := time.Now().UTC() + r.Status = RevisionActive + r.ActivatedAt = &now + s.revisions[r.ID] = r + e.ActiveRevisionID = r.ID + e.ActiveConfig = append([]byte(nil), r.Config...) + e.RecipeDigest = r.RecipeDigest + e.ResolvedSchemaDigest = r.ResolvedSchemaDigest + e.SourceGeneration = r.SourceGeneration + e.Materializations, e.Dataset = WithDataframeSelectors(r.Recipe, r.Materializations, r.Dataset) + e.Publication = r.Publication + e.Publication.State = string(RevisionActive) + e.Publication.RevisionID = r.ID + e.Publication.UpdatedAt = now + e.EmittedColumns = append([]EmittedColumn(nil), r.EmittedColumns...) + e.Diagnostics = append([]Diagnostic(nil), r.Diagnostics...) + s.explorers[explorerKey(project, "default")] = e + return nil +} +func (s *MemoryStore) ActivateRepositoryGeneration(ctx context.Context, project, _ string, revisionID string) error { + return s.ActivateRepository(ctx, project, revisionID) +} diff --git a/internal/explorer/service.go b/internal/explorer/service.go new file mode 100644 index 00000000..8b6d0502 --- /dev/null +++ b/internal/explorer/service.go @@ -0,0 +1,223 @@ +package explorer + +import ( + "context" + "crypto/rand" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "time" + + "github.com/calypr/loom/internal/dataframe/publication" +) + +// Service is the persistence-neutral lifecycle coordinator. Compiler and +// publication adapters are intentionally injected by server wiring. +type Service struct { + store Store + now func() time.Time +} + +func NewService(store Store) (*Service, error) { + if store == nil { + return nil, fmt.Errorf("Explorer store is required") + } + return &Service{store: store, now: func() time.Time { return time.Now().UTC() }}, nil +} +func (s *Service) List(ctx context.Context, project string) ([]Explorer, error) { + return s.store.List(ctx, project) +} +func (s *Service) RepositoryConfig(ctx context.Context, project string) (*RepositoryConfig, error) { + return s.store.GetRepositoryConfig(ctx, project) +} +func (s *Service) SaveRepositoryConfig(ctx context.Context, value RepositoryConfig) (*RepositoryConfig, error) { + return s.store.SaveRepositoryConfig(ctx, value) +} +func (s *Service) ListConfigs(ctx context.Context, project string) ([]RepositoryConfig, error) { + return s.store.ListConfigs(ctx, project) +} +func (s *Service) Config(ctx context.Context, project, id string) (*RepositoryConfig, error) { + return s.store.GetConfig(ctx, project, id) +} +func (s *Service) SaveConfig(ctx context.Context, value RepositoryConfig) (*RepositoryConfig, error) { + return s.store.SaveConfig(ctx, value) +} +func (s *Service) Get(ctx context.Context, project, id string) (*Explorer, error) { + return s.store.Get(ctx, project, id) +} +func (s *Service) Revision(ctx context.Context, id string) (*Revision, error) { + return s.store.GetRevision(ctx, id) +} +func (s *Service) ActiveRevision(ctx context.Context, project, id string) (*Revision, error) { + e, err := s.store.Get(ctx, project, id) + if err != nil { + return nil, err + } + if e.ActiveRevisionID == "" { + return nil, ErrNotFound + } + return s.store.GetRevision(ctx, e.ActiveRevisionID) +} +func (s *Service) FailRevision(ctx context.Context, id string, diagnostics []Diagnostic) (*Revision, error) { + return s.store.TransitionRevision(ctx, id, RevisionFailed, diagnostics) +} + +// NewInteractiveRevisionID is opaque and collision-resistant; repository +// revisions intentionally use the deterministic tuple identity instead. +func NewInteractiveRevisionID() (string, error) { + bytes := make([]byte, 16) + if _, err := rand.Read(bytes); err != nil { + return "", err + } + return "interactive_" + hex.EncodeToString(bytes), nil +} + +// UpsertRepositoryV2 records the repository-owned default and its immutable +// ready revision after the external dataframe publication has succeeded. +// Activation is intentionally a separate call so callers can compose it with +// the dataset release switch where the durable adapter supports that atomic +// transaction. +func (s *Service) UpsertRepositoryV2(ctx context.Context, raw []byte, sourceCommit, sourceGeneration, actor string, compiled Compilation, resolvedSchemaDigest string, materializations []Materialization, dataset DatasetMetadata, publication PublicationMetadata) (*Explorer, *Revision, error) { + cfg, _, canonical, configDigest, err := CanonicalConfigV2(raw, "", "default", "repository") + if err != nil { + // The project is carried by the packet; decode once to obtain it while + // preserving the strict validator above. + var envelope struct { + Project string `json:"project"` + } + if decodeErr := json.Unmarshal(raw, &envelope); decodeErr != nil { + return nil, nil, err + } + cfg, _, canonical, configDigest, err = CanonicalConfigV2(raw, envelope.Project, "default", "repository") + if err != nil { + return nil, nil, err + } + } + project := cfg.Project + owner, err := s.store.Get(ctx, project, "default") + if errors.Is(err, ErrNotFound) { + owner, err = s.store.CreateRepository(ctx, Explorer{Project: project, ExplorerID: "default", Title: cfg.Explorer.Title, ManagementMode: ManagementRepository, DraftConfig: canonical, DraftVersion: 1, DraftDigest: configDigest, SourceGeneration: sourceGeneration, Dataset: dataset, Publication: publication, UpdatedBy: actor, UpdatedAt: s.now()}) + } else if err == nil { + owner.Title, owner.DraftConfig, owner.DraftDigest, owner.SourceGeneration, owner.Dataset, owner.Publication, owner.UpdatedBy = cfg.Explorer.Title, canonical, configDigest, sourceGeneration, dataset, publication, actor + owner, err = s.store.SaveDraft(ctx, *owner, owner.DraftVersion) + } + if err != nil { + return nil, nil, err + } + revisionID := RepositoryRevisionID(project, sourceCommit, configDigest, sourceGeneration) + now := s.now() + revision, err := s.store.InsertRevision(ctx, Revision{ID: revisionID, Project: project, ExplorerID: "default", Config: canonical, ConfigDigest: configDigest, Recipe: compiled.Bundle, RecipeDigest: compiled.RecipeDigest, ResolvedSchemaDigest: resolvedSchemaDigest, SourceGeneration: sourceGeneration, SourceCommit: sourceCommit, Dataset: dataset, Publication: publication, Materializations: append([]Materialization(nil), materializations...), EmittedColumns: append([]EmittedColumn(nil), compiled.EmittedColumns...), Status: RevisionReady, CreatedBy: actor, CreatedAt: now, ReadyAt: &now}) + if err != nil { + return nil, nil, err + } + return owner, revision, nil +} +func (s *Service) ActivateInteractive(ctx context.Context, project, explorerID, revisionID string) error { + return s.store.ActivateInteractive(ctx, project, explorerID, revisionID) +} +func (s *Service) ActivateRepository(ctx context.Context, project, revisionID string) error { + return s.store.ActivateRepository(ctx, project, revisionID) +} +func (s *Service) ActivateRepositoryGeneration(ctx context.Context, project, generation, revisionID string) error { + return s.store.ActivateRepositoryGeneration(ctx, project, generation, revisionID) +} + +// RepositoryRevisionID is stable for retrying the same checked-out repository +// content against the same Loom generation. It intentionally has no Gecko +// organization/project identity component. +func RepositoryRevisionID(project, sourceCommit, definitionDigest, sourceGeneration string) string { + sum := sha256.Sum256([]byte(project + "\x00default\x00" + sourceCommit + "\x00" + definitionDigest + "\x00" + sourceGeneration)) + return "repository_" + hex.EncodeToString(sum[:]) +} + +// CreateInteractiveV2 persists a complete V2 draft without compiling or +// materializing it. The raw canonical packet is retained alongside the digest +// so presentation-only fields survive a later read unchanged. +func (s *Service) CreateInteractiveV2(ctx context.Context, project, id string, raw []byte, actor string) (*Explorer, error) { + if id == "default" { + return nil, fmt.Errorf("default Explorer is repository-managed") + } + cfg, _, canonical, digest, err := CanonicalConfigV2(raw, project, id, "interactive") + if err != nil { + return nil, err + } + return s.store.CreateInteractive(ctx, Explorer{ + Project: project, ExplorerID: id, Title: cfg.Explorer.Title, + ManagementMode: ManagementInteractive, DraftConfig: canonical, + DraftVersion: 1, DraftDigest: digest, UpdatedBy: actor, UpdatedAt: s.now(), + }) +} + +// SaveInteractiveDraftV2 is the only V2 draft write path. It performs no +// compilation or materialization and supplies both CAS components to the +// durable adapter. +func (s *Service) SaveInteractiveDraftV2(ctx context.Context, project, id string, raw []byte, expected int64, expectedDigest, actor string) (*Explorer, error) { + if id == "default" { + return nil, fmt.Errorf("default Explorer is repository-managed") + } + cfg, _, canonical, digest, err := CanonicalConfigV2(raw, project, id, "interactive") + if err != nil { + return nil, err + } + current, err := s.store.Get(ctx, project, id) + if err != nil { + return nil, err + } + if current.ManagementMode != ManagementInteractive { + return nil, fmt.Errorf("Explorer is not interactive") + } + current.Title = cfg.Explorer.Title + current.DraftConfig = canonical + current.DraftDigest = digest + current.UpdatedBy = actor + return s.store.SaveDraft(ctx, *current, expected, expectedDigest) +} + +func (s *Service) InsertInteractiveReadyRevisionV2(ctx context.Context, owner *Explorer, config []byte, configDigest string, compiled Compilation, resolvedSchemaDigest, sourceGeneration, actor string, materializations []Materialization) (*Revision, error) { + if owner == nil || owner.ManagementMode != ManagementInteractive { + return nil, fmt.Errorf("Explorer is not interactive") + } + id, err := NewInteractiveRevisionID() + if err != nil { + return nil, err + } + now := s.now() + return s.store.InsertRevision(ctx, Revision{ + ID: id, Project: owner.Project, ExplorerID: owner.ExplorerID, + Config: append([]byte(nil), config...), ConfigDigest: configDigest, + Recipe: compiled.Bundle, RecipeDigest: compiled.RecipeDigest, + ResolvedSchemaDigest: resolvedSchemaDigest, SourceGeneration: sourceGeneration, + Dataset: datasetMetadata(sourceGeneration, resolvedSchemaDigest, materializations), + Publication: PublicationMetadata{State: string(RevisionReady), Generation: sourceGeneration, UpdatedAt: now}, + EmittedColumns: append([]EmittedColumn(nil), compiled.EmittedColumns...), + Materializations: append([]Materialization(nil), materializations...), + Status: RevisionReady, CreatedBy: actor, CreatedAt: now, ReadyAt: &now, + }) +} + +func datasetMetadata(generation, schemaDigest string, materializations []Materialization) DatasetMetadata { + outputs := make([]DatasetOutput, 0, len(materializations)) + for _, materialization := range materializations { + outputs = append(outputs, DatasetOutput{ + Name: materialization.Output, + State: string(RevisionReady), Queryable: true, + Selector: materialization.Selector, + Columns: append([]publication.PhysicalColumn(nil), materialization.Columns...), + }) + } + return DatasetMetadata{Generation: generation, SchemaDigest: schemaDigest, Outputs: outputs} +} + +func (s *Service) InsertInteractiveFailedRevisionV2(ctx context.Context, owner *Explorer, config []byte, configDigest, sourceGeneration, actor string, diagnostics []Diagnostic) (*Revision, error) { + if owner == nil || owner.ManagementMode != ManagementInteractive { + return nil, fmt.Errorf("Explorer is not interactive") + } + id, err := NewInteractiveRevisionID() + if err != nil { + return nil, err + } + now := s.now() + return s.store.InsertRevision(ctx, Revision{ID: id, Project: owner.Project, ExplorerID: owner.ExplorerID, Config: append([]byte(nil), config...), ConfigDigest: configDigest, SourceGeneration: sourceGeneration, Diagnostics: append([]Diagnostic(nil), diagnostics...), Status: RevisionFailed, CreatedBy: actor, CreatedAt: now, FailedAt: &now}) +} diff --git a/internal/explorer/store.go b/internal/explorer/store.go new file mode 100644 index 00000000..1d395dab --- /dev/null +++ b/internal/explorer/store.go @@ -0,0 +1,38 @@ +package explorer + +import ( + "context" + "errors" +) + +var ( + ErrNotFound = errors.New("explorer not found") + ErrDraftConflict = errors.New("explorer draft conflict") + ErrImmutableRevision = errors.New("explorer revision content is immutable") + ErrStaleCatalog = errors.New("stale Explorer authoring catalog") + ErrIncompleteCatalog = errors.New("Explorer catalog discovery is incomplete") +) + +// Store deliberately exposes only lifecycle mutations for revisions. An +// adapter must never replace definition, recipe, digests, source generation, +// or frozen materialization mappings after InsertRevision succeeds. +type Store interface { + ListConfigs(context.Context, string) ([]RepositoryConfig, error) + GetConfig(context.Context, string, string) (*RepositoryConfig, error) + SaveConfig(context.Context, RepositoryConfig) (*RepositoryConfig, error) + GetRepositoryConfig(context.Context, string) (*RepositoryConfig, error) + SaveRepositoryConfig(context.Context, RepositoryConfig) (*RepositoryConfig, error) + List(context.Context, string) ([]Explorer, error) + Get(context.Context, string, string) (*Explorer, error) + CreateInteractive(context.Context, Explorer) (*Explorer, error) + CreateRepository(context.Context, Explorer) (*Explorer, error) + // expectedDigest is optional so callers can perform a version-only compare; + // when supplied, adapters must include it in the CAS predicate. + SaveDraft(context.Context, Explorer, int64, ...string) (*Explorer, error) + InsertRevision(context.Context, Revision) (*Revision, error) + GetRevision(context.Context, string) (*Revision, error) + TransitionRevision(context.Context, string, RevisionStatus, []Diagnostic) (*Revision, error) + ActivateInteractive(context.Context, string, string, string) error + ActivateRepository(context.Context, string, string) error + ActivateRepositoryGeneration(context.Context, string, string, string) error +} diff --git a/internal/explorer/types.go b/internal/explorer/types.go new file mode 100644 index 00000000..5d7d218b --- /dev/null +++ b/internal/explorer/types.go @@ -0,0 +1,159 @@ +package explorer + +import ( + "encoding/json" + "time" + + "github.com/calypr/loom/internal/dataframe/publication" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataset" +) + +// RepositoryConfig is the V2 repository-owned Explorer contract frozen at +// successful deployment. It is intentionally separate from the retired V1 +// authoring aggregate: the repository packet carries the executable baseline; +// live schema/readiness and publication metadata are stored alongside it. +type RepositoryConfig struct { + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + Management ManagementMode `json:"management"` + Config json.RawMessage `json:"config"` + ConfigDigest string `json:"configDigest,omitempty"` + SourceGeneration string `json:"sourceGeneration"` + SourceCommit string `json:"sourceCommit"` + ExecutionID string `json:"executionId"` + ActiveRevisionID string `json:"activeRevisionId,omitempty"` + DraftVersion int64 `json:"draftVersion,omitempty"` + Materializations []Materialization `json:"materializations"` + Dataset DatasetMetadata `json:"dataset"` + Publication PublicationMetadata `json:"publication"` + Diagnostics []Diagnostic `json:"diagnostics,omitempty"` + UpdatedAt time.Time `json:"updatedAt"` +} + +type ManagementMode string + +const ( + ManagementRepository ManagementMode = "REPOSITORY" + ManagementInteractive ManagementMode = "INTERACTIVE" +) + +type RevisionStatus string + +const ( + RevisionPending RevisionStatus = "PENDING" + RevisionMaterializing RevisionStatus = "MATERIALIZING" + RevisionReady RevisionStatus = "READY" + RevisionActive RevisionStatus = "ACTIVE" + RevisionSuperseded RevisionStatus = "SUPERSEDED" + RevisionFailed RevisionStatus = "FAILED" +) + +type Diagnostic struct { + Severity string `json:"severity"` + Code string `json:"code"` + FieldPath string `json:"fieldPath,omitempty"` + Message string `json:"message"` + Retryable bool `json:"retryable,omitempty"` + RequestID string `json:"requestId,omitempty"` +} + +// DatasetMetadata is the live, server-derived shape of a published recipe. +// It is deliberately separate from ConfigV2: physical columns and readiness +// are properties of a materialized generation, not presentation authored by a +// repository or Builder user. +type DatasetMetadata struct { + Generation string `json:"generation,omitempty"` + SchemaDigest string `json:"schemaDigest,omitempty"` + Outputs []DatasetOutput `json:"outputs"` +} + +type DatasetOutput struct { + Name string `json:"name"` + State string `json:"state"` + Queryable bool `json:"queryable"` + Selector *dataset.DataframeSelector `json:"selector,omitempty"` + Columns []publication.PhysicalColumn `json:"columns,omitempty"` +} + +type PublicationMetadata struct { + State string `json:"state"` + Generation string `json:"generation,omitempty"` + ExecutionID string `json:"executionId,omitempty"` + RevisionID string `json:"revisionId,omitempty"` + UpdatedAt time.Time `json:"updatedAt,omitempty"` +} + +type Explorer struct { + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + Title string `json:"title"` + ManagementMode ManagementMode `json:"managementMode"` + // DraftConfig is the lossless, canonical ExplorerConfigV2 packet used by + // the Builder. + DraftConfig json.RawMessage `json:"draftConfig,omitempty"` + DraftVersion int64 `json:"draftVersion"` + DraftDigest string `json:"draftDigest"` + ActiveRevisionID string `json:"activeRevisionId,omitempty"` + ActiveConfig json.RawMessage `json:"activeConfig,omitempty"` + RecipeDigest string `json:"recipeDigest,omitempty"` + ResolvedSchemaDigest string `json:"resolvedSchemaDigest,omitempty"` + SourceGeneration string `json:"sourceGeneration,omitempty"` + EmittedColumns []EmittedColumn `json:"emittedColumns,omitempty"` + Materializations []Materialization `json:"materializations,omitempty"` + Dataset DatasetMetadata `json:"dataset,omitempty"` + Publication PublicationMetadata `json:"publication,omitempty"` + Diagnostics []Diagnostic `json:"diagnostics,omitempty"` + UpdatedBy string `json:"updatedBy,omitempty"` + UpdatedAt time.Time `json:"updatedAt"` +} +type Materialization struct { + OutputID string `json:"outputId"` + Output string `json:"output"` + MaterializationID string `json:"materializationId"` + Selector *dataset.DataframeSelector `json:"selector,omitempty"` + Columns []publication.PhysicalColumn `json:"columns"` +} + +// WithDataframeSelectors projects the immutable executable recipe identity +// onto server-derived publication metadata. This also upgrades lifecycle +// records written before selectors were persisted without mutating the +// authored ExplorerConfigV2 packet or immutable revision. +func WithDataframeSelectors(bundle recipe.Bundle, materializations []Materialization, metadata DatasetMetadata) ([]Materialization, DatasetMetadata) { + materializations = append([]Materialization(nil), materializations...) + metadata.Outputs = append([]DatasetOutput(nil), metadata.Outputs...) + for index := range materializations { + selector := dataset.DataframeSelector{Recipe: bundle.Name, TranslationVersion: bundle.TranslationVersion, Output: materializations[index].Output} + materializations[index].Selector = &selector + } + for index := range metadata.Outputs { + selector := dataset.DataframeSelector{Recipe: bundle.Name, TranslationVersion: bundle.TranslationVersion, Output: metadata.Outputs[index].Name} + metadata.Outputs[index].Selector = &selector + } + return materializations, metadata +} + +type Revision struct { + ID string `json:"id"` + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + // Config is the exact immutable ExplorerConfigV2 packet for this revision. + Config json.RawMessage `json:"config,omitempty"` + ConfigDigest string `json:"configDigest,omitempty"` + Recipe recipe.Bundle `json:"canonicalRecipe"` + RecipeDigest string `json:"recipeDigest"` + ResolvedSchemaDigest string `json:"resolvedSchemaDigest"` + SourceGeneration string `json:"sourceGeneration"` + SourceCommit string `json:"sourceCommit,omitempty"` + Materializations []Materialization `json:"materializations"` + EmittedColumns []EmittedColumn `json:"emittedColumns"` + Dataset DatasetMetadata `json:"dataset,omitempty"` + Publication PublicationMetadata `json:"publication,omitempty"` + Diagnostics []Diagnostic `json:"diagnostics"` + Status RevisionStatus `json:"status"` + CreatedBy string `json:"createdBy,omitempty"` + CreatedAt time.Time `json:"createdAt"` + ReadyAt *time.Time `json:"readyAt,omitempty"` + ActivatedAt *time.Time `json:"activatedAt,omitempty"` + FailedAt *time.Time `json:"failedAt,omitempty"` +} diff --git a/internal/explorer/v2_lifecycle_test.go b/internal/explorer/v2_lifecycle_test.go new file mode 100644 index 00000000..a031e517 --- /dev/null +++ b/internal/explorer/v2_lifecycle_test.go @@ -0,0 +1,46 @@ +package explorer + +import ( + "context" + "testing" +) + +func TestV2DraftRoundTripAndDigestCAS(t *testing.T) { + service, err := NewService(NewMemoryStore()) + if err != nil { + t.Fatal(err) + } + raw := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"my-explorer","title":"My Explorer","description":"presentation survives","management":"interactive"},"recipe":{"recipeSchemaVersion":1,"name":"explorer-my-explorer","translationVersion":"interactive","outputs":[{"name":"DocumentReference","rootResourceType":"DocumentReference","rowGrain":"document_reference","fields":[{"name":"id","fieldRef":"DocumentReference.id","expr":{"select":"root.id"}}]}]},"views":[{"id":"main","title":"Main","output":"DocumentReference","rowLabel":"id","table":{"columns":[{"column":"id","label":"Identifier","visible":true}]},"filters":[{"column":"id","label":"Identifier"}],"charts":[{"column":"id","type":"TABLE","title":"Identifiers"}],"fixedFilters":{"status":["active"]},"actions":[{"type":"download","title":"Download","fileName":"records.csv"}]}],"sharedFilters":{"main":[{"output":"DocumentReference","column":"id"}]},"fileActions":{"extensions":{"csv":["id"]},"actions":{"download":"csv"}}}`) + created, err := service.CreateInteractiveV2(context.Background(), "project-a", "my-explorer", raw, "author") + if err != nil { + t.Fatal(err) + } + if string(created.DraftConfig) == string(raw) { + t.Log("input was already canonical") + } + if created.DraftDigest == "" || created.DraftVersion != 1 { + t.Fatalf("draft metadata = %#v", created) + } + loaded, err := service.Get(context.Background(), "project-a", "my-explorer") + if err != nil { + t.Fatal(err) + } + if string(loaded.DraftConfig) != string(created.DraftConfig) { + t.Fatalf("draft packet changed on round trip: %s != %s", loaded.DraftConfig, created.DraftConfig) + } + updatedRaw := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"my-explorer","title":"Updated","description":"presentation survives","management":"interactive"},"recipe":{"recipeSchemaVersion":1,"name":"explorer-my-explorer","translationVersion":"interactive","outputs":[{"name":"DocumentReference","rootResourceType":"DocumentReference","rowGrain":"document_reference","fields":[{"name":"id","fieldRef":"DocumentReference.id","expr":{"select":"root.id"}}]}]},"views":[{"id":"main","title":"Main","output":"DocumentReference","rowLabel":"id","table":{"columns":[{"column":"id","label":"Identifier","visible":true}]}}],"sharedFilters":{"main":[{"output":"DocumentReference","column":"id"}]}}`) + _, _, _, nextDigest, err := CanonicalConfigV2(updatedRaw, "project-a", "my-explorer", "interactive") + if err != nil { + t.Fatal(err) + } + updated, err := service.SaveInteractiveDraftV2(context.Background(), "project-a", "my-explorer", updatedRaw, 1, created.DraftDigest, "author") + if err != nil { + t.Fatal(err) + } + if updated.DraftVersion != 2 || updated.DraftDigest != nextDigest { + t.Fatalf("updated metadata = %#v", updated) + } + if _, err := service.SaveInteractiveDraftV2(context.Background(), "project-a", "my-explorer", raw, 1, created.DraftDigest, "stale"); err != ErrDraftConflict { + t.Fatalf("stale digest/version save error = %v, want ErrDraftConflict", err) + } +} diff --git a/internal/server/config_test.go b/internal/server/config_test.go index 9b38afb7..ab4dce57 100644 --- a/internal/server/config_test.go +++ b/internal/server/config_test.go @@ -127,13 +127,11 @@ func TestRequiredDataframeSelectorsAndSnapshotRetentionFromEnvironment(t *testin t.Setenv("LOOM_SNAPSHOT_DIRECTORY", t.TempDir()) t.Setenv("LOOM_PUBLICATION_WORKER_LEASE", "90s") t.Setenv("LOOM_PUBLICATION_MAX_ATTEMPTS", "5") - t.Setenv("LOOM_DEFAULT_RECIPE", "core") - t.Setenv("LOOM_DEFAULT_TRANSLATION_VERSION", "v1") cfg, err := LoadConfig("") if err != nil { t.Fatal(err) } - if len(cfg.Server.RequiredDataframeSelectors) != 1 || cfg.Server.RequiredDataframeSelectors[0].Output != "Patient" || cfg.Server.SnapshotRetention != 48*time.Hour || cfg.Server.PublicationWorkerLease != 90*time.Second || cfg.Server.PublicationMaxAttempts != 5 || cfg.Server.DefaultRecipe != "core" || cfg.Server.DefaultTranslationVersion != "v1" { + if len(cfg.Server.RequiredDataframeSelectors) != 1 || cfg.Server.RequiredDataframeSelectors[0].Output != "Patient" || cfg.Server.SnapshotRetention != 48*time.Hour || cfg.Server.PublicationWorkerLease != 90*time.Second || cfg.Server.PublicationMaxAttempts != 5 { t.Fatalf("environment config = %#v", cfg.Server) } if err := cfg.Validate(); err == nil || !strings.Contains(err.Error(), "dataframer.recipe") { diff --git a/internal/server/dataframe_contract.go b/internal/server/dataframe_contract.go deleted file mode 100644 index 377209ca..00000000 --- a/internal/server/dataframe_contract.go +++ /dev/null @@ -1,107 +0,0 @@ -package server - -import ( - "context" - "errors" - "fmt" - "strings" - "sync" - "time" - - arangostore "github.com/calypr/loom/internal/store/arango" -) - -const dataframeContractsCollection = "loom_dataframe_contracts" - -var errNoDataframeContract = errors.New("no promoted dataframe contract") - -type promotedDataframeContract struct { - Recipe string `json:"recipe"` - TranslationVersion string `json:"translationVersion"` - PromotedAt time.Time `json:"promotedAt"` -} - -type dataframeContractState struct { - mu sync.RWMutex - contract promotedDataframeContract -} - -func (s *dataframeContractState) Set(contract promotedDataframeContract) { - s.mu.Lock() - s.contract = contract - s.mu.Unlock() -} - -func (s *dataframeContractState) Current() (string, string) { - s.mu.RLock() - defer s.mu.RUnlock() - return s.contract.Recipe, s.contract.TranslationVersion -} - -type dataframeContractStore struct{ query releaseQueryClient } - -func dataframeContractBootstrapSpec() arangostore.BootstrapSpec { - return arangostore.BootstrapSpec{Collections: []arangostore.CollectionSpec{{Name: dataframeContractsCollection}}} -} - -func (s dataframeContractStore) Load(ctx context.Context) (promotedDataframeContract, error) { - if s.query == nil { - return promotedDataframeContract{}, fmt.Errorf("dataframe contract store is unavailable") - } - var result *promotedDataframeContract - err := s.query.QueryRows(ctx, `LET contract = DOCUMENT(@@collection, "default") FILTER contract != null RETURN contract`, 1, map[string]interface{}{"@collection": dataframeContractsCollection}, func(row map[string]any) error { - contract := promotedDataframeContract{} - contract.Recipe, _ = row["recipe"].(string) - contract.TranslationVersion, _ = row["translationVersion"].(string) - switch value := row["promotedAt"].(type) { - case time.Time: - contract.PromotedAt = value - case string: - parsed, parseErr := time.Parse(time.RFC3339Nano, value) - if parseErr != nil { - return parseErr - } - contract.PromotedAt = parsed - } - if strings.TrimSpace(contract.Recipe) == "" || strings.TrimSpace(contract.TranslationVersion) == "" { - return fmt.Errorf("stored dataframe contract is invalid") - } - result = &contract - return nil - }) - if err != nil { - return promotedDataframeContract{}, err - } - if result == nil { - return promotedDataframeContract{}, errNoDataframeContract - } - return *result, nil -} - -func (s dataframeContractStore) Promote(ctx context.Context, recipe, version string) (promotedDataframeContract, error) { - recipe, version = strings.TrimSpace(recipe), strings.TrimSpace(version) - if s.query == nil || recipe == "" || version == "" { - return promotedDataframeContract{}, fmt.Errorf("recipe and translation version are required") - } - candidate := promotedDataframeContract{Recipe: recipe, TranslationVersion: version, PromotedAt: time.Now().UTC()} - var result *promotedDataframeContract - err := s.query.QueryRows(ctx, `UPSERT {_key: "default"} -INSERT {_key: "default", recipe: @recipe, translationVersion: @version, promotedAt: @promotedAt} -UPDATE {recipe: @recipe, translationVersion: @version, promotedAt: @promotedAt} -IN @@collection -RETURN NEW`, 1, map[string]interface{}{ - "@collection": dataframeContractsCollection, "recipe": recipe, - "version": version, "promotedAt": candidate.PromotedAt, - }, func(map[string]any) error { - copy := candidate - result = © - return nil - }) - if err != nil { - return promotedDataframeContract{}, err - } - if result == nil { - return promotedDataframeContract{}, fmt.Errorf("promote dataframe contract returned no result") - } - return *result, nil -} diff --git a/internal/server/dataframe_contract_test.go b/internal/server/dataframe_contract_test.go deleted file mode 100644 index b5102382..00000000 --- a/internal/server/dataframe_contract_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package server - -import ( - "context" - "testing" - "time" -) - -func TestDataframeContractStoreLoadsAndPromotesExactVersion(t *testing.T) { - promotedAt := time.Date(2026, 8, 6, 12, 0, 0, 0, time.UTC) - query := &releaseQueryFixture{row: map[string]any{"recipe": "core", "translationVersion": "v1", "promotedAt": promotedAt.Format(time.RFC3339Nano)}} - store := dataframeContractStore{query: query} - loaded, err := store.Load(context.Background()) - if err != nil { - t.Fatal(err) - } - if loaded.Recipe != "core" || loaded.TranslationVersion != "v1" || !loaded.PromotedAt.Equal(promotedAt) { - t.Fatalf("loaded contract = %#v", loaded) - } - query.row = map[string]any{} - promoted, err := store.Promote(context.Background(), "core", "v2") - if err != nil { - t.Fatal(err) - } - if promoted.Recipe != "core" || promoted.TranslationVersion != "v2" || query.binds["recipe"] != "core" || query.binds["version"] != "v2" { - t.Fatalf("promoted contract = %#v binds=%#v", promoted, query.binds) - } - state := &dataframeContractState{} - state.Set(promoted) - if recipe, version := state.Current(); recipe != "core" || version != "v2" { - t.Fatalf("current contract = %s@%s", recipe, version) - } -} diff --git a/internal/server/explorer_config_route.go b/internal/server/explorer_config_route.go new file mode 100644 index 00000000..bc09ca17 --- /dev/null +++ b/internal/server/explorer_config_route.go @@ -0,0 +1,134 @@ +package server + +import ( + "context" + "fmt" + "net/http" + "strings" + "time" + + graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataset" + "github.com/calypr/loom/internal/explorer" + "github.com/gofiber/fiber/v3" +) + +// RegisterExplorerConfigV2Route is the sole repository Explorer deployment +// surface. The body is the portable, executable baseline ExplorerConfigV2 +// document; generation and source commit are deployment context, while live +// schema/readiness and publication metadata are derived by Loom. +type explorerConfigReadAuthorizer func(context.Context, *authscope.Principal, string) error + +func RegisterExplorerConfigV2Route(app *fiber.App, authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, explorers *explorer.Service, materialize graphresolver.ExplorerBundleMaterializer, lifecycle ...ExplorerV2LifecycleConfig) { + if app == nil || authorizer == nil || authorizeRead == nil || explorers == nil || materialize == nil { + return + } + app.Post("/api/v1/projects/:project/generations/:generation/explorer-config", func(c fiber.Ctx) error { + project, generation := strings.TrimSpace(c.Params("project")), strings.TrimSpace(c.Params("generation")) + if project == "" || generation == "" { + return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "project and generation are required"}) + } + // The dataset key (for example HTAN_INT-BForePC) is not an Arborist + // resource path. Reuse the scope supplied during the deferred upload. + authResourcePath := authscope.NormalizeAuthResourcePath(strings.TrimSpace(c.Query("auth_resource_path"))) + principal, _ := c.Locals("principal").(*authscope.Principal) + if err := authorizer.AuthorizeWrite(c.Context(), principal, project, authResourcePath); err != nil { + return c.Status(http.StatusForbidden).JSON(fiber.Map{"error": "forbidden"}) + } + _, bundle, err := explorer.DecodeConfigV2(c.Body(), project) + if err != nil { + return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()}) + } + // Version the execution by the checked-out repository commit while + // retaining a data-only recipe body. A project-specific bundle name + // prevents two repository configs from sharing a publication namespace. + commit := strings.TrimSpace(c.Get("X-Loom-Source-Commit")) + if commit == "" { + return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "X-Loom-Source-Commit is required"}) + } + bundle.Name = "explorer_" + project + "_default" + bundle.TranslationVersion = "repository-" + commit + if err := bundle.Validate(); err != nil { + return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"error": fmt.Sprintf("invalid recipe: %v", err)}) + } + _, _, canonicalConfig, configDigest, err := explorer.CanonicalConfigV2(c.Body(), project, "default", "repository") + if err != nil { + return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()}) + } + execution, err := materialize(c.Context(), bundle, recipe.RuntimeBindings{Project: project, DatasetGeneration: generation}) + if err != nil { + return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"error": fmt.Sprintf("materialize ExplorerConfigV2: %v", err)}) + } + if err := verifyQueryableOutputs(bundle, execution); err != nil { + return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error(), "executionId": execution.ID}) + } + materializations := explorerMaterializations(bundle, execution) + dataset := datasetMetadataFromExecution(bundle, generation, execution.ResolvedSchemaDigest, execution) + publication := explorer.PublicationMetadata{State: string(explorer.RevisionReady), Generation: generation, ExecutionID: execution.ID, UpdatedAt: time.Now().UTC()} + owner, revision, err := explorers.UpsertRepositoryV2(c.Context(), canonicalConfig, commit, generation, "", explorer.Compilation{Bundle: bundle, RecipeDigest: mustBundleDigest(bundle)}, execution.ResolvedSchemaDigest, materializations, dataset, publication) + if err != nil { + return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": fmt.Sprintf("persist Explorer lifecycle V2: %v", err)}) + } + if owner.ManagementMode != explorer.ManagementRepository { + return c.Status(http.StatusConflict).JSON(fiber.Map{"error": "default Explorer has invalid management mode"}) + } + if err := explorers.ActivateRepositoryGeneration(c.Context(), project, generation, revision.ID); err != nil { + return c.Status(http.StatusConflict).JSON(fiber.Map{"error": fmt.Sprintf("activate ExplorerConfigV2: %v", err), "executionId": execution.ID}) + } + publication.State = string(explorer.RevisionActive) + publication.RevisionID = revision.ID + publication.UpdatedAt = time.Now().UTC() + if _, err := explorers.SaveRepositoryConfig(c.Context(), explorer.RepositoryConfig{Project: project, Config: canonicalConfig, ConfigDigest: configDigest, ActiveRevisionID: revision.ID, DraftVersion: owner.DraftVersion, SourceGeneration: generation, SourceCommit: commit, ExecutionID: execution.ID, Materializations: materializations, Dataset: dataset, Publication: publication}); err != nil { + return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": fmt.Sprintf("persist ExplorerConfigV2: %v", err)}) + } + return c.Status(http.StatusOK).JSON(fiber.Map{"project": project, "generation": generation, "explorerId": "default", "executionId": execution.ID, "recipe": bundle.Name, "translationVersion": bundle.TranslationVersion, "activated": true}) + }) + app.Get("/api/v1/projects/:project/explorer-config", func(c fiber.Ctx) error { + project := strings.TrimSpace(c.Params("project")) + principal, _ := c.Locals("principal").(*authscope.Principal) + if err := authorizeRead(c.Context(), principal, project); err != nil { + return c.Status(http.StatusForbidden).JSON(fiber.Map{"error": "forbidden"}) + } + value, err := explorers.RepositoryConfig(c.Context(), project) + if err == explorer.ErrNotFound { + return c.Status(http.StatusNotFound).JSON(fiber.Map{"error": "repository ExplorerConfigV2 not found"}) + } + if err != nil { + return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) + } + return c.JSON(value) + }) + if len(lifecycle) == 0 { + lifecycle = []ExplorerV2LifecycleConfig{{Materialize: materialize}} + } + RegisterExplorerLifecycleRoutes(app, authorizer, authorizeRead, explorers, lifecycle[0]) +} + +func explorerMaterializations(bundle recipe.Bundle, execution graphresolver.RecipeExecution) []explorer.Materialization { + out := make([]explorer.Materialization, 0, len(execution.Outputs)) + for _, output := range execution.Outputs { + out = append(out, explorer.Materialization{OutputID: output.Name, Output: output.Name, MaterializationID: execution.ID, Selector: explorerOutputSelector(bundle, output.Name), Columns: output.Columns}) + } + return out +} + +func datasetMetadataFromExecution(bundle recipe.Bundle, generation, schemaDigest string, execution graphresolver.RecipeExecution) explorer.DatasetMetadata { + outputs := make([]explorer.DatasetOutput, 0, len(execution.Outputs)) + for _, output := range execution.Outputs { + state := strings.ToUpper(output.State) + outputs = append(outputs, explorer.DatasetOutput{ + Name: output.Name, State: state, + Queryable: state == "PUBLISHED" || state == "READY" || state == "ACTIVE", + Selector: explorerOutputSelector(bundle, output.Name), + Columns: output.Columns, + }) + } + return explorer.DatasetMetadata{Generation: generation, SchemaDigest: schemaDigest, Outputs: outputs} +} + +func explorerOutputSelector(bundle recipe.Bundle, output string) *dataset.DataframeSelector { + selector := dataset.DataframeSelector{Recipe: bundle.Name, TranslationVersion: bundle.TranslationVersion, Output: output} + return &selector +} diff --git a/internal/server/explorer_config_route_test.go b/internal/server/explorer_config_route_test.go new file mode 100644 index 00000000..a7e2f65d --- /dev/null +++ b/internal/server/explorer_config_route_test.go @@ -0,0 +1,73 @@ +package server + +import ( + "context" + "io" + "net/http" + "net/http/httptest" + "strings" + "testing" + + graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/explorer" + "github.com/gofiber/fiber/v3" +) + +func TestRepositoryDeploymentPersistsExecutableDataframeSelectors(t *testing.T) { + service, err := explorer.NewService(explorer.NewMemoryStore()) + if err != nil { + t.Fatal(err) + } + materialize := func(_ context.Context, bundle recipe.Bundle, _ recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { + if bundle.Name != "explorer_project-a_default" || bundle.TranslationVersion != "repository-commit-a" { + t.Fatalf("materialized identity = %s/%s", bundle.Name, bundle.TranslationVersion) + } + return graphresolver.RecipeExecution{ID: "execution-a", SourceGeneration: "generation-a", State: "PUBLISHED", Outputs: []graphresolver.RecipeExecutionOutput{{Name: "DocumentReference", State: "PUBLISHED"}}}, nil + } + app := fiber.New() + RegisterExplorerConfigV2Route(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, materialize) + + request := requestJSONWithHeaders(t, app, http.MethodPost, "/api/v1/projects/project-a/generations/generation-a/explorer-config", string(baselineExplorerConfigV2("project-a", "Default")), map[string]string{"X-Loom-Source-Commit": "commit-a"}) + if request.StatusCode != http.StatusOK { + t.Fatalf("deploy status=%d body=%s", request.StatusCode, request.Body) + } + repeated := requestJSONWithHeaders(t, app, http.MethodPost, "/api/v1/projects/project-a/generations/generation-a/explorer-config", string(baselineExplorerConfigV2("project-a", "Default")), map[string]string{"X-Loom-Source-Commit": "commit-a"}) + if repeated.StatusCode != http.StatusOK { + t.Fatalf("repeated deploy status=%d body=%s", repeated.StatusCode, repeated.Body) + } + state, err := getExplorerV2State(context.Background(), service, "project-a", "default") + if err != nil { + t.Fatal(err) + } + if len(state.Dataset.Outputs) != 1 || state.Dataset.Outputs[0].Selector == nil { + t.Fatalf("dataset selector missing: %#v", state.Dataset.Outputs) + } + selector := state.Dataset.Outputs[0].Selector + if selector.Recipe != "explorer_project-a_default" || selector.TranslationVersion != "repository-commit-a" || selector.Output != "DocumentReference" { + t.Fatalf("dataset selector = %#v", selector) + } + if len(state.Materializations) != 1 || state.Materializations[0].Selector == nil || *state.Materializations[0].Selector != *selector { + t.Fatalf("materialization selector = %#v", state.Materializations) + } +} + +func requestJSONWithHeaders(t *testing.T, app *fiber.App, method, path, body string, headers map[string]string) testHTTPResponse { + t.Helper() + request := httptest.NewRequest(method, path, strings.NewReader(body)) + request.Header.Set("Content-Type", "application/json") + for name, value := range headers { + request.Header.Set(name, value) + } + response, err := app.Test(request) + if err != nil { + t.Fatal(err) + } + defer response.Body.Close() + raw, err := io.ReadAll(response.Body) + if err != nil { + t.Fatal(err) + } + return testHTTPResponse{StatusCode: response.StatusCode, Body: string(raw)} +} diff --git a/internal/server/explorer_publication.go b/internal/server/explorer_publication.go new file mode 100644 index 00000000..9e55a340 --- /dev/null +++ b/internal/server/explorer_publication.go @@ -0,0 +1,42 @@ +package server + +import ( + "context" + "fmt" + "log/slog" + + graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" + "github.com/calypr/loom/internal/dataframe/publication" + materializationarango "github.com/calypr/loom/internal/dataframe/publication/arango" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataframe/recipe/engine" +) + +func explorerBundleMaterializer(recipeEngine *engine.Engine, target publication.Target, registry *materializationarango.Registry, degradation error, logger *slog.Logger, batchRows, batchBytes int) graphresolver.ExplorerBundleMaterializer { + return func(ctx context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { + if target == nil { + return graphresolver.RecipeExecution{}, fmt.Errorf("Explorer publication is unavailable: %w", degradation) + } + bindings.IncludeAuthResourcePath = true + var identity publication.BundleIdentity + _, err := recipeEngine.MaterializeBundle(ctx, bundle, bindings, func(run context.Context, full engine.Resolved) error { + var publishErr error + identity, publishErr = publishResolvedRecipe(run, recipeEngine, target, bundle.Name, bindings, full, batchRows, batchBytes) + return publishErr + }) + if err != nil { + return graphresolver.RecipeExecution{}, err + } + published, err := registry.FindExecutionByKey(ctx, identity.Key()) + if err != nil { + return graphresolver.RecipeExecution{}, fmt.Errorf("load Explorer publication: %w", err) + } + outputs := make([]graphresolver.RecipeExecutionOutput, 0, len(published.Outputs)) + for _, output := range published.Outputs { + count := int(output.RowCount) + outputs = append(outputs, graphresolver.RecipeExecutionOutput{Name: output.Name, State: string(output.State.Canonical()), RowCount: &count, Columns: append([]publication.PhysicalColumn(nil), output.Columns...)}) + } + logger.Info("Explorer materialization complete", "project", bindings.Project, "execution", published.ID) + return graphresolver.RecipeExecution{ID: published.ID, Name: bundle.Name, RecipeDigest: published.RecipeDigest, ResolvedSchemaDigest: published.SchemaDigest, SourceGeneration: published.DatasetGeneration, State: string(published.State.Canonical()), Outputs: outputs}, nil + } +} diff --git a/internal/server/explorer_v2_engine.go b/internal/server/explorer_v2_engine.go new file mode 100644 index 00000000..f7310c20 --- /dev/null +++ b/internal/server/explorer_v2_engine.go @@ -0,0 +1,127 @@ +package server + +import ( + "context" + "fmt" + "strings" + + "github.com/calypr/loom/internal/dataframe/compiler/lower" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataframe/recipe/engine" + "github.com/calypr/loom/internal/explorer" +) + +type explorerV2CatalogReader func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) + +func explorerV2Compiler(recipeEngine *engine.Engine, catalogReader explorerV2CatalogReader) ExplorerV2Compiler { + return func(ctx context.Context, request ExplorerV2CompileRequest) (ExplorerV2CompileResult, error) { + cfg, bundle, canonical, digest, err := explorer.CanonicalConfigV2(request.Config, request.Project, request.ExplorerID, "interactive") + if err != nil { + return ExplorerV2CompileResult{}, err + } + var sourceGeneration string + // Every request that reaches the production recipe engine must resolve + // against the active dataset generation. An absent catalog capability is + // a wiring failure, never permission to fall back to the null-generation + // namespace. + if catalogReader != nil { + snapshot, err := catalogReader(ctx, request.Project, request.ExplorerID, "") + if err != nil { + return ExplorerV2CompileResult{}, err + } + if strings.TrimSpace(snapshot.Generation) == "" { + return ExplorerV2CompileResult{}, fmt.Errorf("active dataset generation is unavailable") + } + sourceGeneration = snapshot.Generation + if request.SnapshotToken != "" || len(request.SelectedCandidateIDsByNode) > 0 { + if err := snapshot.ValidateToken(request.SnapshotToken); err != nil { + return ExplorerV2CompileResult{}, err + } + } + for nodeID, candidateIDs := range request.SelectedCandidateIDsByNode { + lookupNodeID := nodeID + if nodeID == "root" && len(bundle.Outputs) > 0 { + lookupNodeID = explorer.OpaqueID("n_", bundle.Outputs[0].RootResourceType) + } + if _, ok := catalogNodeForREST(snapshot.Catalog, lookupNodeID); !ok { + return ExplorerV2CompileResult{}, fmt.Errorf("unresolved catalog node %q", nodeID) + } + for _, candidateID := range candidateIDs { + selection, ok := catalogSelectionForREST(snapshot.Catalog, candidateID) + if !ok || selection.NodeID != lookupNodeID { + return ExplorerV2CompileResult{}, fmt.Errorf("unresolved catalog candidate %q for node %q", candidateID, nodeID) + } + } + } + } else { + return ExplorerV2CompileResult{}, fmt.Errorf("catalog discovery is not configured") + } + if recipeEngine == nil { + return ExplorerV2CompileResult{Config: canonical, Bundle: bundle, RecipeDigest: digest, SourceGeneration: sourceGeneration}, nil + } + resolved, err := recipeEngine.ResolveBundle(ctx, bundle, recipe.RuntimeBindings{Project: request.Project, DatasetGeneration: sourceGeneration}) + if err != nil { + return ExplorerV2CompileResult{}, err + } + emitted := make([]explorer.EmittedColumn, 0) + for _, output := range resolved.Compiled.Outputs { + for _, column := range output.OutputSchema { + if column.Internal { + continue + } + emitted = append(emitted, explorer.EmittedColumn{OutputID: output.Name, PublicColumn: column.Name, SelectionID: column.SemanticPath, LogicalType: column.Kind, Filterable: true, Chartable: true}) + } + } + if err := synchronizeExplorerV2Views(cfg, resolved.Compiled.Outputs); err != nil { + return ExplorerV2CompileResult{}, err + } + return ExplorerV2CompileResult{Config: canonical, Bundle: bundle, RecipeDigest: resolved.StoredRecipeDigest, ResolvedSchemaDigest: resolved.ResolvedSchemaDigest, SourceGeneration: resolved.Compiled.SourceGeneration, EmittedColumns: emitted}, nil + } +} + +// The explorer package intentionally keeps Catalog's internal lookup methods +// private. These tiny adapters keep REST wiring from exposing catalog fields. +func catalogNodeForREST(c explorer.Catalog, id string) (explorer.CatalogNode, bool) { + for _, node := range c.Nodes { + if node.ID == id { + return node, true + } + } + return explorer.CatalogNode{}, false +} +func catalogSelectionForREST(c explorer.Catalog, id string) (explorer.CatalogSelection, bool) { + value, ok := c.Selections[id] + return value, ok +} + +func synchronizeExplorerV2Views(cfg explorer.ConfigV2, outputs []lower.CompiledRecipeOutput) error { + columns := map[string]map[string]bool{} + for _, output := range outputs { + columns[output.Name] = map[string]bool{} + for _, column := range output.Columns { + columns[output.Name][column] = true + } + } + for _, view := range cfg.Views { + available, ok := columns[view.Output] + if !ok { + return fmt.Errorf("view %q references unsupported output %q", view.ID, view.Output) + } + for _, column := range view.Table.Columns { + if !available[column.Column] { + return fmt.Errorf("view %q references missing output column %q", view.ID, column.Column) + } + } + for _, filter := range view.Filters { + if !available[filter.Column] { + return fmt.Errorf("view %q references missing filter column %q", view.ID, filter.Column) + } + } + for _, chart := range view.Charts { + if !available[chart.Column] { + return fmt.Errorf("view %q references missing chart column %q", view.ID, chart.Column) + } + } + } + return nil +} diff --git a/internal/server/explorer_v2_engine_test.go b/internal/server/explorer_v2_engine_test.go new file mode 100644 index 00000000..83009cae --- /dev/null +++ b/internal/server/explorer_v2_engine_test.go @@ -0,0 +1,75 @@ +package server + +import ( + "context" + "encoding/json" + "testing" + + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataframe/recipe/engine" + "github.com/calypr/loom/internal/dataframe/recipe/exec" + "github.com/calypr/loom/internal/explorer" +) + +type compilerTestRegistry struct{} + +func (compilerTestRegistry) LoadRecipe(context.Context, string) (exec.Entry, error) { + return exec.Entry{}, nil +} + +func TestExplorerV2CompilerUsesActiveGenerationWithoutSnapshotToken(t *testing.T) { + var resolvedGeneration string + recipeEngine, err := engine.New(engine.Config{ + Registry: compilerTestRegistry{}, + ResolveBundle: func(_ context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (recipe.Bundle, error) { + resolvedGeneration = bindings.DatasetGeneration + return bundle, nil + }, + QueryRows: func(context.Context, string, int, map[string]any, func(map[string]any) error) error { + return nil + }, + }) + if err != nil { + t.Fatal(err) + } + + snapshot, err := explorer.NewCatalogSnapshot("project-a", "generation-live", "scope", explorer.Catalog{}, true, false, nil) + if err != nil { + t.Fatal(err) + } + compiler := explorerV2Compiler(recipeEngine, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { + return snapshot, nil + }) + + var configV2 explorer.ConfigV2 + if err := json.Unmarshal(baselineExplorerConfigV2("project-a", "Default"), &configV2); err != nil { + t.Fatal(err) + } + configV2.Explorer.ID = "custom" + configV2.Explorer.Management = "interactive" + bundle := testV2Bundle("compiler-test") + bundle.Outputs[0].RowGrain = "file" + configV2.Recipe, err = json.Marshal(bundle) + if err != nil { + t.Fatal(err) + } + configV2.Views = []explorer.ConfigView{{ + ID: "documents", Title: "Documents", Output: "DocumentReference", + Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "id", Label: "ID", Visible: true}}}, + }} + config, err := json.Marshal(configV2) + if err != nil { + t.Fatal(err) + } + result, err := compiler(context.Background(), ExplorerV2CompileRequest{ + Project: "project-a", + ExplorerID: "custom", + Config: json.RawMessage(config), + }) + if err != nil { + t.Fatal(err) + } + if result.SourceGeneration != "generation-live" || resolvedGeneration != "generation-live" { + t.Fatalf("compiler generation = %q, resolver generation = %q; want generation-live", result.SourceGeneration, resolvedGeneration) + } +} diff --git a/internal/server/explorer_v2_lifecycle.go b/internal/server/explorer_v2_lifecycle.go new file mode 100644 index 00000000..d38ba6dc --- /dev/null +++ b/internal/server/explorer_v2_lifecycle.go @@ -0,0 +1,733 @@ +package server + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "net/http" + "sort" + "strings" + "time" + + graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/dataframe/publication" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/explorer" + "github.com/gofiber/fiber/v3" +) + +// ExplorerV2CompileRequest is the server-side authoring seam. Browser +// requests contain opaque candidate IDs only; the compiler resolves them from +// Loom's authoritative catalog. +type ExplorerV2CompileRequest struct { + Project string + ExplorerID string + Config []byte + SnapshotToken string + SelectedCandidateIDsByNode map[string][]string + Output string +} + +type ExplorerV2CompileResult struct { + Config []byte + Bundle recipe.Bundle + RecipeDigest string + ResolvedSchemaDigest string + SourceGeneration string + EmittedColumns []explorer.EmittedColumn + Diagnostics []explorer.Diagnostic +} + +type ExplorerV2Compiler func(context.Context, ExplorerV2CompileRequest) (ExplorerV2CompileResult, error) +type ExplorerV2Previewer func(context.Context, recipe.Bundle, recipe.RuntimeBindings) (map[string][]map[string]any, error) +type ExplorerV2Materializer = graphresolver.ExplorerBundleMaterializer + +// ExplorerV2LifecycleConfig contains explicit capabilities for the REST +// surface. The HTTP layer does not reach into catalog, compiler, or storage +// internals. +type ExplorerV2LifecycleConfig struct { + Compile ExplorerV2Compiler + Catalog explorerV2CatalogReader + Preview ExplorerV2Previewer + Materialize ExplorerV2Materializer +} + +type explorerV2State struct { + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + Management explorer.ManagementMode `json:"management"` + // BaselineConfig is present for the repository default. It is always the + // presentation-free recipe/schema baseline, even when the published + // repository packet also contains an ETL-authored presentation layer. + BaselineConfig json.RawMessage `json:"baselineConfig,omitempty"` + DraftConfig json.RawMessage `json:"draftConfig,omitempty"` + DraftVersion int64 `json:"draftVersion"` + DraftDigest string `json:"draftDigest"` + ActiveConfig json.RawMessage `json:"activeConfig,omitempty"` + ActiveRevisionID string `json:"activeRevisionId,omitempty"` + RecipeDigest string `json:"recipeDigest,omitempty"` + ResolvedSchemaDigest string `json:"resolvedSchemaDigest,omitempty"` + SourceGeneration string `json:"sourceGeneration,omitempty"` + EmittedColumns []explorer.EmittedColumn `json:"emittedColumns,omitempty"` + Materializations []explorer.Materialization `json:"materializations,omitempty"` + Dataset explorer.DatasetMetadata `json:"dataset,omitempty"` + Publication explorer.PublicationMetadata `json:"publication,omitempty"` + Diagnostics []explorer.Diagnostic `json:"diagnostics,omitempty"` + PublicationState string `json:"publicationState,omitempty"` + ActiveURL string `json:"activeUrl"` + UpdatedBy string `json:"updatedBy,omitempty"` + UpdatedAt time.Time `json:"updatedAt"` +} + +func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, explorers *explorer.Service, capabilities ExplorerV2LifecycleConfig) { + if app == nil || authorizer == nil || authorizeRead == nil || explorers == nil { + return + } + + app.Get("/api/v1/projects/:project/explorers", func(c fiber.Ctx) error { + project := strings.TrimSpace(c.Params("project")) + if err := authorizeRead(c.Context(), principalFromFiber(c), project); err != nil { + return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") + } + values, err := listExplorerV2States(c.Context(), explorers, project) + if err != nil { + return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error()) + } + return c.JSON(values) + }) + + app.Get("/api/v1/projects/:project/explorers/:explorerId", func(c fiber.Ctx) error { + project, id := strings.TrimSpace(c.Params("project")), strings.TrimSpace(c.Params("explorerId")) + if err := authorizeRead(c.Context(), principalFromFiber(c), project); err != nil { + return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") + } + value, err := getExplorerV2State(c.Context(), explorers, project, id) + if errors.Is(err, explorer.ErrNotFound) { + return explorerV2Error(c, http.StatusNotFound, "EXPLORER_NOT_FOUND", "Explorer not found") + } + if err != nil { + return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error()) + } + return c.JSON(value) + }) + app.Get("/api/v1/projects/:project/explorers/:explorerId/authoring/catalog", func(c fiber.Ctx) error { + project, id := strings.TrimSpace(c.Params("project")), strings.TrimSpace(c.Params("explorerId")) + if err := authorizeRead(c.Context(), principalFromFiber(c), project); err != nil { + return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") + } + if capabilities.Catalog == nil { + return explorerV2Error(c, http.StatusServiceUnavailable, "CATALOG_UNAVAILABLE", "Explorer authoring catalog is not configured") + } + snapshot, err := capabilities.Catalog(c.Context(), project, id, "") + if err != nil { + return explorerV2Error(c, http.StatusServiceUnavailable, "CATALOG_UNAVAILABLE", err.Error()) + } + nodes := make([]fiber.Map, 0, len(snapshot.Catalog.Nodes)) + for _, node := range snapshot.Catalog.Nodes { + nodes = append(nodes, fiber.Map{"nodeId": node.ID, "label": node.ResourceType}) + } + selections := make([]fiber.Map, 0, len(snapshot.Catalog.Selections)) + for _, selection := range snapshot.Catalog.Selections { + selections = append(selections, fiber.Map{ + "selectionId": selection.ID, "nodeId": selection.NodeID, "fieldRef": selection.FieldRef, + "select": selection.Select, "logicalType": selection.LogicalType, + "filterable": selection.Filterable, "chartable": selection.Chartable, + }) + } + edges := make([]fiber.Map, 0, len(snapshot.Catalog.Edges)) + for _, edge := range snapshot.Catalog.Edges { + edges = append(edges, fiber.Map{"edgeId": edge.ID, "fromNodeId": edge.FromNodeID, "toNodeId": edge.ToNodeID, "label": edge.Label}) + } + return c.JSON(fiber.Map{ + "snapshotToken": snapshot.Token, "project": snapshot.Project, "explorerId": id, + "sourceGeneration": snapshot.Generation, "authorizationScopeDigest": snapshot.AuthorizationScopeDigest, + "resolvedSchemaDigest": snapshot.ResolvedSchemaDigest, "nodes": nodes, + "selections": selections, "routeEdges": edges, + "completeness": fiber.Map{"complete": snapshot.Complete, "truncated": snapshot.Truncated, "diagnostics": snapshot.Diagnostics}, + "diagnostics": snapshot.Diagnostics, + }) + }) + + app.Post("/api/v1/projects/:project/explorers", func(c fiber.Ctx) error { + project := strings.TrimSpace(c.Params("project")) + if err := authorizeExplorerWrite(c, authorizer, project); err != nil { + return err + } + var request struct { + Name string `json:"name"` + Title string `json:"title"` + ExplorerID string `json:"explorerId"` + Source string `json:"source"` + From string `json:"from"` + Blank bool `json:"blank"` + } + if err := decodeStrict(c.Body(), &request); err != nil { + return explorerV2Error(c, http.StatusBadRequest, "MALFORMED_REQUEST", err.Error()) + } + name := strings.TrimSpace(request.Name) + if name == "" { + name = strings.TrimSpace(request.Title) + } + if name == "" { + name = strings.TrimSpace(request.ExplorerID) + } + id := explorer.StableExplorerID(name) + if id == "default" { + return explorerV2Error(c, http.StatusForbidden, "DEFAULT_READ_ONLY", "the repository default is read-only") + } + title := strings.TrimSpace(request.Title) + if title == "" { + title = name + } + var raw []byte + if request.Blank || strings.EqualFold(strings.TrimSpace(request.Source), "blank") || strings.EqualFold(strings.TrimSpace(request.From), "blank") { + raw = blankExplorerConfigV2(project, id, title) + } else { + base, err := explorers.RepositoryConfig(c.Context(), project) + if errors.Is(err, explorer.ErrNotFound) { + return explorerV2Error(c, http.StatusConflict, "REPOSITORY_CONFIG_REQUIRED", "deploy the repository default or request a blank Explorer") + } + if err != nil { + return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error()) + } + raw, err = forkRepositoryConfig(base.Config, project, id, title) + if err != nil { + return explorerV2Error(c, http.StatusUnprocessableEntity, "INVALID_REPOSITORY_CONFIG", err.Error()) + } + } + value, err := explorers.CreateInteractiveV2(c.Context(), project, id, raw, subjectFromFiber(c)) + if err != nil { + if errors.Is(err, explorer.ErrDraftConflict) { + return explorerV2Error(c, http.StatusConflict, "EXPLORER_EXISTS", "an Explorer with this name already exists") + } + return explorerV2Error(c, http.StatusUnprocessableEntity, "INVALID_EXPLORER", err.Error()) + } + state, err := getExplorerV2State(c.Context(), explorers, project, value.ExplorerID) + if err != nil { + return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error()) + } + return c.Status(http.StatusCreated).JSON(state) + }) + + app.Put("/api/v1/projects/:project/explorers/:explorerId/draft", func(c fiber.Ctx) error { + project, id := strings.TrimSpace(c.Params("project")), strings.TrimSpace(c.Params("explorerId")) + if id == "default" { + return explorerV2Error(c, http.StatusForbidden, "DEFAULT_READ_ONLY", "the repository default is read-only") + } + if err := authorizeExplorerWrite(c, authorizer, project); err != nil { + return err + } + var request struct { + Config json.RawMessage `json:"config"` + ExpectedDraftVersion *int64 `json:"expectedDraftVersion"` + ExpectedDraftDigest string `json:"expectedDraftDigest"` + } + if err := decodeStrict(c.Body(), &request); err != nil || request.ExpectedDraftVersion == nil { + if err == nil { + err = fmt.Errorf("expectedDraftVersion is required") + } + return explorerV2Error(c, http.StatusBadRequest, "MALFORMED_REQUEST", err.Error()) + } + _, _, canonical, _, err := explorer.CanonicalConfigV2(request.Config, project, id, "interactive") + if err != nil { + return explorerV2Error(c, http.StatusUnprocessableEntity, "INVALID_CONFIG", err.Error()) + } + value, err := explorers.SaveInteractiveDraftV2(c.Context(), project, id, canonical, *request.ExpectedDraftVersion, request.ExpectedDraftDigest, subjectFromFiber(c)) + if errors.Is(err, explorer.ErrDraftConflict) { + return draftConflictResponse(c, explorers, project, id) + } + if errors.Is(err, explorer.ErrNotFound) { + return explorerV2Error(c, http.StatusNotFound, "EXPLORER_NOT_FOUND", "custom Explorer not found") + } + if err != nil { + return explorerV2Error(c, http.StatusUnprocessableEntity, "DRAFT_SAVE_FAILED", err.Error()) + } + return c.JSON(stateFromExplorer(value)) + }) + + app.Post("/api/v1/projects/:project/explorers/:explorerId/authoring/compile", func(c fiber.Ctx) error { + project, id := strings.TrimSpace(c.Params("project")), strings.TrimSpace(c.Params("explorerId")) + if id == "default" { + return explorerV2Error(c, http.StatusForbidden, "DEFAULT_READ_ONLY", "the repository default is read-only") + } + if err := authorizeExplorerWrite(c, authorizer, project); err != nil { + return err + } + var request struct { + Output string `json:"output"` + Config json.RawMessage `json:"config"` + SnapshotToken string `json:"snapshotToken"` + SelectedCandidateIDsByNode map[string][]string `json:"selectedCandidateIdsByNode"` + ExpectedDraftVersion *int64 `json:"expectedDraftVersion"` + } + if err := decodeStrict(c.Body(), &request); err != nil { + return explorerV2Error(c, http.StatusBadRequest, "MALFORMED_REQUEST", err.Error()) + } + if request.ExpectedDraftVersion == nil { + return explorerV2Error(c, http.StatusBadRequest, "MALFORMED_REQUEST", "expectedDraftVersion is required") + } + if err := verifyExpectedVersion(c.Context(), explorers, project, id, request.ExpectedDraftVersion); err != nil { + return stateErrorResponse(c, err) + } + result, digest, err := compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, Config: request.Config, SnapshotToken: request.SnapshotToken, SelectedCandidateIDsByNode: request.SelectedCandidateIDsByNode, Output: request.Output}) + if err != nil { + return explorerV2Error(c, http.StatusUnprocessableEntity, "COMPILE_FAILED", err.Error()) + } + return c.JSON(fiber.Map{"project": project, "explorerId": id, "config": json.RawMessage(result.Config), "draftDigest": digest, "snapshotToken": request.SnapshotToken, "recipeDigest": result.RecipeDigest, "resolvedSchemaDigest": result.ResolvedSchemaDigest, "sourceGeneration": result.SourceGeneration, "emittedColumns": result.EmittedColumns, "diagnostics": result.Diagnostics}) + }) + + app.Post("/api/v1/projects/:project/explorers/:explorerId/preview", func(c fiber.Ctx) error { + project, id := strings.TrimSpace(c.Params("project")), strings.TrimSpace(c.Params("explorerId")) + if err := authorizeRead(c.Context(), principalFromFiber(c), project); err != nil { + return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") + } + var request struct { + Config json.RawMessage `json:"config"` + Output string `json:"output"` + Limit int `json:"limit"` + DraftDigest string `json:"draftDigest"` + } + if err := decodeStrict(c.Body(), &request); err != nil { + return explorerV2Error(c, http.StatusBadRequest, "MALFORMED_REQUEST", err.Error()) + } + if request.Limit == 0 { + request.Limit = 25 + } + if request.Limit < 1 || request.Limit > 1000 { + return explorerV2Error(c, http.StatusBadRequest, "INVALID_LIMIT", "limit must be between 1 and 1000") + } + if request.DraftDigest != "" { + if err := verifyExpectedDigest(c.Context(), explorers, project, id, request.DraftDigest); err != nil { + return stateErrorResponse(c, err) + } + } + result, digest, err := compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, Config: request.Config, Output: request.Output}) + if err != nil { + return previewFailure(c, digest, err) + } + if !bundleHasOutput(result.Bundle, request.Output) { + return previewFailure(c, digest, fmt.Errorf("unsupported output %q", request.Output)) + } + if capabilities.Preview == nil { + return previewFailure(c, digest, fmt.Errorf("preview executor is not configured")) + } + rows, err := capabilities.Preview(c.Context(), result.Bundle, recipe.RuntimeBindings{Project: project, PreviewLimit: request.Limit, DatasetGeneration: result.SourceGeneration, OutputNames: []string{request.Output}}) + if err != nil { + return previewFailure(c, digest, err) + } + selected := rows[request.Output] + return c.JSON(fiber.Map{"project": project, "explorerId": id, "output": request.Output, "columns": columnsForOutput(result, request.Output), "rows": selected, "rowCount": len(selected), "digest": digest, "diagnostics": result.Diagnostics}) + }) + + app.Post("/api/v1/projects/:project/explorers/:explorerId/publish", func(c fiber.Ctx) error { + project, id := strings.TrimSpace(c.Params("project")), strings.TrimSpace(c.Params("explorerId")) + if id == "default" { + return explorerV2Error(c, http.StatusForbidden, "DEFAULT_READ_ONLY", "the repository default is read-only") + } + if err := authorizeExplorerWrite(c, authorizer, project); err != nil { + return err + } + var request struct { + ExpectedDraftVersion *int64 `json:"expectedDraftVersion"` + ExpectedDraftDigest string `json:"expectedDraftDigest"` + } + if err := decodeStrict(c.Body(), &request); err != nil || request.ExpectedDraftVersion == nil { + if err == nil { + err = fmt.Errorf("expectedDraftVersion is required") + } + return explorerV2Error(c, http.StatusBadRequest, "MALFORMED_REQUEST", err.Error()) + } + owner, err := explorers.Get(c.Context(), project, id) + if errors.Is(err, explorer.ErrNotFound) { + return explorerV2Error(c, http.StatusNotFound, "EXPLORER_NOT_FOUND", "custom Explorer not found") + } + if err != nil { + return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error()) + } + if owner.DraftVersion != *request.ExpectedDraftVersion || (request.ExpectedDraftDigest != "" && owner.DraftDigest != request.ExpectedDraftDigest) { + return draftConflictResponse(c, explorers, project, id) + } + result, digest, err := compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, Config: owner.DraftConfig}) + if err != nil { + return explorerV2Error(c, http.StatusUnprocessableEntity, "COMPILE_FAILED", err.Error()) + } + if capabilities.Materialize == nil { + return explorerV2Error(c, http.StatusServiceUnavailable, "PUBLICATION_UNAVAILABLE", "publication materializer is not configured") + } + execution, err := capabilities.Materialize(c.Context(), result.Bundle, recipe.RuntimeBindings{Project: project, DatasetGeneration: result.SourceGeneration}) + if err != nil { + _ = insertFailedV2Revision(c.Context(), explorers, owner, result.Config, digest, result.SourceGeneration, subjectFromFiber(c), []explorer.Diagnostic{{Severity: "ERROR", Code: "MATERIALIZATION_FAILED", Message: err.Error(), Retryable: true}}) + return explorerV2Error(c, http.StatusUnprocessableEntity, "MATERIALIZATION_FAILED", err.Error()) + } + if err := verifyQueryableOutputs(result.Bundle, execution); err != nil { + _ = insertFailedV2Revision(c.Context(), explorers, owner, result.Config, digest, execution.SourceGeneration, subjectFromFiber(c), []explorer.Diagnostic{{Severity: "ERROR", Code: "OUTPUT_NOT_QUERYABLE", Message: err.Error()}}) + return explorerV2Error(c, http.StatusUnprocessableEntity, "OUTPUT_NOT_QUERYABLE", err.Error()) + } + materializations := executionMaterializations(result.Bundle, execution) + compiled := explorer.Compilation{Bundle: result.Bundle, RecipeDigest: result.RecipeDigest, EmittedColumns: result.EmittedColumns} + sourceGeneration := result.SourceGeneration + if sourceGeneration == "" { + sourceGeneration = execution.SourceGeneration + } + revision, err := explorers.InsertInteractiveReadyRevisionV2(c.Context(), owner, result.Config, digest, compiled, result.ResolvedSchemaDigest, sourceGeneration, subjectFromFiber(c), materializations) + if err != nil { + return explorerV2Error(c, http.StatusInternalServerError, "REVISION_INSERT_FAILED", err.Error()) + } + if err := explorers.ActivateInteractive(c.Context(), project, id, revision.ID); err != nil { + return explorerV2Error(c, http.StatusConflict, "ACTIVATION_FAILED", err.Error()) + } + state, err := getExplorerV2State(c.Context(), explorers, project, id) + if err != nil { + return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error()) + } + return c.JSON(fiber.Map{"project": project, "explorerId": id, "publicationId": revision.ID, "activeUrl": state.ActiveURL, "state": state, "materializations": materializations, "diagnostics": result.Diagnostics}) + }) +} + +func decodeStrict(raw []byte, value any) error { + decoder := json.NewDecoder(strings.NewReader(string(raw))) + decoder.DisallowUnknownFields() + if err := decoder.Decode(value); err != nil { + return err + } + var trailing any + if err := decoder.Decode(&trailing); err == nil { + return fmt.Errorf("multiple JSON values") + } + return nil +} + +func principalFromFiber(c fiber.Ctx) *authscope.Principal { + principal, _ := c.Locals("principal").(*authscope.Principal) + return principal +} +func subjectFromFiber(c fiber.Ctx) string { + if principal := principalFromFiber(c); principal != nil { + return principal.Subject + } + return "" +} +func authorizeExplorerWrite(c fiber.Ctx, authorizer authscope.Authorizer, project string) error { + path := authscope.NormalizeAuthResourcePath(strings.TrimSpace(c.Query("auth_resource_path"))) + if err := authorizer.AuthorizeWrite(c.Context(), principalFromFiber(c), project, path); err != nil { + return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") + } + return nil +} + +func explorerV2Error(c fiber.Ctx, status int, code, message string) error { + return c.Status(status).JSON(fiber.Map{"error": fiber.Map{"code": code, "message": message}}) +} + +func draftConflictResponse(c fiber.Ctx, explorers *explorer.Service, project, id string) error { + current, err := explorers.Get(c.Context(), project, id) + if err != nil { + return explorerV2Error(c, http.StatusConflict, "DRAFT_CONFLICT", "Explorer draft changed; refresh before saving") + } + return c.Status(http.StatusConflict).JSON(fiber.Map{"error": fiber.Map{"code": "DRAFT_CONFLICT", "message": "Explorer draft changed; refresh before saving", "currentVersion": current.DraftVersion, "currentDigest": current.DraftDigest, "updatedAt": current.UpdatedAt.UTC().Format(time.RFC3339Nano)}}) +} + +func verifyExpectedVersion(ctx context.Context, service *explorer.Service, project, id string, expected *int64) error { + if expected == nil { + return nil + } + current, err := service.Get(ctx, project, id) + if errors.Is(err, explorer.ErrNotFound) { + return &v2HTTPError{status: http.StatusNotFound, code: "EXPLORER_NOT_FOUND", message: "Explorer not found"} + } + if err != nil { + return err + } + if current.DraftVersion != *expected { + return &v2HTTPError{status: http.StatusConflict, code: "DRAFT_CONFLICT", message: "Explorer draft changed; refresh before compiling", current: current} + } + return nil +} + +func verifyExpectedDigest(ctx context.Context, service *explorer.Service, project, id, expected string) error { + current, err := service.Get(ctx, project, id) + if errors.Is(err, explorer.ErrNotFound) { + return &v2HTTPError{status: http.StatusNotFound, code: "EXPLORER_NOT_FOUND", message: "Explorer not found"} + } + if err != nil { + return err + } + if current.DraftDigest != expected { + return &v2HTTPError{status: http.StatusConflict, code: "DRAFT_CONFLICT", message: "Explorer draft changed; refresh before previewing", current: current} + } + return nil +} + +type v2HTTPError struct { + status int + code, message string + current *explorer.Explorer +} + +func (e *v2HTTPError) Error() string { return e.message } + +func compileExplorerV2(ctx context.Context, compiler ExplorerV2Compiler, request ExplorerV2CompileRequest) (ExplorerV2CompileResult, string, error) { + _, bundle, canonical, digest, err := explorer.CanonicalConfigV2(request.Config, request.Project, request.ExplorerID, "interactive") + if err != nil { + return ExplorerV2CompileResult{}, digest, err + } + if compiler != nil { + result, err := compiler(ctx, request) + if err != nil { + return ExplorerV2CompileResult{}, digest, err + } + if len(result.Config) == 0 { + result.Config = canonical + } + if _, _, normalized, _, err := explorer.CanonicalConfigV2(result.Config, request.Project, request.ExplorerID, "interactive"); err != nil { + return ExplorerV2CompileResult{}, digest, err + } else { + result.Config = normalized + } + if result.Bundle.Name == "" { + result.Bundle = bundle + } + if result.RecipeDigest == "" { + result.RecipeDigest, err = result.Bundle.Digest() + if err != nil { + return ExplorerV2CompileResult{}, digest, err + } + } + return result, digest, nil + } + return ExplorerV2CompileResult{Config: canonical, Bundle: bundle, RecipeDigest: mustBundleDigest(bundle)}, digest, nil +} + +func mustBundleDigest(bundle recipe.Bundle) string { digest, _ := bundle.Digest(); return digest } + +func previewFailure(c fiber.Ctx, digest string, err error) error { + return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"outputColumns": []string{}, "rows": []map[string]any{}, "rowCount": 0, "digest": digest, "diagnostics": []explorer.Diagnostic{{Severity: "ERROR", Code: "PREVIEW_FAILED", Message: err.Error()}}}) +} + +func bundleHasOutput(bundle recipe.Bundle, name string) bool { + if name == "" { + return len(bundle.Outputs) > 0 + } + for _, output := range bundle.Outputs { + if output.Name == name { + return true + } + } + return false +} + +func columnsForOutput(result ExplorerV2CompileResult, output string) []string { + var columns []string + for _, column := range result.EmittedColumns { + if column.OutputID == output { + columns = append(columns, column.PublicColumn) + } + } + if len(columns) > 0 { + return columns + } + for _, item := range result.Bundle.Outputs { + if item.Name != output { + continue + } + for _, field := range item.Fields { + columns = append(columns, field.Name) + } + } + return columns +} + +func verifyQueryableOutputs(bundle recipe.Bundle, execution graphresolver.RecipeExecution) error { + states := map[string]string{} + for _, output := range execution.Outputs { + states[output.Name] = strings.ToUpper(output.State) + } + for _, output := range bundle.Outputs { + state := states[output.Name] + if state != "PUBLISHED" && state != "READY" && state != "ACTIVE" { + return fmt.Errorf("output %q is not queryable (state %q)", output.Name, state) + } + } + return nil +} + +func executionMaterializations(bundle recipe.Bundle, execution graphresolver.RecipeExecution) []explorer.Materialization { + result := make([]explorer.Materialization, 0, len(execution.Outputs)) + for _, output := range execution.Outputs { + result = append(result, explorer.Materialization{OutputID: output.Name, Output: output.Name, MaterializationID: execution.ID, Selector: explorerOutputSelector(bundle, output.Name), Columns: append([]publication.PhysicalColumn(nil), output.Columns...)}) + } + return result +} + +func insertFailedV2Revision(ctx context.Context, service *explorer.Service, owner *explorer.Explorer, config []byte, digest, generation, actor string, diagnostics []explorer.Diagnostic) error { + _, err := service.InsertInteractiveFailedRevisionV2(ctx, owner, config, digest, generation, actor, diagnostics) + return err +} + +func blankExplorerConfigV2(project, id, title string) []byte { + bundle := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "explorer_" + id, TranslationVersion: "interactive", Outputs: []recipe.Output{{Name: "DocumentReference", RootResourceType: "DocumentReference", RowGrain: "document_reference", Fields: []recipe.Field{{Name: "id", FieldRef: "DocumentReference.id", Expr: recipe.Expression{Select: "root.id"}}}}}} + recipeRaw, _ := json.Marshal(bundle) + cfg := explorer.ConfigV2{APIVersion: explorer.ConfigV2APIVersion, Kind: "ExplorerConfig", Project: project, Explorer: explorer.ConfigExplorer{ID: id, Title: title, Management: "interactive"}, Recipe: recipeRaw, Views: []explorer.ConfigView{{ID: "document-reference", Title: title, Output: "DocumentReference", Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "id", Label: "ID", Visible: true}}}}}} + raw, _ := json.Marshal(cfg) + return raw +} + +func forkRepositoryConfig(raw []byte, project, id, title string) ([]byte, error) { + cfg, bundle, err := explorer.DecodeDefaultConfigV2(raw, project) + if err != nil { + return nil, err + } + cfg.Explorer.ID, cfg.Explorer.Title, cfg.Explorer.Management = id, title, "interactive" + cfg.Views = make([]explorer.ConfigView, 0, len(bundle.Outputs)) + for _, output := range bundle.Outputs { + columns := make([]explorer.ConfigColumn, 0, len(output.Fields)) + for _, field := range output.Fields { + columns = append(columns, explorer.ConfigColumn{Column: field.Name, Label: field.Name, Visible: true}) + } + if len(columns) == 0 { + continue + } + cfg.Views = append(cfg.Views, explorer.ConfigView{ID: explorer.StableExplorerID(output.Name), Title: output.Name, Output: output.Name, Table: explorer.ConfigTable{Columns: columns}}) + } + if len(cfg.Views) == 0 { + return nil, fmt.Errorf("repository baseline has no executable output fields to seed a custom Explorer") + } + return json.Marshal(cfg) +} + +func getExplorerV2State(ctx context.Context, service *explorer.Service, project, id string) (*explorerV2State, error) { + value, err := service.Get(ctx, project, id) + if err == nil { + state := stateFromExplorer(value) + if value.ActiveRevisionID != "" { + if revision, revisionErr := service.Revision(ctx, value.ActiveRevisionID); revisionErr == nil { + state = mergeRevisionState(state, revision) + } + } + return state, nil + } + if id != "default" || !errors.Is(err, explorer.ErrNotFound) { + return nil, err + } + repository, repositoryErr := service.RepositoryConfig(ctx, project) + if repositoryErr != nil { + return nil, repositoryErr + } + digest := repository.ConfigDigest + if digest == "" { + _, _, _, digest, _ = explorer.CanonicalConfigV2(repository.Config, project, "default", "repository") + } + version := repository.DraftVersion + if version == 0 { + version = 1 + } + return &explorerV2State{Project: project, ExplorerID: "default", Management: explorer.ManagementRepository, BaselineConfig: repositoryBaselineConfig(repository.Config), DraftVersion: version, DraftDigest: digest, ActiveConfig: cloneRaw(repository.Config), ActiveRevisionID: repository.ActiveRevisionID, SourceGeneration: repository.SourceGeneration, Materializations: repository.Materializations, Dataset: repository.Dataset, Publication: repository.Publication, Diagnostics: repository.Diagnostics, PublicationState: repository.Publication.State, ActiveURL: explorerURL(project, "default"), UpdatedAt: repository.UpdatedAt}, nil +} + +func listExplorerV2States(ctx context.Context, service *explorer.Service, project string) ([]*explorerV2State, error) { + ids := map[string]bool{"default": true} + values, err := service.List(ctx, project) + if err != nil { + return nil, err + } + for _, value := range values { + ids[value.ExplorerID] = true + } + configs, configErr := service.ListConfigs(ctx, project) + if configErr == nil { + for _, value := range configs { + // RepositoryConfig rows are compatibility/readiness records. Custom + // identities are owned by loom_explorers; accepting arbitrary legacy + // config IDs here recreates the orphan-row 500 failure mode. + if value.ExplorerID == "default" { + ids["default"] = true + } + } + } + ordered := make([]string, 0, len(ids)) + for id := range ids { + ordered = append(ordered, id) + } + sort.Slice(ordered, func(i, j int) bool { + if ordered[i] == "default" { + return true + } + if ordered[j] == "default" { + return false + } + return ordered[i] < ordered[j] + }) + result := make([]*explorerV2State, 0, len(ordered)) + for _, id := range ordered { + state, err := getExplorerV2State(ctx, service, project, id) + if errors.Is(err, explorer.ErrNotFound) && id == "default" { + continue + } + if err != nil { + return nil, err + } + result = append(result, state) + } + return result, nil +} + +func stateFromExplorer(value *explorer.Explorer) *explorerV2State { + if value.ManagementMode == explorer.ManagementRepository { + return &explorerV2State{Project: value.Project, ExplorerID: value.ExplorerID, Management: value.ManagementMode, BaselineConfig: repositoryBaselineConfig(value.DraftConfig), DraftVersion: value.DraftVersion, DraftDigest: value.DraftDigest, ActiveConfig: cloneRaw(value.ActiveConfig), ActiveRevisionID: value.ActiveRevisionID, RecipeDigest: value.RecipeDigest, ResolvedSchemaDigest: value.ResolvedSchemaDigest, SourceGeneration: value.SourceGeneration, EmittedColumns: append([]explorer.EmittedColumn(nil), value.EmittedColumns...), Materializations: append([]explorer.Materialization(nil), value.Materializations...), Dataset: value.Dataset, Publication: value.Publication, Diagnostics: append([]explorer.Diagnostic(nil), value.Diagnostics...), PublicationState: value.Publication.State, ActiveURL: explorerURL(value.Project, value.ExplorerID), UpdatedBy: value.UpdatedBy, UpdatedAt: value.UpdatedAt} + } + return &explorerV2State{Project: value.Project, ExplorerID: value.ExplorerID, Management: value.ManagementMode, DraftConfig: cloneRaw(value.DraftConfig), DraftVersion: value.DraftVersion, DraftDigest: value.DraftDigest, ActiveConfig: cloneRaw(value.ActiveConfig), ActiveRevisionID: value.ActiveRevisionID, RecipeDigest: value.RecipeDigest, ResolvedSchemaDigest: value.ResolvedSchemaDigest, SourceGeneration: value.SourceGeneration, EmittedColumns: append([]explorer.EmittedColumn(nil), value.EmittedColumns...), Materializations: append([]explorer.Materialization(nil), value.Materializations...), Dataset: value.Dataset, Publication: value.Publication, Diagnostics: append([]explorer.Diagnostic(nil), value.Diagnostics...), PublicationState: publicationState(value.ActiveRevisionID), ActiveURL: explorerURL(value.Project, value.ExplorerID), UpdatedBy: value.UpdatedBy, UpdatedAt: value.UpdatedAt} +} + +func mergeRevisionState(state *explorerV2State, revision *explorer.Revision) *explorerV2State { + state.ActiveConfig = cloneRaw(revision.Config) + state.RecipeDigest, state.ResolvedSchemaDigest, state.SourceGeneration = revision.RecipeDigest, revision.ResolvedSchemaDigest, revision.SourceGeneration + state.EmittedColumns, state.Diagnostics = append([]explorer.EmittedColumn(nil), revision.EmittedColumns...), append([]explorer.Diagnostic(nil), revision.Diagnostics...) + state.Materializations, state.Dataset = explorer.WithDataframeSelectors(revision.Recipe, revision.Materializations, revision.Dataset) + state.Publication = revision.Publication + state.Publication.State, state.Publication.RevisionID = string(revision.Status), revision.ID + state.PublicationState = string(revision.Status) + return state +} +func publicationState(id string) string { + if id == "" { + return "" + } + return string(explorer.RevisionActive) +} +func explorerURL(project, id string) string { + return "/api/v1/projects/" + project + "/explorers/" + id +} +func cloneRaw(raw json.RawMessage) json.RawMessage { + if len(raw) == 0 { + return json.RawMessage("null") + } + return append(json.RawMessage(nil), raw...) +} + +func repositoryBaselineConfig(raw json.RawMessage) json.RawMessage { + var cfg explorer.ConfigV2 + if err := json.Unmarshal(raw, &cfg); err != nil { + return cloneRaw(raw) + } + cfg.Views = nil + cfg.SharedFilters = nil + cfg.FileActions = explorer.FileActions{} + baseline, err := json.Marshal(cfg) + if err != nil { + return cloneRaw(raw) + } + return baseline +} + +func stateErrorResponse(c fiber.Ctx, err error) error { + var httpErr *v2HTTPError + if errors.As(err, &httpErr) { + if httpErr.current != nil { + return c.Status(httpErr.status).JSON(fiber.Map{"error": fiber.Map{"code": httpErr.code, "message": httpErr.message, "currentVersion": httpErr.current.DraftVersion, "currentDigest": httpErr.current.DraftDigest, "updatedAt": httpErr.current.UpdatedAt.UTC().Format(time.RFC3339Nano)}}) + } + return explorerV2Error(c, httpErr.status, httpErr.code, httpErr.message) + } + return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_FAILED", err.Error()) +} diff --git a/internal/server/explorer_v2_lifecycle_test.go b/internal/server/explorer_v2_lifecycle_test.go new file mode 100644 index 00000000..9221ba7f --- /dev/null +++ b/internal/server/explorer_v2_lifecycle_test.go @@ -0,0 +1,263 @@ +package server + +import ( + "context" + "encoding/json" + "errors" + "io" + "net/http" + "net/http/httptest" + "strings" + "testing" + + graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/explorer" + "github.com/gofiber/fiber/v3" +) + +func TestExplorerV2RESTLifecycle(t *testing.T) { + store := explorer.NewMemoryStore() + service, err := explorer.NewService(store) + if err != nil { + t.Fatal(err) + } + repository := baselineExplorerConfigV2("project-a", "Default") + var repositoryConfig explorer.ConfigV2 + if err := json.Unmarshal(repository, &repositoryConfig); err != nil { + t.Fatal(err) + } + repositoryConfig.Explorer.Management = "repository" + repositoryConfig.Views = []explorer.ConfigView{{ID: "document-reference", Title: "Documents", Output: "DocumentReference", Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "id", Label: "ID", Visible: true}}}}} + repository, err = json.Marshal(repositoryConfig) + if err != nil { + t.Fatal(err) + } + if _, err := service.SaveRepositoryConfig(context.Background(), explorer.RepositoryConfig{Project: "project-a", Config: repository, SourceGeneration: "generation-a"}); err != nil { + t.Fatal(err) + } + bundle := testV2Bundle("explorer-custom") + compile := func(_ context.Context, request ExplorerV2CompileRequest) (ExplorerV2CompileResult, error) { + digest, _ := bundle.Digest() + return ExplorerV2CompileResult{Config: request.Config, Bundle: bundle, RecipeDigest: digest, SourceGeneration: "generation-a", EmittedColumns: []explorer.EmittedColumn{{OutputID: "DocumentReference", PublicColumn: "id", SelectionID: "id", LogicalType: "string"}}}, nil + } + preview := func(_ context.Context, _ recipe.Bundle, _ recipe.RuntimeBindings) (map[string][]map[string]any, error) { + return map[string][]map[string]any{"DocumentReference": {{"id": "dr-1"}}}, nil + } + materializeFails := false + materialize := func(_ context.Context, _ recipe.Bundle, _ recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { + if materializeFails { + return graphresolver.RecipeExecution{}, errors.New("backend unavailable") + } + return graphresolver.RecipeExecution{ID: "execution-a", SourceGeneration: "generation-a", State: "PUBLISHED", Outputs: []graphresolver.RecipeExecutionOutput{{Name: "DocumentReference", State: "PUBLISHED"}}}, nil + } + catalog := func(_ context.Context, project, _ string, _ string) (explorer.CatalogSnapshot, error) { + return explorer.NewCatalogSnapshot(project, "generation-a", "scope-a", explorer.Catalog{ + Nodes: []explorer.CatalogNode{{ID: "node-document-reference", ResourceType: "DocumentReference"}}, + Selections: map[string]explorer.CatalogSelection{ + "selection-id": {ID: "selection-id", NodeID: "node-document-reference", FieldRef: "DocumentReference.id", Select: "id", LogicalType: "string", Filterable: true}, + }, + }, true, false, nil) + } + app := fiber.New() + RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{Compile: compile, Catalog: catalog, Preview: preview, Materialize: materialize}) + + catalogResponse := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom-explorer/authoring/catalog", "") + if catalogResponse.StatusCode != http.StatusOK || !strings.Contains(catalogResponse.Body, `"snapshotToken":"sha256:`) || !strings.Contains(catalogResponse.Body, `"selectionId":"selection-id"`) { + t.Fatalf("catalog status=%d body=%s", catalogResponse.StatusCode, catalogResponse.Body) + } + + response := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers", `{"name":"Custom Explorer"}`) + if response.StatusCode != http.StatusCreated { + t.Fatalf("create status=%d body=%s", response.StatusCode, response.Body) + } + var created explorerV2State + decodeBody(t, response.Body, &created) + if created.ExplorerID != "custom-explorer" || created.Management != explorer.ManagementInteractive || created.DraftVersion != 1 { + t.Fatalf("created state=%#v", created) + } + + list := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers", "") + if list.StatusCode != http.StatusOK || !strings.Contains(list.Body, `"explorerId":"default"`) || !strings.Contains(list.Body, `"explorerId":"custom-explorer"`) { + t.Fatalf("list status=%d body=%s", list.StatusCode, list.Body) + } + defaultResponse := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/default", "") + if defaultResponse.StatusCode != http.StatusOK { + t.Fatalf("default status=%d body=%s", defaultResponse.StatusCode, defaultResponse.Body) + } + var defaultState explorerV2State + decodeBody(t, defaultResponse.Body, &defaultState) + if len(defaultState.BaselineConfig) == 0 || len(defaultState.ActiveConfig) == 0 || len(defaultState.DraftConfig) != 0 { + t.Fatalf("default state lifecycle config mismatch: %#v", defaultState) + } + var defaultConfig explorer.ConfigV2 + decodeBody(t, string(defaultState.BaselineConfig), &defaultConfig) + if len(defaultConfig.Views) != 0 { + t.Fatalf("default baseline contains views: %#v", defaultConfig.Views) + } + var activeDefaultConfig explorer.ConfigV2 + decodeBody(t, string(defaultState.ActiveConfig), &activeDefaultConfig) + if len(activeDefaultConfig.Views) != 1 || activeDefaultConfig.Views[0].Output != "DocumentReference" { + t.Fatalf("default active config lost presentation: %#v", activeDefaultConfig.Views) + } + defaultWrite := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/default/draft", `{}`) + if defaultWrite.StatusCode != http.StatusForbidden || !strings.Contains(defaultWrite.Body, `"code":"DEFAULT_READ_ONLY"`) { + t.Fatalf("default draft write status=%d body=%s", defaultWrite.StatusCode, defaultWrite.Body) + } + + var draft map[string]any + if err := json.Unmarshal(created.DraftConfig, &draft); err != nil { + t.Fatal(err) + } + if len(draft["views"].([]any)) == 0 { + t.Fatalf("custom fork did not receive presentation views: %s", created.DraftConfig) + } + draftExplorer := draft["explorer"].(map[string]any) + draftExplorer["title"] = "Edited" + draftBytes, _ := json.Marshal(draft) + draftRequest, _ := json.Marshal(map[string]any{"config": json.RawMessage(draftBytes), "expectedDraftVersion": created.DraftVersion, "expectedDraftDigest": created.DraftDigest}) + saved := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/custom-explorer/draft", string(draftRequest)) + if saved.StatusCode != http.StatusOK { + t.Fatalf("draft status=%d body=%s", saved.StatusCode, saved.Body) + } + var updated explorerV2State + decodeBody(t, saved.Body, &updated) + if updated.DraftVersion != 2 || updated.DraftDigest == created.DraftDigest { + t.Fatalf("saved state=%#v", updated) + } + stale := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/custom-explorer/draft", string(draftRequest)) + if stale.StatusCode != http.StatusConflict || !strings.Contains(stale.Body, `"code":"DRAFT_CONFLICT"`) || !strings.Contains(stale.Body, `"currentVersion":2`) { + t.Fatalf("stale status=%d body=%s", stale.StatusCode, stale.Body) + } + + compileRequest, _ := json.Marshal(map[string]any{"output": "DocumentReference", "config": json.RawMessage(updated.DraftConfig), "expectedDraftVersion": updated.DraftVersion}) + compiled := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom-explorer/authoring/compile", string(compileRequest)) + if compiled.StatusCode != http.StatusOK || !strings.Contains(compiled.Body, `"recipeDigest"`) { + t.Fatalf("compile status=%d body=%s", compiled.StatusCode, compiled.Body) + } + + previewRequest, _ := json.Marshal(map[string]any{"config": json.RawMessage(updated.DraftConfig), "output": "DocumentReference", "limit": 25, "draftDigest": updated.DraftDigest}) + previewResponse := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom-explorer/preview", string(previewRequest)) + if previewResponse.StatusCode != http.StatusOK || !strings.Contains(previewResponse.Body, `"rowCount":1`) { + t.Fatalf("preview status=%d body=%s", previewResponse.StatusCode, previewResponse.Body) + } + beforePublish, err := service.ActiveRevision(context.Background(), "project-a", "custom-explorer") + if err != explorer.ErrNotFound { + t.Fatalf("active revision before publish=%v, want ErrNotFound", beforePublish) + } + + publishRequest := `{"expectedDraftVersion":2,"expectedDraftDigest":"` + updated.DraftDigest + `"}` + published := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom-explorer/publish", publishRequest) + if published.StatusCode != http.StatusOK || !strings.Contains(published.Body, `"publicationId"`) || !strings.Contains(published.Body, `"activeUrl"`) { + t.Fatalf("publish status=%d body=%s", published.StatusCode, published.Body) + } + stateResponse := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom-explorer", "") + var active explorerV2State + decodeBody(t, stateResponse.Body, &active) + if stateResponse.StatusCode != http.StatusOK || active.ActiveRevisionID == "" || string(active.ActiveConfig) != string(active.DraftConfig) { + t.Fatalf("active state=%#v", active) + } + priorActiveRevision := active.ActiveRevisionID + materializeFails = true + draftExplorer["title"] = "Failed publication draft" + draftBytes, _ = json.Marshal(draft) + draftRequest, _ = json.Marshal(map[string]any{"config": json.RawMessage(draftBytes), "expectedDraftVersion": active.DraftVersion, "expectedDraftDigest": active.DraftDigest}) + failedDraft := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/custom-explorer/draft", string(draftRequest)) + if failedDraft.StatusCode != http.StatusOK { + t.Fatalf("failed publication draft save status=%d body=%s", failedDraft.StatusCode, failedDraft.Body) + } + var failedDraftState explorerV2State + decodeBody(t, failedDraft.Body, &failedDraftState) + failedPublish := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom-explorer/publish", `{"expectedDraftVersion":3,"expectedDraftDigest":"`+failedDraftState.DraftDigest+`"}`) + if failedPublish.StatusCode != http.StatusUnprocessableEntity { + t.Fatalf("failed publish status=%d body=%s", failedPublish.StatusCode, failedPublish.Body) + } + unchangedResponse := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom-explorer", "") + var unchanged explorerV2State + decodeBody(t, unchangedResponse.Body, &unchanged) + if unchanged.ActiveRevisionID != priorActiveRevision || string(unchanged.ActiveConfig) == string(unchanged.DraftConfig) { + t.Fatalf("failed publication changed active state: %#v", unchanged) + } +} + +func TestRepositoryStateExposesPublishedPacketAndPresentationFreeBaseline(t *testing.T) { + store := explorer.NewMemoryStore() + service, err := explorer.NewService(store) + if err != nil { + t.Fatal(err) + } + raw := baselineExplorerConfigV2("project-a", "Default") + var cfg explorer.ConfigV2 + if err := json.Unmarshal(raw, &cfg); err != nil { + t.Fatal(err) + } + cfg.Views = []explorer.ConfigView{{ID: "document-reference", Title: "Documents", Output: "DocumentReference", Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "id", Visible: true}}}}} + raw, err = json.Marshal(cfg) + if err != nil { + t.Fatal(err) + } + bundle := testV2Bundle("repository") + owner, revision, err := service.UpsertRepositoryV2(context.Background(), raw, "commit-a", "generation-a", "etl", explorer.Compilation{Bundle: bundle, RecipeDigest: "sha256:recipe"}, "sha256:schema", nil, explorer.DatasetMetadata{}, explorer.PublicationMetadata{}) + if err != nil { + t.Fatal(err) + } + if owner.ActiveRevisionID != "" { + t.Fatalf("owner was active before activation: %#v", owner) + } + if err := service.ActivateRepository(context.Background(), "project-a", revision.ID); err != nil { + t.Fatal(err) + } + state, err := getExplorerV2State(context.Background(), service, "project-a", "default") + if err != nil { + t.Fatal(err) + } + var baseline, active explorer.ConfigV2 + decodeBody(t, string(state.BaselineConfig), &baseline) + decodeBody(t, string(state.ActiveConfig), &active) + if len(baseline.Views) != 0 || len(active.Views) != 1 || active.Views[0].Output != "DocumentReference" || len(state.DraftConfig) != 0 { + t.Fatalf("repository state did not separate lifecycle configs: baseline=%#v active=%#v state=%#v", baseline.Views, active.Views, state) + } +} + +func testV2Bundle(name string) recipe.Bundle { + return recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: name, TranslationVersion: "interactive", Outputs: []recipe.Output{{Name: "DocumentReference", RootResourceType: "DocumentReference", RowGrain: "document_reference", Fields: []recipe.Field{{Name: "id", FieldRef: "DocumentReference.id", Expr: recipe.Expression{Select: "root.id"}}}}}} +} + +func baselineExplorerConfigV2(project, title string) []byte { + bundle := testV2Bundle("repository") + recipeRaw, _ := json.Marshal(bundle) + cfg := explorer.ConfigV2{APIVersion: explorer.ConfigV2APIVersion, Kind: "ExplorerConfig", Project: project, Explorer: explorer.ConfigExplorer{ID: "default", Title: title, Management: "repository"}, Recipe: recipeRaw} + raw, _ := json.Marshal(cfg) + return raw +} + +type testHTTPResponse struct { + StatusCode int + Body string +} + +func requestJSON(t *testing.T, app *fiber.App, method, path, body string) testHTTPResponse { + t.Helper() + request := httptest.NewRequest(method, path, strings.NewReader(body)) + if body != "" { + request.Header.Set("Content-Type", "application/json") + } + response, err := app.Test(request) + if err != nil { + t.Fatal(err) + } + defer response.Body.Close() + raw, err := io.ReadAll(response.Body) + if err != nil { + t.Fatal(err) + } + return testHTTPResponse{StatusCode: response.StatusCode, Body: string(raw)} +} + +func decodeBody(t *testing.T, body string, value any) { + t.Helper() + if err := json.Unmarshal([]byte(body), value); err != nil { + t.Fatalf("decode %s: %v", body, err) + } +} diff --git a/internal/server/explorer_wiring.go b/internal/server/explorer_wiring.go new file mode 100644 index 00000000..5c76aa34 --- /dev/null +++ b/internal/server/explorer_wiring.go @@ -0,0 +1,111 @@ +package server + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "fmt" + "sort" + "strings" + "unicode" + + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/catalog" + "github.com/calypr/loom/internal/dataset" + "github.com/calypr/loom/internal/explorer" +) + +// explorerCatalogReader assembles the complete catalog before exposing any +// opaque identifier. A failed dependency returns an explicitly incomplete +// snapshot; callers must never confuse an empty response with a usable one. +func explorerCatalogReader(discoverFields func(context.Context, catalog.PopulatedFieldOptions) ([]catalog.PopulatedField, error), discoverReferences func(context.Context, catalog.PopulatedReferenceOptions) ([]catalog.PopulatedReference, error), scopes *authscope.ScopeResolver, manifests dataset.ActiveResolver) func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { + return func(ctx context.Context, project, _ string, requestedGeneration string) (explorer.CatalogSnapshot, error) { + principal, _ := authscope.PrincipalFromContext(ctx) + if err := authscope.AuthorizeProject(principal, project, scopes != nil); err != nil { + return explorer.CatalogSnapshot{}, err + } + generation := requestedGeneration + schemaDigest := "" + if generation == "" && manifests != nil { + manifest, err := dataset.ResolveActive(ctx, manifests, project) + if err != nil { + return incompleteExplorerCatalog(project, generation, "", err) + } + generation, schemaDigest = manifest.Dataset.Generation, manifest.SchemaIdentity.SchemaSHA256 + } + scope := authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted} + if scopes != nil { + resolved, err := scopes.ResolveReadScopeForGeneration(ctx, principal, project, generation, nil) + if err != nil { + return incompleteExplorerCatalog(project, generation, schemaDigest, err) + } + scope = resolved + } + unrestricted := scope.Unrestricted() + options := catalog.PopulatedFieldOptions{Project: project, DatasetGeneration: generation, AuthResourcePaths: append([]string(nil), scope.AuthResourcePaths...), AuthResourcePathsUnrestricted: &unrestricted} + fields, err := discoverFields(ctx, options) + if err != nil { + return incompleteExplorerCatalog(project, generation, schemaDigest, err) + } + references, err := discoverReferences(ctx, catalog.PopulatedReferenceOptions{Project: project, DatasetGeneration: generation, AuthResourcePaths: append([]string(nil), scope.AuthResourcePaths...), AuthResourcePathsUnrestricted: &unrestricted, Mode: catalog.TraversalModeBuilder}) + if err != nil { + return incompleteExplorerCatalog(project, generation, schemaDigest, err) + } + assembled := explorer.Catalog{Selections: map[string]explorer.CatalogSelection{}} + nodes := map[string]explorer.CatalogNode{} + for _, field := range fields { + if field.ResourceType == "" || isLoomMetadataField(field.Path) { + continue + } + nodeID := explorer.OpaqueID("n_", field.ResourceType) + nodes[nodeID] = explorer.CatalogNode{ID: nodeID, ResourceType: field.ResourceType} + selectionID := explorer.OpaqueID("s_", field.ResourceType+"\x00"+field.Path) + assembled.Selections[selectionID] = explorer.CatalogSelection{ID: selectionID, NodeID: nodeID, FieldRef: explorerFieldRef(field.ResourceType, field.Path), Select: field.Path, LogicalType: field.Kind, Filterable: field.Kind != "object" && field.Kind != "array", Chartable: field.Kind != "object" && field.Kind != "array"} + } + for _, reference := range references { + if reference.FromType == "" || reference.ToType == "" { + continue + } + from, to := explorer.OpaqueID("n_", reference.FromType), explorer.OpaqueID("n_", reference.ToType) + nodes[from] = explorer.CatalogNode{ID: from, ResourceType: reference.FromType} + nodes[to] = explorer.CatalogNode{ID: to, ResourceType: reference.ToType} + assembled.Edges = append(assembled.Edges, explorer.CatalogEdge{ID: explorer.OpaqueID("e_", reference.FromType+"\x00"+reference.Label+"\x00"+reference.ToType), FromNodeID: from, ToNodeID: to, Label: reference.Label}) + } + for _, node := range nodes { + assembled.Nodes = append(assembled.Nodes, node) + } + sort.Slice(assembled.Nodes, func(i, j int) bool { return assembled.Nodes[i].ID < assembled.Nodes[j].ID }) + sort.Slice(assembled.Edges, func(i, j int) bool { return assembled.Edges[i].ID < assembled.Edges[j].ID }) + snapshot, err := explorer.NewCatalogSnapshot(project, generation, explorerScopeDigest(scope), assembled, true, false, nil) + if err != nil { + return explorer.CatalogSnapshot{}, err + } + snapshot.ResolvedSchemaDigest = schemaDigest + return snapshot, nil + } +} + +func incompleteExplorerCatalog(project, generation, schemaDigest string, cause error) (explorer.CatalogSnapshot, error) { + snapshot, err := explorer.NewCatalogSnapshot(project, generation, "unavailable", explorer.Catalog{Selections: map[string]explorer.CatalogSelection{}}, false, false, []explorer.Diagnostic{{Severity: "ERROR", Code: "CATALOG_UNAVAILABLE", Message: cause.Error(), Retryable: true}}) + snapshot.ResolvedSchemaDigest = schemaDigest + return snapshot, err +} + +func explorerScopeDigest(scope authscope.ReadScope) string { + paths := append([]string(nil), scope.AuthResourcePaths...) + sort.Strings(paths) + sum := sha256.Sum256([]byte(string(scope.Mode) + "\x00" + strings.Join(paths, "\x00"))) + return hex.EncodeToString(sum[:]) +} + +func explorerFieldRef(resourceType, path string) string { + var builder strings.Builder + for _, r := range strings.ToLower(path) { + if unicode.IsLetter(r) || unicode.IsDigit(r) { + builder.WriteRune(r) + } else if builder.Len() > 0 { + builder.WriteByte('_') + } + } + return fmt.Sprintf("%s.%s", resourceType, strings.Trim(builder.String(), "_")) +} diff --git a/internal/server/options.go b/internal/server/options.go index 39dbdf21..d561f8c5 100644 --- a/internal/server/options.go +++ b/internal/server/options.go @@ -26,8 +26,6 @@ type ServerConfig struct { Schema string `yaml:"schema"` ClickHouse ClickHouseConfig `yaml:"clickhouse"` Dataframer DataframerConfig `yaml:"dataframer"` - DefaultRecipe string `yaml:"default_recipe"` - DefaultTranslationVersion string `yaml:"default_translation_version"` RecipeBatchRows int `yaml:"recipe_batch_rows"` RecipeBatchBytes int `yaml:"recipe_batch_bytes"` AllowUnauthenticated bool `yaml:"allow_unauthenticated"` @@ -197,15 +195,6 @@ func applyEnvironment(cfg Config) (Config, error) { if value := strings.TrimSpace(os.Getenv("LOOM_SNAPSHOT_DIRECTORY")); value != "" { cfg.Server.SnapshotDirectory = value } - if value := strings.TrimSpace(os.Getenv("LOOM_DEFAULT_RECIPE")); value != "" { - cfg.Server.DefaultRecipe = value - } - if value := strings.TrimSpace(os.Getenv("LOOM_DEFAULT_TRANSLATION_VERSION")); value != "" { - cfg.Server.DefaultTranslationVersion = value - } - if (cfg.Server.DefaultRecipe == "") != (cfg.Server.DefaultTranslationVersion == "") { - return Config{}, fmt.Errorf("LOOM_DEFAULT_RECIPE and LOOM_DEFAULT_TRANSLATION_VERSION must be set together") - } if value := strings.TrimSpace(os.Getenv("LOOM_PUBLICATION_WORKER_LEASE")); value != "" { lease, err := time.ParseDuration(value) if err != nil { @@ -225,9 +214,6 @@ func applyEnvironment(cfg Config) (Config, error) { func (c Config) Validate() error { cfg := c - if (strings.TrimSpace(cfg.Server.DefaultRecipe) == "") != (strings.TrimSpace(cfg.Server.DefaultTranslationVersion) == "") { - return fmt.Errorf("server.default_recipe and server.default_translation_version must be set together") - } if cfg.Server.ClickHouse.Enabled && strings.TrimSpace(cfg.Server.Dataframer.Recipe) == "" { return fmt.Errorf("server.dataframer.recipe is required when server.clickhouse.enabled is true") } diff --git a/internal/server/server.go b/internal/server/server.go index b31f5e4f..2cc7e43f 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -34,6 +34,8 @@ import ( dataframeruntime "github.com/calypr/loom/internal/dataframe/runtime" publicationcontract "github.com/calypr/loom/internal/dataset" publicationarango "github.com/calypr/loom/internal/dataset/arango" + "github.com/calypr/loom/internal/explorer" + explorerarango "github.com/calypr/loom/internal/explorer/arango" "github.com/calypr/loom/internal/ingest" arangostore "github.com/calypr/loom/internal/store/arango" clickhousestore "github.com/calypr/loom/internal/store/clickhouse" @@ -92,18 +94,16 @@ func run(ctx context.Context, serverConfig Config) error { if err := lifecycleClient.Bootstrap(ctx, recipearango.BootstrapSpec()); err != nil { degradation = recordDegradation(logger, degradation, "bootstrap recipe registry", err) } - if err := lifecycleClient.Bootstrap(ctx, dataframeContractBootstrapSpec()); err != nil { - degradation = recordDegradation(logger, degradation, "bootstrap dataframe contract registry", err) - } if err := lifecycleClient.Bootstrap(ctx, recipearango.RevisionBootstrapSpec()); err != nil { degradation = recordDegradation(logger, degradation, "bootstrap recipe revision registry", err) } + if err := lifecycleClient.Bootstrap(ctx, explorerarango.BootstrapSpec()); err != nil { + return fmt.Errorf("bootstrap Explorer store: %w", err) + } recipeRegistry, err := recipearango.New(lifecycleClient) if err != nil { return fmt.Errorf("create recipe registry: %w", err) } - initialRecipe := strings.TrimSpace(serverConfig.Server.DefaultRecipe) - initialVersion := strings.TrimSpace(serverConfig.Server.DefaultTranslationVersion) if serverConfig.Server.ClickHouse.Enabled { data, err := os.ReadFile(serverConfig.Server.Dataframer.Recipe) if err != nil { @@ -116,21 +116,7 @@ func run(ctx context.Context, serverConfig Config) error { if _, err := (exec.PersistentRegistry{Store: recipeRegistry}).RegisterVersion(ctx, defaultBundle); err != nil { degradation = recordDegradation(logger, degradation, "register default dataframe recipe", err) } - if initialRecipe == "" && initialVersion == "" { - initialRecipe, initialVersion = defaultBundle.Name, defaultBundle.TranslationVersion - } - } - contractStore := dataframeContractStore{query: lifecycleClient} - contractState := &dataframeContractState{} - contract, contractErr := contractStore.Load(ctx) - if errors.Is(contractErr, errNoDataframeContract) && initialRecipe != "" && initialVersion != "" { - contract, contractErr = contractStore.Promote(ctx, initialRecipe, initialVersion) - } - if contractErr != nil && !errors.Is(contractErr, errNoDataframeContract) { - degradation = recordDegradation(logger, degradation, "load dataframe contract", contractErr) - contract = promotedDataframeContract{Recipe: initialRecipe, TranslationVersion: initialVersion} } - contractState.Set(contract) lifecycleStore, err := publicationarango.New(lifecycleClient) if err != nil { return fmt.Errorf("create dataset lifecycle store: %w", err) @@ -282,27 +268,16 @@ func run(ctx context.Context, serverConfig Config) error { } return graphresolver.ProjectRelease{ID: active.Release.ID, Project: active.Release.Project, Generation: active.Release.Generation, Revision: strconv.FormatInt(active.Revision, 10), State: "ACTIVE"}, nil } - contractPromoter := func(ctx context.Context, recipeName, version string) (graphresolver.DataframeContract, error) { - if _, err := (exec.PersistentRegistry{Store: recipeRegistry}).LoadVersion(ctx, recipeName, version); err != nil { - return graphresolver.DataframeContract{}, err - } - contract, err := contractStore.Promote(ctx, recipeName, version) - if err != nil { - return graphresolver.DataframeContract{}, err - } - contractState.Set(contract) - return graphresolver.DataframeContract{Recipe: contract.Recipe, TranslationVersion: contract.TranslationVersion, PromotedAt: contract.PromotedAt.Format(time.RFC3339Nano)}, nil + explorerStore, err := explorerarango.New(lifecycleClient) + if err != nil { + return fmt.Errorf("create Explorer store: %w", err) } - contractAuthorizer := func(ctx context.Context) error { - principal, ok := authscope.PrincipalFromContext(ctx) - if !ok || principal == nil { - return authscope.ErrUnauthenticated - } - if noAuthEnabled || strings.EqualFold(serverConfig.Auth.Mode, "basic") || strings.EqualFold(principal.Claims["loom_operator"], "true") { - return nil - } - return authscope.ErrForbidden + explorerService, err := explorer.NewService(explorerStore) + if err != nil { + return fmt.Errorf("create Explorer service: %w", err) } + explorerMaterializer := explorerBundleMaterializer(recipeEngine, bundleTarget, publishedRegistry, degradation, logger, serverConfig.Server.RecipeBatchRows, serverConfig.Server.RecipeBatchBytes) + explorerCatalog := explorerCatalogReader(discoverFields, discoverReferences, scopeResolver, activeManifestResolver) resolver := graphresolver.NewResolver(graphresolver.ResolverConfig{ DataframeQuery: queryapi.Config{ DiscoverReferences: discoverReferences, @@ -326,10 +301,7 @@ func run(ctx context.Context, serverConfig Config) error { RecipeMaterialize: recipeMaterializer(recipeEngine, bundleTarget, publishedRegistry, degradation, logger, serverConfig.Server.RecipeBatchRows, serverConfig.Server.RecipeBatchBytes), ExactMaterializationStarter: exactStarter, ProjectReleaseActivator: releaseActivator, - DataframeContractPromoter: contractPromoter, - DataframeContractAuthorizer: contractAuthorizer, CandidateProjects: candidateProjects, - DefaultContract: contractState.Current, }) ingestRunner := loadapi.IngestRunner{BaseOptions: ingest.LoadOptions{ ConnectionOptions: connOpts, @@ -381,6 +353,23 @@ func run(ctx context.Context, serverConfig Config) error { if err := registerRoutes(server, resourceService, snapshotService, releaseService, authorizer, resolver, publishedRegistry, scopeResolver); err != nil { return fmt.Errorf("register HTTP routes: %w", err) } + RegisterExplorerConfigV2Route(server.App(), authorizer, func(ctx context.Context, principal *authscope.Principal, project string) error { + if scopeResolver == nil { + return nil + } + scope, err := scopeResolver.ResolveReadScope(ctx, principal, project, nil) + if err != nil || (!scope.Unrestricted() && len(scope.AuthResourcePaths) == 0) { + return authscope.ErrForbidden + } + return nil + }, explorerService, explorerMaterializer, ExplorerV2LifecycleConfig{ + Compile: explorerV2Compiler(recipeEngine, explorerCatalog), + Catalog: explorerCatalog, + Preview: func(ctx context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (map[string][]map[string]any, error) { + return recipeEngine.PreviewBundle(ctx, bundle, bindings) + }, + Materialize: explorerMaterializer, + }) if publicationWorker != nil { go func() { err := publicationWorker.Run(ctx, time.Second, func(workerErr error) { diff --git a/internal/store/arango/client.go b/internal/store/arango/client.go index fe6bfed8..94c343dd 100644 --- a/internal/store/arango/client.go +++ b/internal/store/arango/client.go @@ -25,6 +25,19 @@ type Client struct { client *http.Client } +// Transaction is the narrow query surface used by stores that need to make +// several collection updates visible as one Arango transaction. +type Transaction interface { + QueryRows(context.Context, string, int, map[string]interface{}, RowVisitor) error +} + +type TransactionCollections struct { + Read []string + Write []string +} + +type TransactionFunc func(context.Context, Transaction) error + var bufferPool = sync.Pool{ New: func() any { return &bytes.Buffer{} @@ -146,7 +159,31 @@ func (c *Client) InsertBatchRaw(ctx context.Context, collection string, docs []j } func (c *Client) QueryRows(ctx context.Context, query string, batchSize int, bindVars map[string]interface{}, visit RowVisitor) error { - cursor, err := c.db.Query(ctx, query, &driver.QueryOptions{BatchSize: batchSize, BindVars: bindVars}) + return queryRows(ctx, c.db, query, batchSize, bindVars, visit) +} + +func (c *Client) WithTransaction(ctx context.Context, collections TransactionCollections, fn TransactionFunc) error { + if fn == nil { + return fmt.Errorf("Arango transaction callback is required") + } + return c.db.WithTransaction(ctx, driver.TransactionCollections{ + Read: collections.Read, + Write: collections.Write, + }, nil, nil, nil, func(txCtx context.Context, tx driver.Transaction) error { + return fn(txCtx, transactionClient{queryer: tx}) + }) +} + +type transactionClient struct { + queryer driver.DatabaseQuery +} + +func (t transactionClient) QueryRows(ctx context.Context, query string, batchSize int, bindVars map[string]interface{}, visit RowVisitor) error { + return queryRows(ctx, t.queryer, query, batchSize, bindVars, visit) +} + +func queryRows(ctx context.Context, queryer driver.DatabaseQuery, query string, batchSize int, bindVars map[string]interface{}, visit RowVisitor) error { + cursor, err := queryer.Query(ctx, query, &driver.QueryOptions{BatchSize: batchSize, BindVars: bindVars}) if err != nil { return err } From e6afba6abc00196a714b12f033deea1367f0aba0 Mon Sep 17 00:00:00 2001 From: matthewpeterkort Date: Tue, 18 Aug 2026 14:00:04 -0700 Subject: [PATCH 04/15] optimize loom clickhouse table reader API --- docs/DEVELOPER_ARCHITECTURE.md | 8 +- docs/FRONTEND_EXPLORER_V2_MIGRATION.md | 41 +- .../graph/aggregate_http_integration_test.go | 162 +++++++ .../graph/materialization/aggregate_batch.go | 399 ++++++++++++++++ .../materialization/aggregate_batch_test.go | 97 ++++ .../graph/materialization/operation_cache.go | 107 +++++ .../materialization/operation_cache_test.go | 45 ++ .../graphql/graph/materialization/service.go | 79 +--- .../graph/resolver/fhir_reference_loader.go | 5 - .../graph/resolver/operation_context.go | 36 ++ .../aggregate_clickhouse_integration_test.go | 105 ++++ .../dataframe/published/aggregate_execute.go | 447 ++++++++++++++++++ .../published/aggregate_execute_test.go | 74 +++ .../dataframe/published/aggregate_plan.go | 290 ++++++++++++ .../published/aggregate_plan_test.go | 160 +++++++ internal/dataframe/published/aggregate_sql.go | 447 ++++++++++++++++++ .../dataframe/published/aggregate_types.go | 93 ++++ internal/dataframe/published/aggregations.go | 255 ---------- internal/dataframe/published/federation.go | 106 ----- .../dataframe/published/federation_test.go | 7 - internal/dataframe/published/read.go | 9 +- internal/explorer/config_v2.go | 10 + internal/explorer/service.go | 76 ++- internal/explorer/v2_lifecycle_test.go | 4 +- internal/server/explorer_v2_engine.go | 2 +- internal/server/explorer_v2_lifecycle.go | 52 +- internal/server/explorer_v2_lifecycle_test.go | 46 +- 27 files changed, 2639 insertions(+), 523 deletions(-) create mode 100644 internal/api/graphql/graph/aggregate_http_integration_test.go create mode 100644 internal/api/graphql/graph/materialization/aggregate_batch.go create mode 100644 internal/api/graphql/graph/materialization/aggregate_batch_test.go create mode 100644 internal/api/graphql/graph/materialization/operation_cache.go create mode 100644 internal/api/graphql/graph/materialization/operation_cache_test.go create mode 100644 internal/api/graphql/graph/resolver/operation_context.go create mode 100644 internal/dataframe/published/aggregate_clickhouse_integration_test.go create mode 100644 internal/dataframe/published/aggregate_execute.go create mode 100644 internal/dataframe/published/aggregate_execute_test.go create mode 100644 internal/dataframe/published/aggregate_plan.go create mode 100644 internal/dataframe/published/aggregate_plan_test.go create mode 100644 internal/dataframe/published/aggregate_sql.go create mode 100644 internal/dataframe/published/aggregate_types.go delete mode 100644 internal/dataframe/published/aggregations.go diff --git a/docs/DEVELOPER_ARCHITECTURE.md b/docs/DEVELOPER_ARCHITECTURE.md index 06995b7c..fb3d9fbd 100644 --- a/docs/DEVELOPER_ARCHITECTURE.md +++ b/docs/DEVELOPER_ARCHITECTURE.md @@ -37,9 +37,11 @@ lifecycle or authoring types; REST V2 is the only Explorer contract. Ownership map: `dataset` owns immutable FHIR generation lifecycle; `catalog` owns persistence-neutral observed facts; `catalog/arango` owns catalog -persistence; `dataframe/publication` owns dataframe publishing contracts and -the runner; `dataframe/publication/{arango,clickhouse}` own storage adapters; -and `dataframe/published` owns safe published-data reading and federation. +persistence; `explorer` owns portable Explorer configs, editable drafts, +immutable revisions, and publication state; `explorer/arango` owns its durable +adapter; `dataframe/publication` owns dataframe publishing contracts and the +runner; `dataframe/publication/{arango,clickhouse}` own storage adapters; and +`dataframe/published` owns safe published-data reading and federation. `cmd/arango-fhir-proto` is the operator CLI. Its supported commands are: diff --git a/docs/FRONTEND_EXPLORER_V2_MIGRATION.md b/docs/FRONTEND_EXPLORER_V2_MIGRATION.md index de681ee6..dcaa90db 100644 --- a/docs/FRONTEND_EXPLORER_V2_MIGRATION.md +++ b/docs/FRONTEND_EXPLORER_V2_MIGRATION.md @@ -11,7 +11,7 @@ Loom now has two Explorer ownership modes: | Explorer | Owner | Config returned by Loom | Frontend behavior | | --- | --- | --- | --- | -| `default` | Repository / ETL | `baselineConfig` contains the recipe/schema baseline; `activeConfig` may contain the complete ETL-authored packet | Render `activeConfig` when present, otherwise build the layout from live dataset metadata. | +| `default` | Repository / ETL initially; Builder may edit and publish | `baselineConfig` contains a presentation-free projection; `draftConfig` and `activeConfig` contain the editable/published packet | Render and edit `draftConfig`; use `activeConfig` for the published view and fall back to `baselineConfig`/dataset metadata when needed. | | Custom ID | User / Builder | `draftConfig` and, after publication, `activeConfig` contain the complete V2 packet | Render and edit the lossless presentation config. | Repository packets may be baseline-only or may include a complete presentation @@ -67,12 +67,11 @@ interface ExplorerState { // recipe/schema baseline. baselineConfig?: ExplorerConfigV2; - // The published packet is renderable but not editable. It may be present - // for the repository default and is present after custom publication. + // The published packet is renderable. Edit draftConfig and publish it to + // replace activeConfig. activeConfig?: ExplorerConfigV2; - // Present for custom Explorers only. The default is read-only and does not - // require an editable draft. + // Present for custom Explorers and for the repository default. draftConfig?: ExplorerConfigV2; draftVersion: number; @@ -144,10 +143,10 @@ the selected detail record. GET /api/v1/projects/:project/explorers/:explorerId ``` -For `default`, this is read-only but fully inspectable. Do not expect a -`draftConfig`; the repository default has no editable draft. Render -`activeConfig` when it contains a complete packet. If it is absent or has no -views, use `baselineConfig` and derive the layout from `dataset`. +The `default` Explorer is editable. Render `draftConfig` in the Builder and +use `activeConfig` for the currently published view. If either packet is +absent or has no views, use `baselineConfig` and derive the layout from +`dataset`. ### Create a custom Explorer @@ -196,6 +195,10 @@ saves only the draft. It does not compile, materialize, or change the active revision. `expectedDraftVersion` is required; send `expectedDraftDigest` when available. +The same endpoint applies to `default`. Keep `explorer.id` as `default` and +keep `explorer.management` as `repository`; the repository identity describes +where the config originated, not whether Builder edits are allowed. + On conflict, Loom returns HTTP 409: ```json @@ -308,7 +311,7 @@ return HTTP 422 with empty `columns`/`rows` and a diagnostic such as } ``` -### Publish a custom Explorer +### Publish an Explorer ```http POST /api/v1/projects/:project/explorers/:explorerId/publish @@ -323,8 +326,9 @@ Content-Type: application/json Publish reads the server-owned draft. The frontend does not send a config in this request. Loom recompiles the draft, materializes every referenced output, checks that every output is queryable, inserts an immutable revision, and then -activates it. A failed publication leaves the previous active revision in -place and records diagnostics on the failed revision. +activates it. This applies to both custom Explorers and `default`. A failed +publication leaves the previous active revision in place and records +diagnostics on the failed revision. On success, update the local store from the returned `state` rather than manually inferring active metadata: @@ -389,8 +393,9 @@ Split the implementation into three layers: 2. `explorerStore` — the selected project/Explorer, draft version/digest, active revision, and request status. 3. Presenters: - - `DefaultExplorerPresenter`: renders `activeConfig` when present and - derives views from `dataset.outputs` and `columns` otherwise. + - `DefaultExplorerPresenter`: renders `draftConfig` while editing, then + `activeConfig` after publication, and derives views from `dataset.outputs` + and `columns` when no complete packet is available. - `InteractiveExplorerPresenter`: renders `draftConfig.views` and validates referenced outputs/columns against live metadata. @@ -404,7 +409,7 @@ The minimum request flow is: ```text GET explorers -> GET selected Explorer - -> custom: edit draft and PUT /draft + -> edit draft (including default) and PUT /draft -> POST /authoring/compile when discovery changes -> POST /preview for the selected output -> POST /publish after explicit user confirmation @@ -420,8 +425,8 @@ the Builder belong behind the REST lifecycle contract. - `400`: malformed request, missing expected version, unsupported limit, or missing required header/input. Show a request correction message. -- `403`: authorization failure or an attempted write to `default`. -- `404`: the custom Explorer does not exist. Refresh the Explorer list. +- `403`: authorization failure. +- `404`: the Explorer does not exist. Refresh the Explorer list. - `409` with `DRAFT_CONFLICT`: refresh server state and reconcile edits. - `409` during publication/activation: keep the current active Explorer and show the returned diagnostic; do not claim publication succeeded. @@ -450,4 +455,4 @@ HTTP response. Clear the pending state in both success and failure handlers. - [ ] Use the REST compile result as the source of emitted columns and digests. - [ ] Scope preview to one output and clear loading state on 4xx/5xx responses. - [ ] Publish only after explicit confirmation and consume the returned state. -- [ ] Keep repository default read-only in the frontend. +- [ ] Allow the repository default to use the same draft/compile/publish flow as custom Explorers. diff --git a/internal/api/graphql/graph/aggregate_http_integration_test.go b/internal/api/graphql/graph/aggregate_http_integration_test.go new file mode 100644 index 00000000..8a0aa2bb --- /dev/null +++ b/internal/api/graphql/graph/aggregate_http_integration_test.go @@ -0,0 +1,162 @@ +package graphqlapi_test + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "strings" + "sync" + "sync/atomic" + "testing" + "time" + + graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" + "github.com/calypr/loom/internal/authscope" + dfpublication "github.com/calypr/loom/internal/dataframe/publication" + dfpublished "github.com/calypr/loom/internal/dataframe/published" +) + +type aggregateHTTPCatalog struct { + dfpublication.BundleCatalog + execution dfpublication.BundleExecution + lists atomic.Int32 +} + +func (c *aggregateHTTPCatalog) ListExecutions(context.Context, dfpublication.BundleState, time.Time) ([]dfpublication.BundleExecution, error) { + c.lists.Add(1) + return []dfpublication.BundleExecution{c.execution}, nil +} + +func (c *aggregateHTTPCatalog) GetPointer(context.Context, string) (dfpublication.BundlePointer, error) { + return dfpublication.BundlePointer{ExecutionID: c.execution.ID}, nil +} + +type aggregateHTTPQueryer struct { + mu sync.Mutex + queries []string +} + +func (q *aggregateHTTPQueryer) QueryRowsArgs(_ context.Context, query string, _ []string, _ ...any) ([]map[string]any, error) { + q.mu.Lock() + q.queries = append(q.queries, query) + q.mu.Unlock() + return nil, nil +} + +func (q *aggregateHTTPQueryer) QueryRowsArgsVisit(ctx context.Context, query string, columns []string, visit func(map[string]any) error, args ...any) error { + rows, err := q.QueryRowsArgs(ctx, query, columns, args...) + if err != nil { + return err + } + for _, row := range rows { + if err := visit(row); err != nil { + return err + } + } + return nil +} + +func TestGraphQLAggregateAliasesUseOneGroupingStatement(t *testing.T) { + columns := []dfpublication.PhysicalColumn{{Name: "__loom_row_id", ClickHouse: "String"}} + for i := 0; i < 156; i++ { + columns = append(columns, dfpublication.PhysicalColumn{Name: fmt.Sprintf("facet_%03d", i), ClickHouse: "Nullable(String)"}) + } + now := time.Now().UTC() + catalog := &aggregateHTTPCatalog{execution: dfpublication.BundleExecution{ + ID: "execution", BundleIdentity: dfpublication.BundleIdentity{ + Name: "recipe", TranslationVersion: "v1", Project: "P1", DatasetGeneration: "generation", + }, + State: dfpublication.BundlePublished, UpdatedAt: now, + Outputs: []dfpublication.BundleOutputRecord{{ + Name: "Patient", PhysicalTable: "physical_patient", Columns: columns, + State: dfpublication.BundlePublished, + }}, + }} + queryer := &aggregateHTTPQueryer{} + root := graphresolver.NewResolver(graphresolver.ResolverConfig{ + MaterializationReader: &dfpublished.Reader{ClickHouse: queryer, Catalog: catalog}, + }) + server, err := newGraphServer(root, authscope.StaticAuthenticator{Principal: authscope.Principal{Subject: "user", Projects: []string{"P1"}}}) + if err != nil { + t.Fatal(err) + } + + var fields strings.Builder + for i := 0; i < 156; i++ { + directive := "" + if i == 0 { + directive = " @include(if: $include)" + } + fmt.Fprintf(&fields, " a%03d: dataframeAggregate(input: {selector: $selector, groupBy: [\"facet_%03d\"], operation: \"COUNT\"})%s { columns rows materialization { id } }", i, i, directive) + } + fields.WriteString(" totalA: dataframeAggregate(input: {selector: $selector, operation: \"COUNT\"}) { columns rows materialization { id } }") + fields.WriteString(" totalB: dataframeAggregate(input: {selector: $selector, operation: \"COUNT\"}) { columns rows materialization { id } }") + query := "query AggregateTable($selector: DataframeSelectorInput!, $include: Boolean!) {" + + " page: dataframeRows(input: {selector: $selector, columns: [\"facet_000\"], first: 1}) { columns rows }" + + " ...FacetFields" + + " skipped: dataframeAggregate(input: {selector: $selector, operation: \"COUNT\"}) @skip(if: true) { columns }" + + "} fragment FacetFields on Query {" + fields.String() + "}" + body, err := json.Marshal(map[string]any{ + "query": query, + "variables": map[string]any{ + "selector": map[string]any{"recipe": "recipe", "translationVersion": "v1", "output": "Patient"}, + "include": true, + }, + }) + if err != nil { + t.Fatal(err) + } + request := httptest.NewRequest(http.MethodPost, "/graphql/graph", strings.NewReader(string(body))) + request.Header.Set("Content-Type", "application/json") + response, err := server.App().Test(request) + if err != nil { + t.Fatal(err) + } + defer response.Body.Close() + var payload map[string]any + if err := json.NewDecoder(response.Body).Decode(&payload); err != nil { + t.Fatal(err) + } + if errorsValue, ok := payload["errors"].([]any); ok && len(errorsValue) != 0 { + t.Fatalf("unexpected GraphQL errors: %#v", errorsValue) + } + data, ok := payload["data"].(map[string]any) + if !ok { + t.Fatalf("response has no data: %#v", payload) + } + for i := 0; i < 156; i++ { + if _, ok := data[fmt.Sprintf("a%03d", i)]; !ok { + t.Fatalf("response is missing alias a%03d", i) + } + } + if _, ok := data["totalA"]; !ok { + t.Fatal("response is missing totalA") + } + if _, ok := data["totalB"]; !ok { + t.Fatal("response is missing totalB") + } + if _, ok := data["skipped"]; ok { + t.Fatal("skipped alias unexpectedly executed") + } + + queryer.mu.Lock() + queries := append([]string(nil), queryer.queries...) + queryer.mu.Unlock() + aggregateCalls := 0 + for _, statement := range queries { + if strings.Contains(statement, "GROUP BY GROUPING SETS") { + aggregateCalls++ + } + } + if aggregateCalls != 1 { + t.Fatalf("aggregate ClickHouse calls = %d, want 1 (all calls %d)", aggregateCalls, len(queries)) + } + if len(queries) > 5 { + t.Fatalf("total ClickHouse calls = %d, want at most 5", len(queries)) + } + if catalog.lists.Load() != 1 { + t.Fatalf("catalog discovery calls = %d, want 1", catalog.lists.Load()) + } +} diff --git a/internal/api/graphql/graph/materialization/aggregate_batch.go b/internal/api/graphql/graph/materialization/aggregate_batch.go new file mode 100644 index 00000000..14b4a5ad --- /dev/null +++ b/internal/api/graphql/graph/materialization/aggregate_batch.go @@ -0,0 +1,399 @@ +package materializationapi + +import ( + "context" + "fmt" + "sort" + "strings" + "sync" + "time" + + "github.com/calypr/loom/generated/graphql/graph/model" + httpapi "github.com/calypr/loom/internal/api/http" + dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" + dfmaterialization "github.com/calypr/loom/internal/dataframe/published" +) + +const aggregateFallbackDelay = 2 * time.Millisecond + +type aggregateOperationStateKey struct{} + +type aggregateOperationState struct { + service *Service + operationCtx context.Context + expectedCalls int + receivedCalls int + pending []*aggregateCall + timer *time.Timer + dispatching bool + dispatchCalls func(context.Context, []*aggregateCall) + lastEnqueue time.Time + + mu sync.Mutex + projects *projectsCacheEntry + federations map[string]*federationCacheEntry +} + +type aggregateCallKind uint8 + +const ( + aggregateCallLegacy aggregateCallKind = iota + aggregateCallRich +) + +type aggregateCall struct { + kind aggregateCallKind + selector dfmaterialization.DataframeSelector + filters []dfmaterialization.Filter + legacy model.DataframeAggregateInput + rich model.DataframeAggregationsInput + result chan aggregateCallResult +} + +type aggregateCallResult struct { + legacy dfmaterialization.AggregateResult + rich dfmaterialization.AggregationsResult + err error +} + +func (s *Service) WithOperationContext(ctx context.Context, expectedCalls int) context.Context { + state := &aggregateOperationState{ + service: s, expectedCalls: expectedCalls, + federations: make(map[string]*federationCacheEntry), + } + result := context.WithValue(ctx, aggregateOperationStateKey{}, state) + state.operationCtx = result + if done := result.Done(); done != nil { + go func() { + <-done + state.cancelPending(result.Err()) + }() + } + if s != nil && s.logger != nil { + s.logger.Debug("dataframe aggregate operation installed", + "request_id", httpapi.RequestIDFromContext(result), + "expected_calls", expectedCalls, + ) + } + return result +} + +func aggregateStateFromContext(ctx context.Context) *aggregateOperationState { + state, _ := ctx.Value(aggregateOperationStateKey{}).(*aggregateOperationState) + return state +} + +func (s *Service) submitAggregateCall(ctx context.Context, call *aggregateCall) aggregateCallResult { + call.result = make(chan aggregateCallResult, 1) + state := aggregateStateFromContext(ctx) + if state == nil || state.service != s || state.expectedCalls <= 0 { + s.dispatchAggregateCalls(ctx, []*aggregateCall{call}) + } else { + state.enqueue(call) + } + select { + case result := <-call.result: + return result + case <-ctx.Done(): + return aggregateCallResult{err: ctx.Err()} + } +} + +func (s *aggregateOperationState) enqueue(call *aggregateCall) { + s.mu.Lock() + if err := s.operationCtx.Err(); err != nil { + s.mu.Unlock() + call.result <- aggregateCallResult{err: err} + return + } + s.pending = append(s.pending, call) + s.receivedCalls++ + s.lastEnqueue = time.Now() + if s.timer == nil { + s.timer = time.AfterFunc(aggregateFallbackDelay, s.fallbackDispatch) + } + if s.receivedCalls >= s.expectedCalls { + if s.timer != nil { + s.timer.Stop() + s.timer = nil + } + batch := s.takePendingLocked() + s.mu.Unlock() + go s.dispatch(batch) + return + } + s.mu.Unlock() +} + +func (s *aggregateOperationState) fallbackDispatch() { + s.mu.Lock() + if remaining := aggregateFallbackDelay - time.Since(s.lastEnqueue); remaining > 0 { + s.timer = time.AfterFunc(remaining, s.fallbackDispatch) + s.mu.Unlock() + return + } + s.timer = nil + batch := s.takePendingLocked() + s.mu.Unlock() + if s.service != nil && s.service.logger != nil && len(batch) > 0 { + s.service.logger.Debug("dataframe aggregate fallback dispatch", + "request_id", httpapi.RequestIDFromContext(s.operationCtx), + "batch_calls", len(batch), + "expected_calls", s.expectedCalls, + "received_calls", s.receivedCalls, + ) + } + s.dispatch(batch) +} + +func (s *aggregateOperationState) takePendingLocked() []*aggregateCall { + batch := s.pending + s.pending = nil + if len(batch) > 0 { + s.dispatching = true + } + return batch +} + +func (s *aggregateOperationState) dispatch(batch []*aggregateCall) { + if len(batch) > 0 { + if s.service != nil && s.service.logger != nil { + s.service.logger.Debug("dataframe aggregate dispatch", + "request_id", httpapi.RequestIDFromContext(s.operationCtx), + "batch_calls", len(batch), + "expected_calls", s.expectedCalls, + "received_calls", s.receivedCalls, + ) + } + if s.dispatchCalls != nil { + s.dispatchCalls(s.operationCtx, batch) + } else { + s.service.dispatchAggregateCalls(s.operationCtx, batch) + } + } + s.mu.Lock() + s.dispatching = false + if len(s.pending) > 0 && s.timer == nil { + s.timer = time.AfterFunc(aggregateFallbackDelay, s.fallbackDispatch) + } + s.mu.Unlock() +} + +func (s *aggregateOperationState) cancelPending(err error) { + s.mu.Lock() + if s.timer != nil { + s.timer.Stop() + s.timer = nil + } + pending := s.pending + s.pending = nil + s.mu.Unlock() + for _, call := range pending { + call.result <- aggregateCallResult{err: err} + } +} + +type aggregateExecutionGroup struct { + dataset dfmaterialization.FederatedDataset + access map[string]dfmaterialization.SourceAccess + calls []*aggregateCall +} + +func (s *Service) dispatchAggregateCalls(ctx context.Context, calls []*aggregateCall) { + started := time.Now() + if len(calls) == 0 { + return + } + if s.reader == nil { + for _, call := range calls { + call.result <- aggregateCallResult{err: readerUnavailable()} + } + return + } + principal, err := s.principal(ctx) + if err != nil { + for _, call := range calls { + call.result <- aggregateCallResult{err: mapReaderError(err)} + } + return + } + + groups := make(map[string]*aggregateExecutionGroup) + groupKeys := make([]string, 0) + for _, call := range calls { + dataset, access, resolveErr := s.authorizedFederation(ctx, principal, call.selector, call.filters) + if resolveErr != nil { + call.result <- aggregateCallResult{err: mapReaderError(resolveErr)} + continue + } + if len(dataset.Sources) == 0 { + call.result <- aggregateCallResult{err: dataframeerrors.NewError(dataframeerrors.CodeDatasetNotFound, "")} + continue + } + key := aggregateDatasetKey(dataset) + group := groups[key] + if group == nil { + group = &aggregateExecutionGroup{dataset: dataset, access: access} + groups[key] = group + groupKeys = append(groupKeys, key) + } + group.calls = append(group.calls, call) + } + sort.Strings(groupKeys) + + logicalJobs, deduplicated, statements, filterGroups, groupingStatements, scalarStatements, resultRows, sourceCount := 0, 0, 0, 0, 0, 0, 0, 0 + clickhouseStarted := time.Now() + for _, key := range groupKeys { + group := groups[key] + sourceCount += len(group.dataset.Sources) + jobs := make([]dfmaterialization.AggregateJob, 0) + callIDs := make(map[*aggregateCall][]int) + nextID := 0 + for _, call := range group.calls { + converted, convertErr := aggregateJobsForCall(call, nextID) + if convertErr != nil { + call.result <- aggregateCallResult{err: convertErr} + continue + } + ids := make([]int, len(converted)) + for index := range converted { + ids[index] = converted[index].ID + } + callIDs[call] = ids + nextID += len(converted) + jobs = append(jobs, converted...) + } + if len(jobs) == 0 { + continue + } + logicalJobs += len(jobs) + batch, batchErr := s.reader.ExecuteAggregateBatch(ctx, group.dataset, dfmaterialization.AggregateBatchRequest{ + Jobs: jobs, AccessByProject: group.access, + }) + deduplicated += batch.DeduplicatedJobs + statements += batch.Statements + filterGroups += batch.FilterGroups + groupingStatements += batch.GroupingStatements + scalarStatements += batch.ScalarStatements + if batchErr != nil { + for call := range callIDs { + call.result <- aggregateCallResult{err: mapReaderError(batchErr)} + } + continue + } + byID := make(map[int]dfmaterialization.AggregateJobResult, len(batch.Jobs)) + for _, job := range batch.Jobs { + byID[job.ID] = job + resultRows += len(job.Rows) + } + for call, ids := range callIDs { + s.completeAggregateCall(group.dataset, call, ids, byID) + } + } + clickhouseElapsed := time.Since(clickhouseStarted) + attrs := []any{ + "request_id", httpapi.RequestIDFromContext(ctx), + "logical_graphql_calls", len(calls), "logical_jobs", logicalJobs, + "deduplicated_jobs", deduplicated, "selector_groups", len(groups), + "filter_groups", filterGroups, "grouping_statements", groupingStatements, + "scalar_statements", scalarStatements, "clickhouse_calls", statements, + "source_count", sourceCount, "planning_ms", time.Since(started).Milliseconds() - clickhouseElapsed.Milliseconds(), + "clickhouse_ms", clickhouseElapsed.Milliseconds(), "result_rows", resultRows, + } + if statements > 5 { + s.logger.Warn("dataframe aggregate batch executed", attrs...) + } else { + s.logger.Info("dataframe aggregate batch executed", attrs...) + } +} + +func aggregateDatasetKey(dataset dfmaterialization.FederatedDataset) string { + ids := make([]string, 0, len(dataset.Sources)+len(dataset.ProjectStatuses)+2) + for _, source := range dataset.Sources { + ids = append(ids, "source:"+source.ID) + } + for _, status := range dataset.ProjectStatuses { + ids = append(ids, "project:"+status.ProjectID+":"+string(status.State)) + } + sort.Strings(ids) + return dataset.Selector.Key() + "\x00" + dataset.Revision + "\x00" + fmt.Sprint(dataset.ExpectedProjects) + "\x00" + strings.Join(ids, "\x1f") +} + +func aggregateJobsForCall(call *aggregateCall, firstID int) ([]dfmaterialization.AggregateJob, error) { + if call.kind == aggregateCallLegacy { + return []dfmaterialization.AggregateJob{{ + ID: firstID, ResponseMode: dfmaterialization.AggregateResponseLegacy, + Filters: call.filters, GroupBy: append([]string(nil), call.legacy.GroupBy...), + Operation: call.legacy.Operation, Column: stringValue(call.legacy.Column), + }}, nil + } + if len(call.rich.Specs) == 0 { + return nil, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") + } + if len(call.rich.Specs) > 50 { + return nil, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") + } + jobs := make([]dfmaterialization.AggregateJob, 0, len(call.rich.Specs)) + for _, spec := range call.rich.Specs { + if spec == nil { + return nil, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") + } + mode := dfmaterialization.AggregateResponseMode(strings.ToUpper(strings.TrimSpace(spec.Kind))) + switch mode { + case dfmaterialization.AggregateResponseTerms, dfmaterialization.AggregateResponseHistogram, + dfmaterialization.AggregateResponseDateHistogram, dfmaterialization.AggregateResponseStats, + dfmaterialization.AggregateResponseMissing: + default: + return nil, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") + } + filters := call.filters + if spec.ExcludeSelfFilter != nil && *spec.ExcludeSelfFilter { + filters = dfmaterialization.ExcludeSelfFilters(filters, spec.Column) + } + job := dfmaterialization.AggregateJob{ + ID: firstID + len(jobs), ResponseMode: mode, Filters: filters, + Column: spec.Column, + } + if spec.Size != nil { + job.Size = *spec.Size + } + if spec.Interval != nil { + job.Interval = *spec.Interval + } + if spec.DateInterval != nil { + job.DateInterval = *spec.DateInterval + } + jobs = append(jobs, job) + } + return jobs, nil +} + +func (s *Service) completeAggregateCall(dataset dfmaterialization.FederatedDataset, call *aggregateCall, ids []int, byID map[int]dfmaterialization.AggregateJobResult) { + if call.kind == aggregateCallLegacy { + job := byID[ids[0]] + if job.Err != nil { + call.result <- aggregateCallResult{err: mapReaderError(job.Err)} + return + } + call.result <- aggregateCallResult{legacy: dfmaterialization.AggregateResult{ + Materialization: federatedMaterialization(dataset), Columns: job.Columns, Rows: job.Rows, + }} + return + } + results := make([]dfmaterialization.AggregationResult, 0, len(ids)) + for index, id := range ids { + job := byID[id] + if job.Err != nil { + call.result <- aggregateCallResult{err: fmt.Errorf("aggregation %q: %w", call.rich.Specs[index].Name, mapReaderError(job.Err))} + return + } + spec := call.rich.Specs[index] + results = append(results, dfmaterialization.AggregationResult{ + Name: spec.Name, Kind: strings.ToUpper(strings.TrimSpace(spec.Kind)), + Columns: job.Columns, Rows: job.Rows, MissingCount: job.MissingCount, Truncated: job.Truncated, + }) + } + call.result <- aggregateCallResult{rich: dfmaterialization.AggregationsResult{ + Dataset: dataset, Aggregations: dfmaterialization.NormalizeAggregationResults(results), + }} +} diff --git a/internal/api/graphql/graph/materialization/aggregate_batch_test.go b/internal/api/graphql/graph/materialization/aggregate_batch_test.go new file mode 100644 index 00000000..6ce31e7e --- /dev/null +++ b/internal/api/graphql/graph/materialization/aggregate_batch_test.go @@ -0,0 +1,97 @@ +package materializationapi + +import ( + "context" + "sync" + "testing" + "time" +) + +func TestAggregateSchedulerDispatchesExpectedConcurrentCallsOnce(t *testing.T) { + batches := make(chan int, 2) + state := &aggregateOperationState{operationCtx: context.Background(), expectedCalls: 158} + state.dispatchCalls = func(_ context.Context, calls []*aggregateCall) { + batches <- len(calls) + for _, call := range calls { + call.result <- aggregateCallResult{} + } + } + var wait sync.WaitGroup + for range 158 { + wait.Add(1) + go func() { + defer wait.Done() + call := &aggregateCall{result: make(chan aggregateCallResult, 1)} + state.enqueue(call) + select { + case <-call.result: + case <-time.After(time.Second): + t.Error("aggregate call timed out") + } + }() + } + wait.Wait() + select { + case size := <-batches: + if size != 158 { + t.Fatalf("batch size = %d, want 158", size) + } + default: + t.Fatal("scheduler did not dispatch") + } + select { + case size := <-batches: + t.Fatalf("unexpected second batch of %d calls", size) + default: + } +} + +func TestAggregateSchedulerFallbackAndLateCallUseSeparateBatches(t *testing.T) { + batches := make(chan int, 2) + state := &aggregateOperationState{operationCtx: context.Background(), expectedCalls: 2} + state.dispatchCalls = func(_ context.Context, calls []*aggregateCall) { + batches <- len(calls) + for _, call := range calls { + call.result <- aggregateCallResult{} + } + } + first := &aggregateCall{result: make(chan aggregateCallResult, 1)} + state.enqueue(first) + select { + case size := <-batches: + if size != 1 { + t.Fatalf("fallback batch size = %d", size) + } + case <-time.After(100 * time.Millisecond): + t.Fatal("fallback did not dispatch") + } + second := &aggregateCall{result: make(chan aggregateCallResult, 1)} + state.enqueue(second) + select { + case size := <-batches: + if size != 1 { + t.Fatalf("late batch size = %d", size) + } + case <-time.After(100 * time.Millisecond): + t.Fatal("late call did not dispatch") + } +} + +func TestAggregateSchedulerCancellationReleasesPendingCalls(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + state := &aggregateOperationState{operationCtx: ctx, expectedCalls: 2} + call := &aggregateCall{result: make(chan aggregateCallResult, 1)} + state.mu.Lock() + state.pending = append(state.pending, call) + state.mu.Unlock() + cancel() + state.cancelPending(ctx.Err()) + select { + case result := <-call.result: + if result.err != context.Canceled { + t.Fatalf("cancellation error = %v", result.err) + } + case <-time.After(time.Second): + t.Fatal("canceled call remained blocked") + } +} diff --git a/internal/api/graphql/graph/materialization/operation_cache.go b/internal/api/graphql/graph/materialization/operation_cache.go new file mode 100644 index 00000000..528eb98c --- /dev/null +++ b/internal/api/graphql/graph/materialization/operation_cache.go @@ -0,0 +1,107 @@ +package materializationapi + +import ( + "context" + "sort" + "strings" + + httpapi "github.com/calypr/loom/internal/api/http" + "github.com/calypr/loom/internal/authscope" + dfmaterialization "github.com/calypr/loom/internal/dataframe/published" +) + +type projectsCacheEntry struct { + ready chan struct{} + projects []string + err error +} + +type federationCacheEntry struct { + ready chan struct{} + dataset dfmaterialization.FederatedDataset + access map[string]dfmaterialization.SourceAccess + err error +} + +func (s *Service) projects(ctx context.Context, principal *authscope.Principal) ([]string, error) { + state := aggregateStateFromContext(ctx) + if state == nil || state.service != s { + return s.projectsUncached(ctx, principal) + } + state.mu.Lock() + if entry := state.projects; entry != nil { + state.mu.Unlock() + if s.logger != nil { + s.logger.Debug("dataframe project discovery cache wait", "request_id", httpapi.RequestIDFromContext(ctx)) + } + select { + case <-entry.ready: + return append([]string(nil), entry.projects...), entry.err + case <-ctx.Done(): + return nil, ctx.Err() + } + } + entry := &projectsCacheEntry{ready: make(chan struct{})} + state.projects = entry + state.mu.Unlock() + if s.logger != nil { + s.logger.Debug("dataframe project discovery cache miss", "request_id", httpapi.RequestIDFromContext(ctx)) + } + + entry.projects, entry.err = s.projectsUncached(ctx, principal) + entry.projects = append([]string(nil), entry.projects...) + close(entry.ready) + if s.logger != nil { + s.logger.Debug("dataframe project discovery resolved", "request_id", httpapi.RequestIDFromContext(ctx), "project_count", len(entry.projects), "error", entry.err) + } + return append([]string(nil), entry.projects...), entry.err +} + +func (s *Service) authorizedFederation(ctx context.Context, principal *authscope.Principal, selector dfmaterialization.DataframeSelector, filters []dfmaterialization.Filter) (dfmaterialization.FederatedDataset, map[string]dfmaterialization.SourceAccess, error) { + candidates, err := s.projects(ctx, principal) + if err != nil { + s.logReadFailure(ctx, "authorized_project_discovery", selector.Output, err) + return dfmaterialization.FederatedDataset{}, nil, mapReaderError(err) + } + candidates = filterProjects(candidates, filters) + key := federationCacheKey(selector, candidates) + state := aggregateStateFromContext(ctx) + if state == nil || state.service != s { + return s.authorizedFederationUncached(ctx, principal, selector, candidates) + } + state.mu.Lock() + if entry := state.federations[key]; entry != nil { + state.mu.Unlock() + if s.logger != nil { + s.logger.Debug("dataframe federation cache wait", "request_id", httpapi.RequestIDFromContext(ctx), "selector", selector.Key(), "candidate_project_count", len(candidates)) + } + select { + case <-entry.ready: + return entry.dataset, entry.access, entry.err + case <-ctx.Done(): + return dfmaterialization.FederatedDataset{}, nil, ctx.Err() + } + } + entry := &federationCacheEntry{ready: make(chan struct{})} + state.federations[key] = entry + state.mu.Unlock() + if s.logger != nil { + s.logger.Debug("dataframe federation cache miss", "request_id", httpapi.RequestIDFromContext(ctx), "selector", selector.Key(), "candidate_project_count", len(candidates)) + } + + entry.dataset, entry.access, entry.err = s.authorizedFederationUncached(ctx, principal, selector, candidates) + close(entry.ready) + if s.logger != nil { + s.logger.Debug("dataframe federation resolved", "request_id", httpapi.RequestIDFromContext(ctx), "selector", selector.Key(), "source_count", len(entry.dataset.Sources), "authorized_project_count", len(entry.access), "error", entry.err) + } + return entry.dataset, entry.access, entry.err +} + +func federationCacheKey(selector dfmaterialization.DataframeSelector, projects []string) string { + values := append([]string(nil), projects...) + for i := range values { + values[i] = strings.TrimSpace(values[i]) + } + sort.Strings(values) + return selector.Key() + "\x00" + strings.Join(values, "\x1f") +} diff --git a/internal/api/graphql/graph/materialization/operation_cache_test.go b/internal/api/graphql/graph/materialization/operation_cache_test.go new file mode 100644 index 00000000..0b864f35 --- /dev/null +++ b/internal/api/graphql/graph/materialization/operation_cache_test.go @@ -0,0 +1,45 @@ +package materializationapi + +import ( + "context" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/calypr/loom/internal/authscope" +) + +func TestProjectsCacheSharesInflightResolutionPerOperation(t *testing.T) { + var calls atomic.Int32 + service := NewService(Config{CandidateProjects: func(context.Context) ([]string, error) { + calls.Add(1) + time.Sleep(time.Millisecond) + return []string{"project"}, nil + }}) + ctx := service.WithOperationContext(context.Background(), 0) + principal := &authscope.Principal{Subject: "subject"} + var wait sync.WaitGroup + for range 32 { + wait.Add(1) + go func() { + defer wait.Done() + projects, err := service.projects(ctx, principal) + if err != nil || len(projects) != 1 || projects[0] != "project" { + t.Errorf("projects = %#v, err = %v", projects, err) + } + }() + } + wait.Wait() + if calls.Load() != 1 { + t.Fatalf("candidate project calls = %d, want 1", calls.Load()) + } + + second := service.WithOperationContext(context.Background(), 0) + if _, err := service.projects(second, principal); err != nil { + t.Fatal(err) + } + if calls.Load() != 2 { + t.Fatalf("cache crossed operation contexts: calls = %d", calls.Load()) + } +} diff --git a/internal/api/graphql/graph/materialization/service.go b/internal/api/graphql/graph/materialization/service.go index 34946eaf..5b96ea11 100644 --- a/internal/api/graphql/graph/materialization/service.go +++ b/internal/api/graphql/graph/materialization/service.go @@ -56,7 +56,7 @@ func (s *Service) principal(ctx context.Context) (*authscope.Principal, error) { return principal, nil } -func (s *Service) projects(ctx context.Context, principal *authscope.Principal) ([]string, error) { +func (s *Service) projectsUncached(ctx context.Context, principal *authscope.Principal) ([]string, error) { if len(principal.Projects) > 0 { return append([]string(nil), principal.Projects...), nil } @@ -203,94 +203,31 @@ func (s *Service) Rows(ctx context.Context, input model.DataframeRowsInput) (dfm } func (s *Service) AggregateInput(ctx context.Context, input model.DataframeAggregateInput) (dfmaterialization.AggregateResult, error) { - if s.reader == nil { - return dfmaterialization.AggregateResult{}, readerUnavailable() - } selector, err := resolveSelector(input.Selector) if err != nil { return dfmaterialization.AggregateResult{}, err } - principal, err := s.principal(ctx) - if err != nil { - s.logReadFailure(ctx, "principal_resolution", selector.Output, err) - return dfmaterialization.AggregateResult{}, mapReaderError(err) - } - dataset, access, err := s.authorizedFederation(ctx, principal, selector, convertFilters(input.Filters)) - if err != nil { - s.logReadFailure(ctx, "federated_publication_resolution", selector.Output, err) - return dfmaterialization.AggregateResult{}, mapReaderError(err) + result := s.submitAggregateCall(ctx, &aggregateCall{kind: aggregateCallLegacy, selector: selector, filters: convertFilters(input.Filters), legacy: input}) + if result.err != nil { + s.logReadFailure(ctx, "federated_clickhouse_aggregate", selector.Output, result.err) } - if len(dataset.Sources) == 0 { - return dfmaterialization.AggregateResult{}, dataframeerrors.NewError(dataframeerrors.CodeDatasetNotFound, "") - } - result, err := s.reader.AggregateFederatedDataset(ctx, dataset, dfmaterialization.FederatedAggregateRequest{ - GroupBy: input.GroupBy, Filters: convertFilters(input.Filters), Operation: input.Operation, Column: stringValue(input.Column), AccessByProject: access, - }) - if err != nil { - s.logReadFailure(ctx, "federated_clickhouse_aggregate", selector.Output, err, "source_ids", materializationIDs(dataset.Sources), "physical_tables", physicalTables(dataset.Sources)) - return dfmaterialization.AggregateResult{}, mapReaderError(err) - } - result.Dataset = dataset - return dfmaterialization.AggregateResult{Materialization: federatedMaterialization(result.Dataset), Columns: result.Columns, Rows: result.Rows}, nil + return result.legacy, result.err } func (s *Service) AggregationsInput(ctx context.Context, input model.DataframeAggregationsInput) (dfmaterialization.AggregationsResult, error) { - if s.reader == nil { - return dfmaterialization.AggregationsResult{}, readerUnavailable() - } selector, err := resolveSelector(input.Selector) if err != nil { return dfmaterialization.AggregationsResult{}, err } - principal, err := s.principal(ctx) - if err != nil { - return dfmaterialization.AggregationsResult{}, mapReaderError(err) - } - dataset, access, err := s.authorizedFederation(ctx, principal, selector, convertFilters(input.Filters)) - if err != nil { - return dfmaterialization.AggregationsResult{}, mapReaderError(err) - } - if len(dataset.Sources) == 0 { - return dfmaterialization.AggregationsResult{}, dataframeerrors.NewError(dataframeerrors.CodeDatasetNotFound, "") - } - specs := make([]dfmaterialization.AggregationSpec, 0, len(input.Specs)) - for _, spec := range input.Specs { - if spec == nil { - continue - } - value := dfmaterialization.AggregationSpec{Name: spec.Name, Kind: spec.Kind, Column: spec.Column, ExcludeSelfFilter: spec.ExcludeSelfFilter != nil && *spec.ExcludeSelfFilter} - if spec.Size != nil { - value.Size = *spec.Size - } - if spec.Interval != nil { - value.Interval = *spec.Interval - } - if spec.DateInterval != nil { - value.DateInterval = *spec.DateInterval - } - specs = append(specs, value) - } - result, err := s.reader.AggregateFederatedBatchDataset(ctx, dataset, dfmaterialization.AggregationsRequest{ - Filters: convertFilters(input.Filters), Specs: specs, AccessByProject: access, - }) - if err != nil { - return dfmaterialization.AggregationsResult{}, err - } - result.Dataset = dataset - return result, nil + result := s.submitAggregateCall(ctx, &aggregateCall{kind: aggregateCallRich, selector: selector, filters: convertFilters(input.Filters), rich: input}) + return result.rich, result.err } func AggregationsJSON(result dfmaterialization.AggregationsResult) (json.RawMessage, error) { return json.Marshal(dfmaterialization.NormalizeAggregationResults(result.Aggregations)) } -func (s *Service) authorizedFederation(ctx context.Context, principal *authscope.Principal, selector dfmaterialization.DataframeSelector, filters []dfmaterialization.Filter) (dfmaterialization.FederatedDataset, map[string]dfmaterialization.SourceAccess, error) { - candidates, err := s.projects(ctx, principal) - if err != nil { - s.logReadFailure(ctx, "authorized_project_discovery", selector.Output, err) - return dfmaterialization.FederatedDataset{}, nil, mapReaderError(err) - } - candidates = filterProjects(candidates, filters) +func (s *Service) authorizedFederationUncached(ctx context.Context, principal *authscope.Principal, selector dfmaterialization.DataframeSelector, candidates []string) (dfmaterialization.FederatedDataset, map[string]dfmaterialization.SourceAccess, error) { sources, err := s.reader.CurrentFederatedSources(ctx, candidates, selector) if err != nil { s.logReadFailure(ctx, "published_source_discovery", selector.Output, err, "projects", candidates) diff --git a/internal/api/graphql/graph/resolver/fhir_reference_loader.go b/internal/api/graphql/graph/resolver/fhir_reference_loader.go index eca0e091..40a28121 100644 --- a/internal/api/graphql/graph/resolver/fhir_reference_loader.go +++ b/internal/api/graphql/graph/resolver/fhir_reference_loader.go @@ -69,11 +69,6 @@ func withFHIRReferenceLoader(ctx context.Context, resolver *Resolver) context.Co }) } -// WithOperationContext installs request-scoped FHIR reference batching. -func (r *Resolver) WithOperationContext(ctx context.Context) context.Context { - return withFHIRReferenceLoader(ctx, r) -} - func fhirReferenceLoaderFromContext(ctx context.Context, resolver *Resolver) *fhirReferenceLoader { if loader, ok := ctx.Value(fhirReferenceLoaderKey{}).(*fhirReferenceLoader); ok { return loader diff --git a/internal/api/graphql/graph/resolver/operation_context.go b/internal/api/graphql/graph/resolver/operation_context.go new file mode 100644 index 00000000..8b961a73 --- /dev/null +++ b/internal/api/graphql/graph/resolver/operation_context.go @@ -0,0 +1,36 @@ +package resolver + +import ( + "context" + + "github.com/99designs/gqlgen/graphql" + "github.com/vektah/gqlparser/v2/ast" +) + +// WithOperationContext installs all request-scoped loaders and aggregate +// scheduling state at gqlgen's operation boundary. +func (r *Resolver) WithOperationContext(ctx context.Context) context.Context { + ctx = withFHIRReferenceLoader(ctx, r) + if r.materializations != nil { + ctx = r.materializations.WithOperationContext(ctx, aggregateRootFieldCount(ctx)) + } + return ctx +} + +func aggregateRootFieldCount(ctx context.Context) int { + if !graphql.HasOperationContext(ctx) { + return 0 + } + op := graphql.GetOperationContext(ctx) + if op == nil || op.Operation == nil || op.Operation.Operation != ast.Query { + return 0 + } + fields := graphql.CollectFields(op, op.Operation.SelectionSet, []string{"Query"}) + count := 0 + for _, field := range fields { + if field.Name == "dataframeAggregate" || field.Name == "dataframeAggregations" { + count++ + } + } + return count +} diff --git a/internal/dataframe/published/aggregate_clickhouse_integration_test.go b/internal/dataframe/published/aggregate_clickhouse_integration_test.go new file mode 100644 index 00000000..31d3ed75 --- /dev/null +++ b/internal/dataframe/published/aggregate_clickhouse_integration_test.go @@ -0,0 +1,105 @@ +package published + +import ( + "context" + "os" + "testing" + "time" + + storeclickhouse "github.com/calypr/loom/internal/store/clickhouse" + "github.com/google/uuid" +) + +func TestAggregateBatchClickHouseIntegration(t *testing.T) { + url := os.Getenv("LOOM_CLICKHOUSE_URL") + if url == "" { + t.Skip("LOOM_CLICKHOUSE_URL is not set") + } + database := os.Getenv("LOOM_CLICKHOUSE_DATABASE") + if database == "" { + database = "loom_test" + } + client, err := storeclickhouse.New(storeclickhouse.Options{ + URL: url, Database: database, + Username: os.Getenv("LOOM_CLICKHOUSE_USERNAME"), + Password: os.Getenv("LOOM_CLICKHOUSE_PASSWORD"), + Timeout: 10 * time.Second, + }) + if err != nil { + t.Fatal(err) + } + defer client.Close() + ctx := context.Background() + if err := client.EnsureDatabase(ctx); err != nil { + t.Fatal(err) + } + tableA := "loom_aggregate_a_" + uuid.NewString()[:8] + tableB := "loom_aggregate_b_" + uuid.NewString()[:8] + defer client.DropTable(ctx, tableA) + defer client.DropTable(ctx, tableB) + physicalColumns := []storeclickhouse.Column{ + {Name: "__loom_row_id", Type: "UInt64"}, + {Name: "facet", Type: "Nullable(String)"}, + {Name: "value", Type: "Nullable(Float64)"}, + {Name: "auth_resource_path", Type: "String"}, + } + for _, table := range []string{tableA, tableB} { + if err := client.CreateTable(ctx, table, physicalColumns); err != nil { + t.Fatal(err) + } + } + if err := client.InsertRows(ctx, tableA, physicalColumns, []map[string]any{ + {"__loom_row_id": uint64(1), "facet": "a", "value": 2.0, "auth_resource_path": "allowed"}, + {"__loom_row_id": uint64(2), "facet": nil, "value": 3.0, "auth_resource_path": "allowed"}, + {"__loom_row_id": uint64(3), "facet": "secret", "value": 100.0, "auth_resource_path": "denied"}, + }); err != nil { + t.Fatal(err) + } + if err := client.InsertRows(ctx, tableB, physicalColumns, []map[string]any{ + {"__loom_row_id": uint64(1), "facet": "b", "value": 5.0, "auth_resource_path": "anything"}, + }); err != nil { + t.Fatal(err) + } + sourceColumns := []Column{ + {Name: "__loom_row_id", ClickHouse: "UInt64"}, + {Name: "facet", ClickHouse: "Nullable(String)"}, + {Name: "value", ClickHouse: "Nullable(Float64)"}, + {Name: authResourcePathColumn, ClickHouse: "String"}, + } + dataset := FederatedDataset{ + Columns: []Column{ + {Name: "facet", ClickHouse: "Nullable(String)"}, + {Name: "value", ClickHouse: "Nullable(Float64)"}, + {Name: projectIDColumn, ClickHouse: "String"}, + }, + Sources: []Materialization{ + {ID: "a:Patient", Project: "a", PhysicalTable: tableA, Columns: sourceColumns}, + {ID: "b:Patient", Project: "b", PhysicalTable: tableB, Columns: sourceColumns}, + }, + } + result, err := (&Reader{ClickHouse: client}).ExecuteAggregateBatch(ctx, dataset, AggregateBatchRequest{ + Jobs: []AggregateJob{ + {ID: 1, ResponseMode: AggregateResponseLegacy, GroupBy: []string{"facet"}, Operation: "COUNT"}, + {ID: 2, ResponseMode: AggregateResponseLegacy, Operation: "COUNT"}, + {ID: 3, ResponseMode: AggregateResponseLegacy, Operation: "SUM", Column: "value"}, + }, + AccessByProject: map[string]SourceAccess{ + "a": {ResourcePaths: []string{"allowed"}}, + "b": {Unrestricted: true}, + }, + }) + if err != nil { + t.Fatal(err) + } + for _, job := range result.Jobs { + if job.Err != nil { + t.Fatalf("job %d: %v", job.ID, job.Err) + } + } + if len(result.Jobs[0].Rows) != 3 { + t.Fatalf("grouped rows = %#v", result.Jobs[0].Rows) + } + if got, err := numericCount(result.Jobs[1].Rows[0]["count"]); err != nil || got != 3 { + t.Fatalf("ungrouped count = %v, err = %v", result.Jobs[1].Rows, err) + } +} diff --git a/internal/dataframe/published/aggregate_execute.go b/internal/dataframe/published/aggregate_execute.go new file mode 100644 index 00000000..5795f94a --- /dev/null +++ b/internal/dataframe/published/aggregate_execute.go @@ -0,0 +1,447 @@ +package published + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "math/big" + "sort" + "strconv" + "strings" + "time" + + dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" +) + +func (r *Reader) ExecuteAggregateBatch(ctx context.Context, dataset FederatedDataset, req AggregateBatchRequest) (AggregateBatchResult, error) { + result := AggregateBatchResult{LogicalJobs: len(req.Jobs)} + if r == nil || r.ClickHouse == nil { + return result, dataframeerrors.NewError(dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) + } + if err := ctx.Err(); err != nil { + return result, err + } + seenIDs := make(map[int]struct{}, len(req.Jobs)) + for _, job := range req.Jobs { + if _, exists := seenIDs[job.ID]; exists { + return result, fmt.Errorf("aggregate planner invariant: duplicate job ID %d", job.ID) + } + seenIDs[job.ID] = struct{}{} + } + plan := buildAggregatePlan(dataset, req) + result.DeduplicatedJobs = len(plan.jobs) + filterGroups := make(map[string]struct{}) + for _, statement := range plan.statements { + if len(statement.jobs) > 0 { + filterGroups[statement.jobs[0].filterKey] = struct{}{} + } + } + result.FilterGroups = len(filterGroups) + if r.Logger != nil { + r.Logger.Debug("dataframe aggregate plan built", + "selector", dataset.Selector.Key(), + "source_count", len(dataset.Sources), + "logical_jobs", result.LogicalJobs, + "valid_jobs", len(plan.jobs), + "deduplicated_jobs", result.DeduplicatedJobs, + "statement_count", len(plan.statements), + "filter_groups", result.FilterGroups, + ) + } + for _, statement := range plan.statements { + if err := ctx.Err(); err != nil { + return assembleAggregateBatchResult(req.Jobs, plan, result), err + } + sql, err := buildAggregateSQL(dataset, req.AccessByProject, statement) + if err != nil { + setStatementError(plan.results, statement, err) + continue + } + result.Statements++ + if statement.kind == statementScalar { + result.ScalarStatements++ + } else { + result.GroupingStatements++ + } + statementStarted := time.Now() + if r.Logger != nil { + r.Logger.Debug("dataframe aggregate statement started", + "selector", dataset.Selector.Key(), + "statement_kind", string(statement.kind), + "job_count", len(statement.jobs), + "grouping_sets", sql.groupingSets, + "source_count", len(dataset.Sources), + "source_column_count", len(sql.sourceColumns), + "query_id", shortQueryID(sql.query), + "query_bytes", len(sql.query), + "bind_count", len(sql.args), + ) + } + rows, err := r.ClickHouse.QueryRowsArgs(ctx, sql.query, sql.columns, sql.args...) + if err != nil { + if r.Logger != nil { + r.Logger.Error("clickhouse federated aggregate failed", + "selector", dataset.Selector.Key(), + "statement_kind", string(statement.kind), + "job_count", len(statement.jobs), + "grouping_sets", sql.groupingSets, + "source_count", len(dataset.Sources), + "source_column_count", len(sql.sourceColumns), + "query_id", shortQueryID(sql.query), + "query_bytes", len(sql.query), + "bind_count", len(sql.args), + "duration_ms", time.Since(statementStarted).Milliseconds(), + "failure_class", aggregateFailureClass(err), + "error", err, + ) + } + if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) || ctx.Err() != nil { + if ctx.Err() != nil { + return assembleAggregateBatchResult(req.Jobs, plan, result), ctx.Err() + } + return assembleAggregateBatchResult(req.Jobs, plan, result), err + } + setStatementError(plan.results, statement, backendCallError(err)) + continue + } + if err := decodeAggregateStatement(plan.results, statement, rows); err != nil { + setStatementError(plan.results, statement, err) + if r.Logger != nil { + r.Logger.Error("dataframe aggregate statement decode failed", + "selector", dataset.Selector.Key(), + "statement_kind", string(statement.kind), + "job_count", len(statement.jobs), + "query_id", shortQueryID(sql.query), + "duration_ms", time.Since(statementStarted).Milliseconds(), + "result_rows", len(rows), + "error", err, + ) + } + } else if r.Logger != nil { + r.Logger.Debug("dataframe aggregate statement completed", + "selector", dataset.Selector.Key(), + "statement_kind", string(statement.kind), + "job_count", len(statement.jobs), + "grouping_sets", sql.groupingSets, + "query_id", shortQueryID(sql.query), + "duration_ms", time.Since(statementStarted).Milliseconds(), + "result_rows", len(rows), + ) + } + } + return assembleAggregateBatchResult(req.Jobs, plan, result), nil +} + +func aggregateFailureClass(err error) string { + if err == nil { + return "" + } + message := strings.ToLower(err.Error()) + switch { + case strings.Contains(message, "memory limit exceeded"), strings.Contains(message, "overcommittracker"): + return "memory_limit" + case strings.Contains(message, "timeout"), strings.Contains(message, "deadline exceeded"): + return "timeout" + case strings.Contains(message, "cancel"): + return "canceled" + default: + return "clickhouse" + } +} + +func setStatementError(results map[int]AggregateJobResult, statement aggregateStatementPlan, err error) { + for _, job := range statement.jobs { + for _, id := range job.aliases { + results[id] = AggregateJobResult{ID: id, Err: err} + } + } +} + +func decodeAggregateStatement(results map[int]AggregateJobResult, statement aggregateStatementPlan, rows []map[string]any) error { + if statement.kind == statementScalar { + return decodeScalarStatement(results, statement, rows) + } + return decodeGroupedStatement(results, statement, rows) +} + +func decodeGroupedStatement(results map[int]AggregateJobResult, statement aggregateStatementPlan, rows []map[string]any) error { + bySlot := make([][]map[string]any, len(statement.jobs)) + missing := make([]int64, len(statement.jobs)) + for _, row := range rows { + slot64, err := numericCount(row["__loom_slot"]) + if err != nil || slot64 < 0 || int(slot64) >= len(statement.jobs) { + return fmt.Errorf("ClickHouse aggregate returned invalid slot %v", row["__loom_slot"]) + } + slot := int(slot64) + keys, err := decodeGroupJSON(row["__loom_group_json"]) + if err != nil { + return err + } + planned := statement.jobs[slot] + switch statement.kind { + case statementTerms: + if len(keys) != 1 { + return fmt.Errorf("ClickHouse aggregate returned %d group keys, want 1", len(keys)) + } + key := keys[0] + if key == nil { + count, countErr := numericCount(row["__loom_metric"]) + if countErr != nil { + return countErr + } + missing[slot] += count + continue + } + bySlot[slot] = append(bySlot[slot], map[string]any{"key": key, "doc_count": row["__loom_metric"]}) + case statementBucket: + if len(keys) != 1 { + return fmt.Errorf("ClickHouse aggregate returned %d group keys, want 1", len(keys)) + } + bySlot[slot] = append(bySlot[slot], map[string]any{"key": keys[0], "doc_count": row["__loom_metric"]}) + default: + if len(keys) != len(planned.job.GroupBy) { + return fmt.Errorf("ClickHouse aggregate returned %d group keys, want %d", len(keys), len(planned.job.GroupBy)) + } + value := make(map[string]any, len(planned.job.GroupBy)+1) + for index, column := range planned.job.GroupBy { + value[column] = keys[index] + } + value[legacyMetricName(planned.job.Operation)] = row["__loom_metric"] + bySlot[slot] = append(bySlot[slot], value) + } + } + for slot, planned := range statement.jobs { + jobRows := bySlot[slot] + columns := append([]string(nil), planned.job.GroupBy...) + truncated := false + switch statement.kind { + case statementTerms: + columns = []string{"key", "doc_count"} + sort.SliceStable(jobRows, func(i, j int) bool { + left, _ := numericCount(jobRows[i]["doc_count"]) + right, _ := numericCount(jobRows[j]["doc_count"]) + if left != right { + return left > right + } + return compareAggregateValues(jobRows[i]["key"], jobRows[j]["key"]) < 0 + }) + truncated = len(jobRows) > planned.job.Size + if truncated { + jobRows = jobRows[:planned.job.Size] + } + case statementBucket: + columns = []string{"key", "doc_count"} + sort.SliceStable(jobRows, func(i, j int) bool { + return compareAggregateValues(jobRows[i]["key"], jobRows[j]["key"]) < 0 + }) + truncated = len(jobRows) >= planned.job.Size + default: + columns = append(columns, legacyMetricName(planned.job.Operation)) + sort.SliceStable(jobRows, func(i, j int) bool { + for _, column := range planned.job.GroupBy { + if compared := compareAggregateValues(jobRows[i][column], jobRows[j][column]); compared != 0 { + return compared < 0 + } + } + return false + }) + } + fanoutJobResult(results, planned, AggregateJobResult{ + ID: planned.job.ID, Columns: columns, Rows: jobRows, + MissingCount: missing[slot], Truncated: truncated, + }) + } + return nil +} + +func decodeScalarStatement(results map[int]AggregateJobResult, statement aggregateStatementPlan, rows []map[string]any) error { + row := map[string]any{} + if len(rows) > 0 { + row = rows[0] + } + for slot, planned := range statement.jobs { + if planned.job.ResponseMode == AggregateResponseStats { + columns := []string{"count", "value_count", "distinct_count", "min", "max", "sum", "avg"} + output := make(map[string]any, len(columns)) + for _, column := range columns { + output[column] = row[fmt.Sprintf("__loom_%d_%s", slot, column)] + } + fanoutJobResult(results, planned, AggregateJobResult{ID: planned.job.ID, Columns: columns, Rows: []map[string]any{output}}) + continue + } + value := row[fmt.Sprintf("__loom_%d_missing_count", slot)] + if value == nil { + value = int64(0) + } + if planned.job.ResponseMode == AggregateResponseTerms { + missing, err := numericCount(value) + if err != nil { + return err + } + for _, id := range planned.aliases { + result := results[id] + result.MissingCount = missing + results[id] = result + } + continue + } + fanoutJobResult(results, planned, AggregateJobResult{ID: planned.job.ID, Columns: []string{"missing_count"}, Rows: []map[string]any{{"missing_count": value}}}) + } + return nil +} + +func fanoutJobResult(results map[int]AggregateJobResult, job *plannedAggregateJob, base AggregateJobResult) { + for _, id := range job.aliases { + copyResult := base + copyResult.ID = id + copyResult.Columns = append([]string(nil), base.Columns...) + copyResult.Rows = cloneAggregateRows(base.Rows) + results[id] = copyResult + } +} + +func assembleAggregateBatchResult(inputs []AggregateJob, plan aggregatePlan, result AggregateBatchResult) AggregateBatchResult { + result.Jobs = make([]AggregateJobResult, 0, len(inputs)) + for _, input := range inputs { + value, ok := plan.results[input.ID] + if !ok { + value = AggregateJobResult{ID: input.ID, Err: fmt.Errorf("aggregate job did not produce a result")} + } + result.Jobs = append(result.Jobs, value) + } + return result +} + +func cloneAggregateRows(rows []map[string]any) []map[string]any { + result := make([]map[string]any, len(rows)) + for i, row := range rows { + result[i] = make(map[string]any, len(row)) + for key, value := range row { + result[i][key] = value + } + } + return result +} + +func legacyMetricName(operation string) string { + if operation == "" { + return "count" + } + return strings.ToLower(operation) +} + +func decodeGroupJSON(value any) ([]any, error) { + if values, ok := value.([]any); ok { + return values, nil + } + var data []byte + switch typed := value.(type) { + case string: + data = []byte(typed) + case []byte: + data = typed + default: + encoded, err := json.Marshal(value) + if err != nil { + return nil, err + } + data = encoded + } + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.UseNumber() + var result []any + if err := decoder.Decode(&result); err != nil { + return nil, fmt.Errorf("decode aggregate group key: %w", err) + } + return result, nil +} + +func compareAggregateValues(left, right any) int { + if left == nil && right == nil { + return 0 + } + if left == nil { + return 1 + } + if right == nil { + return -1 + } + if lnum, ok := aggregateNumber(left); ok { + if rnum, ok := aggregateNumber(right); ok { + return lnum.Cmp(rnum) + } + } + if lbool, ok := left.(bool); ok { + if rbool, ok := right.(bool); ok { + if lbool == rbool { + return 0 + } + if !lbool { + return -1 + } + return 1 + } + } + if lstr, ok := left.(string); ok { + if rstr, ok := right.(string); ok { + return strings.Compare(lstr, rstr) + } + } + if larray, ok := left.([]any); ok { + if rarray, ok := right.([]any); ok { + for i := 0; i < len(larray) && i < len(rarray); i++ { + if compared := compareAggregateValues(larray[i], rarray[i]); compared != 0 { + return compared + } + } + if len(larray) < len(rarray) { + return -1 + } + if len(larray) > len(rarray) { + return 1 + } + return 0 + } + } + ljson, _ := json.Marshal(left) + rjson, _ := json.Marshal(right) + return bytes.Compare(ljson, rjson) +} + +func aggregateNumber(value any) (*big.Rat, bool) { + var text string + switch typed := value.(type) { + case json.Number: + text = string(typed) + case int: + text = strconv.Itoa(typed) + case int8: + text = strconv.FormatInt(int64(typed), 10) + case int16: + text = strconv.FormatInt(int64(typed), 10) + case int32: + text = strconv.FormatInt(int64(typed), 10) + case int64: + text = strconv.FormatInt(typed, 10) + case uint: + text = strconv.FormatUint(uint64(typed), 10) + case uint8: + text = strconv.FormatUint(uint64(typed), 10) + case uint16: + text = strconv.FormatUint(uint64(typed), 10) + case uint32: + text = strconv.FormatUint(uint64(typed), 10) + case uint64: + text = strconv.FormatUint(typed, 10) + case float32: + text = strconv.FormatFloat(float64(typed), 'g', -1, 32) + case float64: + text = strconv.FormatFloat(typed, 'g', -1, 64) + default: + return nil, false + } + valueRat, ok := new(big.Rat).SetString(text) + return valueRat, ok +} diff --git a/internal/dataframe/published/aggregate_execute_test.go b/internal/dataframe/published/aggregate_execute_test.go new file mode 100644 index 00000000..e11921f8 --- /dev/null +++ b/internal/dataframe/published/aggregate_execute_test.go @@ -0,0 +1,74 @@ +package published + +import ( + "context" + "encoding/json" + "strings" + "testing" +) + +func TestExecuteAggregateBatchRichShapesShareScans(t *testing.T) { + dataset := aggregateTestDataset(1) + fake := &aggregateFakeQueryer{rows: [][]map[string]any{ + { + {"__loom_slot": int64(0), "__loom_group_json": "[\"a\"]", "__loom_metric": int64(5)}, + {"__loom_slot": int64(0), "__loom_group_json": "[\"b\"]", "__loom_metric": int64(3)}, + {"__loom_slot": int64(0), "__loom_group_json": "[\"c\"]", "__loom_metric": int64(1)}, + }, + {{ + "__loom_0_count": int64(9), "__loom_0_value_count": int64(8), "__loom_0_distinct_count": int64(3), + "__loom_0_min": "a", "__loom_0_max": "z", "__loom_0_sum": nil, "__loom_0_avg": nil, + "__loom_1_missing_count": int64(1), "__loom_2_missing_count": int64(4), + }}, + }} + result, err := (&Reader{ClickHouse: fake}).ExecuteAggregateBatch(context.Background(), dataset, AggregateBatchRequest{ + Jobs: []AggregateJob{ + {ID: 1, ResponseMode: AggregateResponseTerms, Column: "facet_000", Size: 2}, + {ID: 2, ResponseMode: AggregateResponseStats, Column: "facet_000"}, + {ID: 3, ResponseMode: AggregateResponseMissing, Column: "facet_000"}, + }, + AccessByProject: map[string]SourceAccess{"project": {Unrestricted: true}}, + }) + if err != nil { + t.Fatal(err) + } + if result.Statements != 2 || result.GroupingStatements != 1 || result.ScalarStatements != 1 { + t.Fatalf("statement counts = %#v", result) + } + if len(result.Jobs[0].Rows) != 2 || !result.Jobs[0].Truncated || result.Jobs[0].MissingCount != 4 { + t.Fatalf("terms result = %#v", result.Jobs[0]) + } + if result.Jobs[1].Rows[0]["distinct_count"] != int64(3) { + t.Fatalf("stats result = %#v", result.Jobs[1]) + } + if result.Jobs[2].Rows[0]["missing_count"] != int64(1) { + t.Fatalf("missing result = %#v", result.Jobs[2]) + } + if !strings.Contains(fake.calls[0].query, "row_number() OVER") { + t.Fatalf("terms statement does not rank in ClickHouse: %s", fake.calls[0].query) + } +} + +func TestExecuteAggregateBatchUsesTypedMultiColumnOrdering(t *testing.T) { + dataset := aggregateTestDataset(2) + fake := &aggregateFakeQueryer{rows: [][]map[string]any{{ + {"__loom_slot": int64(0), "__loom_group_json": "[10,\"b\"]", "__loom_metric": int64(1)}, + {"__loom_slot": int64(0), "__loom_group_json": "[2,\"z\"]", "__loom_metric": int64(1)}, + {"__loom_slot": int64(0), "__loom_group_json": "[2,\"a\"]", "__loom_metric": int64(1)}, + {"__loom_slot": int64(0), "__loom_group_json": "[null,\"a\"]", "__loom_metric": int64(1)}, + }}} + result, err := (&Reader{ClickHouse: fake}).ExecuteAggregateBatch(context.Background(), dataset, AggregateBatchRequest{ + Jobs: []AggregateJob{{ID: 1, ResponseMode: AggregateResponseLegacy, GroupBy: []string{"facet_000", "facet_001"}, Operation: "COUNT"}}, + AccessByProject: map[string]SourceAccess{"project": {Unrestricted: true}}, + }) + if err != nil { + t.Fatal(err) + } + rows := result.Jobs[0].Rows + if rows[0]["facet_000"].(json.Number).String() != "2" || rows[0]["facet_001"] != "a" { + t.Fatalf("typed ordering = %#v", rows) + } + if rows[len(rows)-1]["facet_000"] != nil { + t.Fatalf("null key did not sort last: %#v", rows) + } +} diff --git a/internal/dataframe/published/aggregate_plan.go b/internal/dataframe/published/aggregate_plan.go new file mode 100644 index 00000000..a2e22f32 --- /dev/null +++ b/internal/dataframe/published/aggregate_plan.go @@ -0,0 +1,290 @@ +package published + +import ( + "encoding/json" + "fmt" + "sort" + "strings" + + dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" +) + +type plannedAggregateJob struct { + job AggregateJob + filters []Filter + filterKey string + key string + aliases []int +} + +type aggregateStatementKind string + +const ( + statementLegacy aggregateStatementKind = "legacy" + statementTerms aggregateStatementKind = "terms" + statementBucket aggregateStatementKind = "bucket" + statementScalar aggregateStatementKind = "scalar" +) + +type aggregateStatementPlan struct { + kind aggregateStatementKind + jobs []*plannedAggregateJob + filters []Filter +} + +type aggregatePlan struct { + jobs []*plannedAggregateJob + statements []aggregateStatementPlan + results map[int]AggregateJobResult +} + +func ExcludeSelfFilters(filters []Filter, column string) []Filter { + result := make([]Filter, 0, len(filters)) + for _, filter := range filters { + if strings.TrimSpace(filter.Column) != strings.TrimSpace(column) { + result = append(result, filter) + } + } + return result +} + +func buildAggregatePlan(dataset FederatedDataset, req AggregateBatchRequest) aggregatePlan { + plan := aggregatePlan{results: make(map[int]AggregateJobResult, len(req.Jobs))} + allowed := make(map[string]struct{}, len(dataset.Columns)) + for _, column := range dataset.Columns { + if !internalAggregateColumn(column.Name) { + allowed[column.Name] = struct{}{} + } + } + dedup := make(map[string]*plannedAggregateJob) + for _, input := range req.Jobs { + job, filters, filterKey, key, err := validateAggregateJob(input, allowed) + if err != nil { + plan.results[input.ID] = AggregateJobResult{ID: input.ID, Err: err} + continue + } + if existing := dedup[key]; existing != nil { + existing.aliases = append(existing.aliases, job.ID) + continue + } + planned := &plannedAggregateJob{job: job, filters: filters, filterKey: filterKey, key: key, aliases: []int{job.ID}} + dedup[key] = planned + plan.jobs = append(plan.jobs, planned) + } + + groups := make(map[string][]*plannedAggregateJob) + keys := make([]string, 0) + for _, job := range plan.jobs { + family := statementFamily(job.job, dataset) + key := job.filterKey + "\x00" + family + if _, ok := groups[key]; !ok { + keys = append(keys, key) + } + groups[key] = append(groups[key], job) + } + sort.Strings(keys) + for _, key := range keys { + jobs := groups[key] + kind := statementKind(jobs[0].job.ResponseMode) + if kind == statementLegacy || kind == statementTerms || kind == statementBucket { + for start := 0; start < len(jobs); start += maxGroupingSets { + end := start + maxGroupingSets + if end > len(jobs) { + end = len(jobs) + } + plan.statements = append(plan.statements, aggregateStatementPlan{kind: kind, jobs: jobs[start:end], filters: jobs[0].filters}) + } + } else { + plan.statements = append(plan.statements, aggregateStatementPlan{kind: kind, jobs: jobs, filters: jobs[0].filters}) + } + } + // Terms buckets need a missing count. Fold those expressions into the + // compatible scalar scan (or create one scalar scan for the filter group) + // instead of issuing a second query per terms specification. + for _, job := range plan.jobs { + if job.job.ResponseMode != AggregateResponseTerms { + continue + } + found := false + for index := range plan.statements { + statement := &plan.statements[index] + if statement.kind == statementScalar && len(statement.jobs) > 0 && statement.jobs[0].filterKey == job.filterKey { + statement.jobs = append(statement.jobs, job) + found = true + break + } + } + if !found { + plan.statements = append(plan.statements, aggregateStatementPlan{kind: statementScalar, jobs: []*plannedAggregateJob{job}, filters: job.filters}) + } + } + ordered := make([]aggregateStatementPlan, 0, len(plan.statements)) + for _, statement := range plan.statements { + if statement.kind != statementScalar { + ordered = append(ordered, statement) + } + } + for _, statement := range plan.statements { + if statement.kind == statementScalar { + ordered = append(ordered, statement) + } + } + plan.statements = ordered + return plan +} + +func validateAggregateJob(input AggregateJob, allowed map[string]struct{}) (AggregateJob, []Filter, string, string, error) { + job := input + job.Operation = strings.ToUpper(strings.TrimSpace(job.Operation)) + job.Column = strings.TrimSpace(job.Column) + for i := range job.GroupBy { + job.GroupBy[i] = strings.TrimSpace(job.GroupBy[i]) + if _, ok := allowed[job.GroupBy[i]]; !ok || internalAggregateColumn(job.GroupBy[i]) { + return job, nil, "", "", aggregateInvalidRequest("group column %q is not in federated dataset schema", job.GroupBy[i]) + } + } + filters, filterKey, err := canonicalFilters(job.Filters, allowed) + if err != nil { + return job, nil, "", "", err + } + switch job.ResponseMode { + case AggregateResponseLegacy: + switch job.Operation { + case "COUNT": + job.Column = "" + case "COUNT_DISTINCT", "SUM", "AVG", "MIN", "MAX": + if _, ok := allowed[job.Column]; !ok || internalAggregateColumn(job.Column) { + return job, nil, "", "", aggregateInvalidRequest("metric column %q is not in federated dataset schema", job.Column) + } + default: + return job, nil, "", "", aggregateInvalidRequest("unsupported aggregate operation %q", input.Operation) + } + case AggregateResponseTerms, AggregateResponseHistogram, AggregateResponseDateHistogram, AggregateResponseStats, AggregateResponseMissing: + if _, ok := allowed[job.Column]; !ok || internalAggregateColumn(job.Column) { + return job, nil, "", "", aggregateInvalidRequest("aggregate column %q is not in federated dataset schema", job.Column) + } + if job.ResponseMode == AggregateResponseTerms || job.ResponseMode == AggregateResponseHistogram || job.ResponseMode == AggregateResponseDateHistogram { + if job.Size <= 0 { + job.Size = defaultAggregationSize + } + if job.Size > maxAggregationSize { + return job, nil, "", "", aggregateInvalidRequest("size exceeds maximum of %d", maxAggregationSize) + } + } + if job.ResponseMode == AggregateResponseHistogram && job.Interval <= 0 { + return job, nil, "", "", aggregateInvalidRequest("interval must be greater than zero") + } + if job.ResponseMode == AggregateResponseDateHistogram && job.DateInterval <= 0 { + return job, nil, "", "", aggregateInvalidRequest("dateInterval must be greater than zero seconds") + } + default: + return job, nil, "", "", aggregateInvalidRequest("unsupported aggregate response mode %q", job.ResponseMode) + } + job.Filters = filters + keyBytes, _ := json.Marshal([]any{job.ResponseMode, filterKey, job.GroupBy, job.Operation, job.Column, job.Size, job.Interval, job.DateInterval}) + return job, filters, filterKey, string(keyBytes), nil +} + +func internalAggregateColumn(column string) bool { + switch strings.TrimSpace(column) { + case "__loom_row_id", "__loom_global_row_id", authResourcePathColumn: + return true + default: + return false + } +} + +func canonicalFilters(filters []Filter, allowed map[string]struct{}) ([]Filter, string, error) { + type token struct { + encoded string + filter Filter + } + tokens := make([]token, 0, len(filters)) + for _, input := range filters { + filter := input + filter.Column = strings.TrimSpace(filter.Column) + filter.Op = strings.ToUpper(strings.TrimSpace(filter.Op)) + if _, ok := allowed[filter.Column]; !ok || internalAggregateColumn(filter.Column) { + return nil, "", dataframeerrors.NewError(dataframeerrors.CodeInvalidFilter, fmt.Sprintf("filter column %q is not in federated dataset schema", filter.Column)) + } + switch filter.Op { + case "EQ", "NEQ", "IN", "NOT_IN", "LT", "LTE", "GT", "GTE", "CONTAINS", "STARTS_WITH", "EXISTS", "IS_NULL", "ARRAY_CONTAINS", "ARRAY_OVERLAPS": + default: + return nil, "", dataframeerrors.NewError(dataframeerrors.CodeInvalidFilter, fmt.Sprintf("unsupported filter operation %q", input.Op)) + } + if filter.Op == "IN" || filter.Op == "NOT_IN" || filter.Op == "ARRAY_OVERLAPS" { + filter.Value = canonicalCollection(filter.Value) + } + value, err := json.Marshal(filter.Value) + if err != nil { + return nil, "", fmt.Errorf("encode filter value: %w", err) + } + encodedBytes, _ := json.Marshal([]json.RawMessage{json.RawMessage(mustJSON(filter.Column)), json.RawMessage(mustJSON(filter.Op)), value}) + tokens = append(tokens, token{encoded: string(encodedBytes), filter: filter}) + } + sort.SliceStable(tokens, func(i, j int) bool { return tokens[i].encoded < tokens[j].encoded }) + result := make([]Filter, len(tokens)) + parts := make([]string, len(tokens)) + for i, item := range tokens { + result[i], parts[i] = item.filter, item.encoded + } + return result, strings.Join(parts, "\x1e"), nil +} + +func aggregateInvalidRequest(format string, args ...any) error { + return dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, fmt.Sprintf(format, args...)) +} + +func mustJSON(value string) []byte { + encoded, _ := json.Marshal(value) + return encoded +} + +func canonicalCollection(value any) any { + var values []any + switch typed := value.(type) { + case []any: + values = append(values, typed...) + case []string: + for _, item := range typed { + values = append(values, item) + } + default: + return value + } + sort.SliceStable(values, func(i, j int) bool { + left, _ := json.Marshal(values[i]) + right, _ := json.Marshal(values[j]) + return string(left) < string(right) + }) + return values +} + +func statementFamily(job AggregateJob, dataset FederatedDataset) string { + switch job.ResponseMode { + case AggregateResponseLegacy: + return "legacy:" + job.Operation + ":" + job.Column + case AggregateResponseTerms: + column, _ := findColumn(dataset.Columns, job.Column) + return "terms:" + column.ClickHouse + case AggregateResponseHistogram, AggregateResponseDateHistogram: + return "bucket:" + string(job.ResponseMode) + case AggregateResponseStats, AggregateResponseMissing: + return "scalar" + default: + return string(job.ResponseMode) + } +} + +func statementKind(mode AggregateResponseMode) aggregateStatementKind { + switch mode { + case AggregateResponseLegacy: + return statementLegacy + case AggregateResponseTerms: + return statementTerms + case AggregateResponseHistogram, AggregateResponseDateHistogram: + return statementBucket + default: + return statementScalar + } +} diff --git a/internal/dataframe/published/aggregate_plan_test.go b/internal/dataframe/published/aggregate_plan_test.go new file mode 100644 index 00000000..0823615a --- /dev/null +++ b/internal/dataframe/published/aggregate_plan_test.go @@ -0,0 +1,160 @@ +package published + +import ( + "context" + "fmt" + "strings" + "testing" +) + +type aggregateQueryCall struct { + query string + args []any +} + +type aggregateFakeQueryer struct { + calls []aggregateQueryCall + rows [][]map[string]any + errs []error +} + +func (f *aggregateFakeQueryer) QueryRowsArgs(_ context.Context, query string, _ []string, args ...any) ([]map[string]any, error) { + index := len(f.calls) + f.calls = append(f.calls, aggregateQueryCall{query: query, args: append([]any(nil), args...)}) + if index < len(f.errs) && f.errs[index] != nil { + return nil, f.errs[index] + } + if index < len(f.rows) { + return f.rows[index], nil + } + return nil, nil +} + +func (f *aggregateFakeQueryer) QueryRowsArgsVisit(ctx context.Context, query string, columns []string, visit func(map[string]any) error, args ...any) error { + rows, err := f.QueryRowsArgs(ctx, query, columns, args...) + if err != nil { + return err + } + for _, row := range rows { + if err := visit(row); err != nil { + return err + } + } + return nil +} + +func aggregateTestDataset(columnCount int) FederatedDataset { + columns := make([]Column, columnCount) + for i := range columns { + columns[i] = Column{Name: fmt.Sprintf("facet_%03d", i), ClickHouse: "Nullable(String)"} + } + return FederatedDataset{ + Columns: columns, + Sources: []Materialization{{ + ID: "source:Patient", Project: "project", PhysicalTable: "physical_patient", + Columns: append([]Column(nil), columns...), + }}, + } +} + +func TestAggregatePlanCombines156CountFacets(t *testing.T) { + dataset := aggregateTestDataset(156) + jobs := make([]AggregateJob, 0, 158) + for i := 0; i < 156; i++ { + jobs = append(jobs, AggregateJob{ID: i, ResponseMode: AggregateResponseLegacy, GroupBy: []string{dataset.Columns[i].Name}, Operation: "COUNT"}) + } + jobs = append(jobs, + AggregateJob{ID: 156, ResponseMode: AggregateResponseLegacy, Operation: "COUNT"}, + AggregateJob{ID: 157, ResponseMode: AggregateResponseLegacy, Operation: "COUNT"}, + ) + fake := &aggregateFakeQueryer{} + result, err := (&Reader{ClickHouse: fake}).ExecuteAggregateBatch(context.Background(), dataset, AggregateBatchRequest{ + Jobs: jobs, AccessByProject: map[string]SourceAccess{"project": {Unrestricted: true}}, + }) + if err != nil { + t.Fatal(err) + } + if result.LogicalJobs != 158 || result.DeduplicatedJobs != 157 || result.Statements != 1 { + t.Fatalf("batch counts = logical %d deduplicated %d statements %d", result.LogicalJobs, result.DeduplicatedJobs, result.Statements) + } + if len(fake.calls) != 1 { + t.Fatalf("ClickHouse calls = %d, want 1", len(fake.calls)) + } + query := fake.calls[0].query + if !strings.Contains(query, "GROUP BY GROUPING SETS") { + t.Fatalf("query does not use grouping sets: %s", query) + } + if !strings.Contains(query, "SETTINGS group_by_use_nulls = 0") { + t.Fatalf("query does not pin the ClickHouse-compatible null grouping setting") + } + if count := strings.Count(query, "physical_patient"); count != 1 { + t.Fatalf("physical source occurs %d times, want 1", count) + } + if !strings.Contains(query, "arrayJoin") { + t.Fatalf("query does not use the narrow logical facet fan-out") + } + if count := strings.Count(query, "GROUPING SETS"); count != 1 { + t.Fatalf("query has %d physical grouping statements, want 1", count) + } + if count := strings.Count(query, "tuple("); count < 156 { + t.Fatalf("query has %d logical facet tuples, want at least 156", count) + } +} + +func TestAggregatePlanCanonicalizesFilterAndMemberOrder(t *testing.T) { + dataset := aggregateTestDataset(2) + first := []Filter{{Column: "facet_001", Op: "IN", Value: []any{"b", "a"}}, {Column: "facet_000", Op: "EQ", Value: "x"}} + second := []Filter{{Column: "facet_000", Op: "eq", Value: "x"}, {Column: "facet_001", Op: "in", Value: []any{"a", "b"}}} + plan := buildAggregatePlan(dataset, AggregateBatchRequest{Jobs: []AggregateJob{ + {ID: 1, ResponseMode: AggregateResponseLegacy, GroupBy: []string{"facet_000"}, Operation: "COUNT", Filters: first}, + {ID: 2, ResponseMode: AggregateResponseLegacy, GroupBy: []string{"facet_001"}, Operation: "COUNT", Filters: second}, + }}) + if len(plan.statements) != 1 { + t.Fatalf("statements = %d, want 1", len(plan.statements)) + } +} + +func TestAggregatePlanValidationIsJobLocal(t *testing.T) { + dataset := aggregateTestDataset(1) + fake := &aggregateFakeQueryer{} + result, err := (&Reader{ClickHouse: fake}).ExecuteAggregateBatch(context.Background(), dataset, AggregateBatchRequest{ + Jobs: []AggregateJob{ + {ID: 1, ResponseMode: AggregateResponseLegacy, GroupBy: []string{"missing"}, Operation: "COUNT"}, + {ID: 2, ResponseMode: AggregateResponseLegacy, GroupBy: []string{"facet_000"}, Operation: "COUNT"}, + }, + AccessByProject: map[string]SourceAccess{"project": {Unrestricted: true}}, + }) + if err != nil { + t.Fatal(err) + } + if result.Jobs[0].Err == nil || result.Jobs[1].Err != nil { + t.Fatalf("job errors = %#v, %#v", result.Jobs[0].Err, result.Jobs[1].Err) + } + if len(fake.calls) != 1 { + t.Fatalf("ClickHouse calls = %d, want 1", len(fake.calls)) + } +} + +func TestAggregateDedupFansOutIndependentRows(t *testing.T) { + dataset := aggregateTestDataset(1) + fake := &aggregateFakeQueryer{rows: [][]map[string]any{{ + {"__loom_slot": int64(0), "__loom_group_json": "[\"x\"]", "__loom_metric": int64(2)}, + }}} + result, err := (&Reader{ClickHouse: fake}).ExecuteAggregateBatch(context.Background(), dataset, AggregateBatchRequest{ + Jobs: []AggregateJob{ + {ID: 1, ResponseMode: AggregateResponseLegacy, GroupBy: []string{"facet_000"}, Operation: "COUNT"}, + {ID: 2, ResponseMode: AggregateResponseLegacy, GroupBy: []string{"facet_000"}, Operation: "COUNT"}, + }, + AccessByProject: map[string]SourceAccess{"project": {Unrestricted: true}}, + }) + if err != nil { + t.Fatal(err) + } + if result.DeduplicatedJobs != 1 || len(result.Jobs) != 2 { + t.Fatalf("result = %#v", result) + } + result.Jobs[0].Rows[0]["count"] = int64(9) + if result.Jobs[1].Rows[0]["count"] != int64(2) { + t.Fatalf("deduplicated aliases share row maps: %#v", result.Jobs) + } +} diff --git a/internal/dataframe/published/aggregate_sql.go b/internal/dataframe/published/aggregate_sql.go new file mode 100644 index 00000000..7885b7c9 --- /dev/null +++ b/internal/dataframe/published/aggregate_sql.go @@ -0,0 +1,447 @@ +package published + +import ( + "fmt" + "sort" + "strings" +) + +// Aggregate statements can contain a large number of grouping sets. Keep the +// query from competing with the rest of the Loom process for all pod memory: +// ClickHouse spills aggregation/sort state before the container limit is hit, +// and a small thread cap avoids one state arena per source worker. These are +// statement-local settings and do not change the server-wide profile. +const aggregateExternalMemoryBytes = 256 * 1024 * 1024 + +const aggregateMaxThreads = 2 + +func aggregateSettings() string { + return fmt.Sprintf( + "SETTINGS group_by_use_nulls = 0, max_bytes_before_external_group_by = %d, max_bytes_before_external_sort = %d, max_threads = %d", + aggregateExternalMemoryBytes, aggregateExternalMemoryBytes, aggregateMaxThreads, + ) +} + +type aggregateSQL struct { + query string + columns []string + args []any + sourceColumns []string + groupingSets int +} + +func buildAggregateSQL(dataset FederatedDataset, access map[string]SourceAccess, statement aggregateStatementPlan) (aggregateSQL, error) { + switch statement.kind { + case statementLegacy: + return buildGroupingSetSQL(dataset, access, statement, false) + case statementTerms: + return buildGroupingSetSQL(dataset, access, statement, true) + case statementBucket: + return buildBucketSQL(dataset, access, statement) + case statementScalar: + return buildScalarSQL(dataset, access, statement) + default: + return aggregateSQL{}, fmt.Errorf("unknown aggregate statement kind %q", statement.kind) + } +} + +func aggregateUnion(dataset FederatedDataset, access map[string]SourceAccess, statement aggregateStatementPlan) (string, []any, []string, error) { + set := make(map[string]struct{}) + for _, job := range statement.jobs { + for _, column := range job.job.GroupBy { + set[column] = struct{}{} + } + if job.job.Column != "" { + set[job.job.Column] = struct{}{} + } + } + for _, filter := range statement.filters { + set[filter.Column] = struct{}{} + } + columns := make([]string, 0, len(set)) + for column := range set { + columns = append(columns, column) + } + sort.Strings(columns) + union, args, err := federatedNormalizedUnion(dataset, columns, access) + return union, args, columns, err +} + +func buildGroupingSetSQL(dataset FederatedDataset, access map[string]SourceAccess, statement aggregateStatementPlan, terms bool) (aggregateSQL, error) { + if !terms { + return buildLegacyGroupingSetSQL(dataset, access, statement) + } + return buildTermsGroupingSetSQL(dataset, access, statement) +} + +// buildLegacyGroupingSetSQL keeps the aggregate state narrow even when an +// operation contains hundreds of one-column facets. ClickHouse expands a +// large GROUPING SETS clause into one aggregation state per set; on the +// production 156-facet shape that alone can exceed the server's memory cap. +// We fan out the logical facet slot/key pairs once with arrayJoin and perform +// one physical GROUPING SETS aggregation over the narrow pair. The source +// union is still built once per statement, and every logical job remains +// represented by its slot in the grouped key. +func buildLegacyGroupingSetSQL(dataset FederatedDataset, access map[string]SourceAccess, statement aggregateStatementPlan) (aggregateSQL, error) { + union, args, sourceColumns, err := aggregateUnion(dataset, access, statement) + if err != nil { + return aggregateSQL{}, err + } + allowed := aggregateAllowedColumns(dataset) + where, whereArgs, err := buildWhere(statement.filters, allowed) + if err != nil { + return aggregateSQL{}, err + } + args = append(args, whereArgs...) + + keyAliases := make([]string, len(statement.jobs)) + keyExpressions := make([]string, 0, len(statement.jobs)+1) + for index, planned := range statement.jobs { + if len(planned.job.GroupBy) == 0 { + continue + } + alias := fmt.Sprintf("__loom_group_key_%d", index) + keyAliases[index] = alias + keyExpressions = append(keyExpressions, "toJSONString(tuple("+quotedColumns(planned.job.GroupBy)+")) AS `"+alias+"`") + } + metricColumn := strings.TrimSpace(statement.jobs[0].job.Column) + if metricColumn != "" { + keyExpressions = append(keyExpressions, "`"+metricColumn+"` AS `__loom_metric_value`") + } + sourceProjection := strings.Join(keyExpressions, ", ") + if sourceProjection == "" { + sourceProjection = "*" + } + source := "SELECT " + sourceProjection + " FROM (" + union + ") AS __loom_aggregate_source" + if len(where) > 0 { + source += " WHERE " + strings.Join(where, " AND ") + } + pairs := make([]string, 0, len(statement.jobs)) + for index, planned := range statement.jobs { + if len(planned.job.GroupBy) == 0 { + pairs = append(pairs, fmt.Sprintf("tuple(%d, '[]')", index)) + } else { + pairs = append(pairs, fmt.Sprintf("tuple(%d, `%s`)", index, keyAliases[index])) + } + } + fanout := "SELECT tupleElement(__loom_pair, 1) AS `__loom_slot`, tupleElement(__loom_pair, 2) AS `__loom_group_json`" + if metricColumn != "" { + fanout += ", `__loom_metric_value`" + } + fanout += " FROM (SELECT arrayJoin([" + strings.Join(pairs, ", ") + "]) AS __loom_pair" + if metricColumn != "" { + fanout += ", `__loom_metric_value`" + } + fanout += " FROM (" + source + ") AS __loom_aggregate_source) AS __loom_aggregate_fanout" + metric := legacyMetricOnColumn(statement.jobs[0].job, "__loom_metric_value") + query := fmt.Sprintf("SELECT `__loom_slot`, `__loom_group_json`, %s AS `__loom_metric` FROM (%s) AS __loom_group_source GROUP BY GROUPING SETS ((`__loom_slot`, `__loom_group_json`)) %s", metric, fanout, aggregateSettings()) + return aggregateSQL{ + query: query, columns: []string{"__loom_slot", "__loom_group_json", "__loom_metric"}, args: args, + sourceColumns: sourceColumns, groupingSets: len(statement.jobs), + }, nil +} + +func buildTermsGroupingSetSQL(dataset FederatedDataset, access map[string]SourceAccess, statement aggregateStatementPlan) (aggregateSQL, error) { + union, args, sourceColumns, err := aggregateUnion(dataset, access, statement) + if err != nil { + return aggregateSQL{}, err + } + allowed := aggregateAllowedColumns(dataset) + where, whereArgs, err := buildWhere(statement.filters, allowed) + if err != nil { + return aggregateSQL{}, err + } + args = append(args, whereArgs...) + allGroups := make([]string, 0) + for _, job := range statement.jobs { + groups := []string{job.job.Column} + for _, column := range groups { + if !contains(allGroups, column) { + allGroups = append(allGroups, column) + } + } + } + sort.Strings(allGroups) + + innerSelect := make([]string, 0, len(allGroups)+4) + for _, column := range allGroups { + innerSelect = append(innerSelect, fmt.Sprintf("`%s`", column)) + } + maskNames := make([]string, 0) + for start := 0; start < len(allGroups); start += 63 { + end := start + 63 + if end > len(allGroups) { + end = len(allGroups) + } + name := fmt.Sprintf("__loom_mask_%d", len(maskNames)) + maskNames = append(maskNames, name) + innerSelect = append(innerSelect, fmt.Sprintf("%s AS `%s`", groupingMaskExpression(allGroups[start:end]), name)) + } + metric := "count()" + innerSelect = append(innerSelect, metric+" AS `__loom_metric`") + + sets := make([]string, len(statement.jobs)) + conditions := make([]string, len(statement.jobs)) + for i, job := range statement.jobs { + groups := []string{job.job.Column} + sets[i] = "(" + quotedColumns(groups) + ")" + conditions[i] = groupingCondition(allGroups, groups, maskNames) + } + slot := "0" + if len(statement.jobs) > 1 { + parts := make([]string, 0, len(statement.jobs)*2+1) + for i, condition := range conditions { + parts = append(parts, condition, fmt.Sprintf("%d", i)) + } + parts = append(parts, "-1") + slot = "multiIf(" + strings.Join(parts, ", ") + ")" + } + groupJSONValues := make([]string, len(statement.jobs)) + for i, job := range statement.jobs { + groups := []string{job.job.Column} + groupJSONValues[i] = "'[]'" + if len(groups) > 0 { + groupJSONValues[i] = "toJSONString(tuple(" + quotedColumns(groups) + "))" + } + } + groupJSON := groupJSONValues[0] + if len(statement.jobs) > 1 { + parts := make([]string, 0, len(statement.jobs)*2+1) + for i, condition := range conditions { + parts = append(parts, condition, groupJSONValues[i]) + } + parts = append(parts, "'[]'") + groupJSON = "multiIf(" + strings.Join(parts, ", ") + ")" + } + rawProjection := "" + if len(allGroups) > 0 { + rawProjection = ", " + quotedColumns(allGroups) + } + query := fmt.Sprintf("SELECT %s AS `__loom_slot`, %s AS `__loom_group_json`, `__loom_metric`%s FROM (SELECT %s FROM (%s) AS __loom_aggregate_source", slot, groupJSON, rawProjection, strings.Join(innerSelect, ", "), union) + if len(where) > 0 { + query += " WHERE " + strings.Join(where, " AND ") + } + // ClickHouse 25.7's analyzer rejects GROUPING() with + // group_by_use_nulls=1 (even when every argument is a grouping key). + // Keep the setting explicit at 0 and use the grouping masks to distinguish + // rolled-up defaults from real NULL values. + query += " GROUP BY GROUPING SETS (" + strings.Join(sets, ", ") + ") " + aggregateSettings() + ") AS __loom_grouped" + limitParts := make([]string, 0, len(statement.jobs)*2+1) + for i, planned := range statement.jobs { + limitParts = append(limitParts, fmt.Sprintf("`__loom_slot` = %d", i), fmt.Sprintf("%d", planned.job.Size+1)) + } + limitParts = append(limitParts, "0") + limitExpr := "multiIf(" + strings.Join(limitParts, ", ") + ")" + orderKey := "`" + statement.jobs[0].job.Column + "`" + if len(statement.jobs) > 1 { + parts := make([]string, 0, len(statement.jobs)*2+1) + for i, condition := range conditions { + parts = append(parts, condition, "`"+statement.jobs[i].job.Column+"`") + } + parts = append(parts, "NULL") + orderKey = "multiIf(" + strings.Join(parts, ", ") + ")" + } + query = fmt.Sprintf("SELECT `__loom_slot`, `__loom_group_json`, `__loom_metric` FROM (SELECT *, row_number() OVER (PARTITION BY `__loom_slot` ORDER BY `__loom_metric` DESC, `__loom_order_key` ASC) AS `__loom_rank` FROM (SELECT *, %s AS `__loom_order_key` FROM (%s) AS __loom_terms_projected) AS __loom_terms WHERE `__loom_group_json` != '[null]') AS __loom_ranked WHERE `__loom_rank` <= %s ORDER BY `__loom_slot`, `__loom_metric` DESC, `__loom_order_key` ASC", orderKey, query, limitExpr) + return aggregateSQL{ + query: query, columns: []string{"__loom_slot", "__loom_group_json", "__loom_metric"}, args: args, + sourceColumns: sourceColumns, groupingSets: len(statement.jobs), + }, nil +} + +func groupingCondition(all, groups, masks []string) string { + present := make(map[string]struct{}, len(groups)) + for _, group := range groups { + present[group] = struct{}{} + } + conditions := make([]string, 0, len(masks)) + for start, index := 0, 0; start < len(all); start, index = start+63, index+1 { + end := start + 63 + if end > len(all) { + end = len(all) + } + var mask uint64 + for offset, column := range all[start:end] { + if _, ok := present[column]; !ok { + mask |= uint64(1) << uint(end-start-1-offset) + } + } + conditions = append(conditions, fmt.Sprintf("`%s` = %d", masks[index], mask)) + } + if len(conditions) == 0 { + return "1" + } + return strings.Join(conditions, " AND ") +} + +// groupingMaskExpression deliberately calls GROUPING with one column at a +// time. ClickHouse's analyzer has a compatibility bug for the variadic form +// (GROUPING(a, b, ...)) when GROUPING SETS contains sparse sets: it can reject +// a valid key as not being part of GROUP BY. Combining the scalar GROUPING +// results into the same bit mask is semantically identical and works across +// the ClickHouse versions supported by Loom. +func groupingMaskExpression(columns []string) string { + if len(columns) == 0 { + return "toUInt64(0)" + } + terms := make([]string, 0, len(columns)) + for index, column := range columns { + shift := len(columns) - 1 - index + terms = append(terms, fmt.Sprintf("bitShiftLeft(toUInt64(grouping(`%s`)), %d)", column, shift)) + } + return strings.Join(terms, " + ") +} + +func legacyMetric(job AggregateJob) string { + return legacyMetricOnColumn(job, job.Column) +} + +func legacyMetricOnColumn(job AggregateJob, column string) string { + switch job.Operation { + case "COUNT_DISTINCT": + return fmt.Sprintf("uniqExact(`%s`)", column) + case "SUM": + return fmt.Sprintf("sum(`%s`)", column) + case "AVG": + return fmt.Sprintf("avg(`%s`)", column) + case "MIN": + return fmt.Sprintf("min(`%s`)", column) + case "MAX": + return fmt.Sprintf("max(`%s`)", column) + default: + return "count()" + } +} + +func buildBucketSQL(dataset FederatedDataset, access map[string]SourceAccess, statement aggregateStatementPlan) (aggregateSQL, error) { + union, unionArgs, sourceColumns, err := aggregateUnion(dataset, access, statement) + if err != nil { + return aggregateSQL{}, err + } + where, whereArgs, err := buildWhere(statement.filters, aggregateAllowedColumns(dataset)) + if err != nil { + return aggregateSQL{}, err + } + expressionArgs := make([]any, 0, len(statement.jobs)*2) + expressions := make([]string, len(statement.jobs)) + bucketColumns := make([]string, len(statement.jobs)) + sets := make([]string, len(statement.jobs)) + for slot, planned := range statement.jobs { + job := planned.job + bucket := fmt.Sprintf("__loom_bucket_%d", slot) + bucketColumns[slot] = bucket + sets[slot] = "(`" + bucket + "`)" + if job.ResponseMode == AggregateResponseHistogram { + expressions[slot] = fmt.Sprintf("floor(toFloat64(`%s`) / ?)*? AS `%s`", job.Column, bucket) + expressionArgs = append(expressionArgs, job.Interval, job.Interval) + } else { + expressions[slot] = fmt.Sprintf("toStartOfInterval(`%s`, toIntervalSecond(?)) AS `%s`", job.Column, bucket) + expressionArgs = append(expressionArgs, job.DateInterval) + } + } + args := append(expressionArgs, unionArgs...) + args = append(args, whereArgs...) + source := fmt.Sprintf("SELECT %s FROM (%s) AS __loom_aggregate_source", strings.Join(expressions, ", "), union) + if len(where) > 0 { + source += " WHERE " + strings.Join(where, " AND ") + } + maskNames := make([]string, 0) + masks := make([]string, 0) + for start := 0; start < len(bucketColumns); start += 63 { + end := start + 63 + if end > len(bucketColumns) { + end = len(bucketColumns) + } + name := fmt.Sprintf("__loom_mask_%d", len(maskNames)) + maskNames = append(maskNames, name) + masks = append(masks, fmt.Sprintf("%s AS `%s`", groupingMaskExpression(bucketColumns[start:end]), name)) + } + conditions := make([]string, len(statement.jobs)) + for slot, bucket := range bucketColumns { + conditions[slot] = groupingCondition(bucketColumns, []string{bucket}, maskNames) + } + slotExpr := "0" + keyExpr := "toJSONString(tuple(`" + bucketColumns[0] + "`))" + orderKeyExpr := "`" + bucketColumns[0] + "`" + if len(statement.jobs) > 1 { + slotParts := make([]string, 0, len(statement.jobs)*2+1) + keyParts := make([]string, 0, len(statement.jobs)*2+1) + orderParts := make([]string, 0, len(statement.jobs)*2+1) + for slot, condition := range conditions { + slotParts = append(slotParts, condition, fmt.Sprintf("%d", slot)) + keyParts = append(keyParts, condition, "toJSONString(tuple(`"+bucketColumns[slot]+"`))") + orderParts = append(orderParts, condition, "`"+bucketColumns[slot]+"`") + } + slotParts = append(slotParts, "-1") + keyParts = append(keyParts, "'[]'") + orderParts = append(orderParts, "NULL") + slotExpr = "multiIf(" + strings.Join(slotParts, ", ") + ")" + keyExpr = "multiIf(" + strings.Join(keyParts, ", ") + ")" + orderKeyExpr = "multiIf(" + strings.Join(orderParts, ", ") + ")" + } + groupedSelect := append(append([]string(nil), bucketColumns...), masks...) + for index := range bucketColumns { + groupedSelect[index] = "`" + bucketColumns[index] + "`" + } + groupedSelect = append(groupedSelect, "count() AS `__loom_metric`") + grouped := fmt.Sprintf("SELECT %s FROM (%s) AS __loom_bucket_source GROUP BY GROUPING SETS (%s) %s", strings.Join(groupedSelect, ", "), source, strings.Join(sets, ", "), aggregateSettings()) + projected := fmt.Sprintf("SELECT %s AS `__loom_slot`, %s AS `__loom_group_json`, %s AS `__loom_order_key`, `__loom_metric` FROM (%s) AS __loom_bucket_grouped", slotExpr, keyExpr, orderKeyExpr, grouped) + sizeParts := make([]string, 0, len(statement.jobs)*2+1) + for slot, planned := range statement.jobs { + sizeParts = append(sizeParts, fmt.Sprintf("`__loom_slot` = %d", slot), fmt.Sprintf("%d", planned.job.Size)) + } + sizeParts = append(sizeParts, "0") + sizeExpr := "multiIf(" + strings.Join(sizeParts, ", ") + ")" + query := fmt.Sprintf("SELECT `__loom_slot`, `__loom_group_json`, `__loom_metric` FROM (SELECT *, row_number() OVER (PARTITION BY `__loom_slot` ORDER BY `__loom_order_key` ASC) AS `__loom_rank` FROM (%s) AS __loom_bucket_projected WHERE `__loom_group_json` != '[null]') AS __loom_bucket_ranked WHERE `__loom_rank` <= %s ORDER BY `__loom_slot`, `__loom_order_key` ASC", projected, sizeExpr) + return aggregateSQL{ + query: query, columns: []string{"__loom_slot", "__loom_group_json", "__loom_metric"}, args: args, + sourceColumns: sourceColumns, groupingSets: len(statement.jobs), + }, nil +} + +func buildScalarSQL(dataset FederatedDataset, access map[string]SourceAccess, statement aggregateStatementPlan) (aggregateSQL, error) { + union, args, sourceColumns, err := aggregateUnion(dataset, access, statement) + if err != nil { + return aggregateSQL{}, err + } + where, whereArgs, err := buildWhere(statement.filters, aggregateAllowedColumns(dataset)) + if err != nil { + return aggregateSQL{}, err + } + args = append(args, whereArgs...) + expressions := make([]string, 0) + columns := make([]string, 0) + for slot, planned := range statement.jobs { + column := planned.job.Column + if planned.job.ResponseMode == AggregateResponseStats { + for _, value := range []struct{ name, expression string }{ + {"count", "count()"}, {"value_count", fmt.Sprintf("countIf(`%s` IS NOT NULL)", column)}, + {"distinct_count", fmt.Sprintf("uniqExactIf(`%s`, `%s` IS NOT NULL)", column, column)}, + {"min", fmt.Sprintf("min(`%s`)", column)}, {"max", fmt.Sprintf("max(`%s`)", column)}, + {"sum", fmt.Sprintf("sum(`%s`)", column)}, {"avg", fmt.Sprintf("avg(`%s`)", column)}, + } { + alias := fmt.Sprintf("__loom_%d_%s", slot, value.name) + expressions = append(expressions, value.expression+" AS `"+alias+"`") + columns = append(columns, alias) + } + } else { + alias := fmt.Sprintf("__loom_%d_missing_count", slot) + expressions = append(expressions, fmt.Sprintf("countIf(`%s` IS NULL) AS `%s`", column, alias)) + columns = append(columns, alias) + } + } + query := fmt.Sprintf("SELECT %s FROM (%s) AS __loom_aggregate_source", strings.Join(expressions, ", "), union) + if len(where) > 0 { + query += " WHERE " + strings.Join(where, " AND ") + } + return aggregateSQL{query: query, columns: columns, args: args, sourceColumns: sourceColumns}, nil +} + +func aggregateAllowedColumns(dataset FederatedDataset) map[string]struct{} { + allowed := make(map[string]struct{}, len(dataset.Columns)) + for _, column := range dataset.Columns { + if !internalAggregateColumn(column.Name) { + allowed[column.Name] = struct{}{} + } + } + return allowed +} diff --git a/internal/dataframe/published/aggregate_types.go b/internal/dataframe/published/aggregate_types.go new file mode 100644 index 00000000..664d4ecf --- /dev/null +++ b/internal/dataframe/published/aggregate_types.go @@ -0,0 +1,93 @@ +package published + +import "sort" + +type AggregationSpec struct { + Name string + Kind string + Column string + Size int + Interval float64 + DateInterval int + ExcludeSelfFilter bool +} + +type AggregationsRequest struct { + Filters []Filter + Specs []AggregationSpec + AccessByProject map[string]SourceAccess +} + +type AggregationResult struct { + Name string `json:"name"` + Kind string `json:"kind"` + Columns []string `json:"columns"` + Rows []map[string]any `json:"rows"` + MissingCount int64 `json:"missingCount,omitempty"` + Truncated bool `json:"truncated,omitempty"` +} + +type AggregationsResult struct { + Dataset FederatedDataset + Aggregations []AggregationResult +} + +const ( + defaultAggregationSize = 100 + maxAggregationSize = 10_000 + maxAggregationSpecs = 50 + maxGroupingSets = 256 +) + +type AggregateResponseMode string + +const ( + AggregateResponseLegacy AggregateResponseMode = "LEGACY" + AggregateResponseTerms AggregateResponseMode = "TERMS" + AggregateResponseHistogram AggregateResponseMode = "HISTOGRAM" + AggregateResponseDateHistogram AggregateResponseMode = "DATE_HISTOGRAM" + AggregateResponseStats AggregateResponseMode = "STATS" + AggregateResponseMissing AggregateResponseMode = "MISSING" +) + +type AggregateJob struct { + ID int + ResponseMode AggregateResponseMode + Filters []Filter + GroupBy []string + Operation string + Column string + Size int + Interval float64 + DateInterval int +} + +type AggregateJobResult struct { + ID int + Columns []string + Rows []map[string]any + MissingCount int64 + Truncated bool + Err error +} + +type AggregateBatchRequest struct { + Jobs []AggregateJob + AccessByProject map[string]SourceAccess +} + +type AggregateBatchResult struct { + Jobs []AggregateJobResult + LogicalJobs int + DeduplicatedJobs int + Statements int + GroupingStatements int + ScalarStatements int + FilterGroups int +} + +func NormalizeAggregationResults(results []AggregationResult) []AggregationResult { + copyResults := append([]AggregationResult(nil), results...) + sort.Slice(copyResults, func(i, j int) bool { return copyResults[i].Name < copyResults[j].Name }) + return copyResults +} diff --git a/internal/dataframe/published/aggregations.go b/internal/dataframe/published/aggregations.go deleted file mode 100644 index 52fe0e26..00000000 --- a/internal/dataframe/published/aggregations.go +++ /dev/null @@ -1,255 +0,0 @@ -package published - -import ( - "context" - "fmt" - "sort" - "strings" -) - -type AggregationSpec struct { - Name string - Kind string - Column string - Size int - Interval float64 - DateInterval int - ExcludeSelfFilter bool -} - -type AggregationsRequest struct { - Filters []Filter - Specs []AggregationSpec - AccessByProject map[string]SourceAccess -} - -type AggregationResult struct { - Name string `json:"name"` - Kind string `json:"kind"` - Columns []string `json:"columns"` - Rows []map[string]any `json:"rows"` - MissingCount int64 `json:"missingCount,omitempty"` - Truncated bool `json:"truncated,omitempty"` -} - -type AggregationsResult struct { - Dataset FederatedDataset - Aggregations []AggregationResult -} - -const ( - defaultAggregationSize = 100 - maxAggregationSize = 10_000 - maxAggregationSpecs = 50 -) - -func (r *Reader) AggregateFederatedBatchDataset(ctx context.Context, dataset FederatedDataset, req AggregationsRequest) (AggregationsResult, error) { - if r == nil || r.ClickHouse == nil { - return AggregationsResult{}, fmt.Errorf("ClickHouse dependency is required") - } - if len(req.Specs) == 0 { - return AggregationsResult{}, fmt.Errorf("at least one aggregation specification is required") - } - if len(req.Specs) > maxAggregationSpecs { - return AggregationsResult{}, fmt.Errorf("too many aggregation specifications") - } - allowed := make(map[string]struct{}, len(dataset.Columns)) - for _, column := range dataset.Columns { - allowed[column.Name] = struct{}{} - } - results := make([]AggregationResult, 0, len(req.Specs)) - for _, spec := range req.Specs { - result, err := r.aggregateFederatedSpec(ctx, dataset, allowed, req, spec) - if err != nil { - return AggregationsResult{}, fmt.Errorf("aggregation %q: %w", spec.Name, err) - } - results = append(results, result) - } - return AggregationsResult{Dataset: dataset, Aggregations: results}, nil -} - -func (r *Reader) aggregateFederatedSpec(ctx context.Context, dataset FederatedDataset, allowed map[string]struct{}, req AggregationsRequest, spec AggregationSpec) (AggregationResult, error) { - kind := strings.ToUpper(strings.TrimSpace(spec.Kind)) - if strings.TrimSpace(spec.Name) == "" { - return AggregationResult{}, fmt.Errorf("name is required") - } - if kind == "" { - return AggregationResult{}, fmt.Errorf("kind is required") - } - if kind != "MISSING" { - if _, ok := allowed[spec.Column]; !ok || spec.Column == "__loom_row_id" { - return AggregationResult{}, fmt.Errorf("column %q is not in federated dataset schema", spec.Column) - } - } - filters := req.Filters - if spec.ExcludeSelfFilter { - filters = make([]Filter, 0, len(req.Filters)) - for _, filter := range req.Filters { - if filter.Column != spec.Column { - filters = append(filters, filter) - } - } - } - if kind == "MISSING" { - return r.aggregateMissing(ctx, dataset, allowed, req, filters, spec) - } - size := spec.Size - if size <= 0 { - size = defaultAggregationSize - } - if size > maxAggregationSize { - return AggregationResult{}, fmt.Errorf("size exceeds maximum of %d", maxAggregationSize) - } - switch kind { - case "TERMS": - return r.aggregateTerms(ctx, dataset, allowed, req, filters, spec, size) - case "HISTOGRAM": - if spec.Interval <= 0 { - return AggregationResult{}, fmt.Errorf("interval must be greater than zero") - } - return r.aggregateHistogram(ctx, dataset, allowed, req, filters, spec, size) - case "DATE_HISTOGRAM": - if spec.DateInterval <= 0 { - return AggregationResult{}, fmt.Errorf("dateInterval must be greater than zero seconds") - } - return r.aggregateDateHistogram(ctx, dataset, allowed, req, filters, spec, size) - case "STATS": - return r.aggregateStats(ctx, dataset, allowed, req, filters, spec) - default: - return AggregationResult{}, fmt.Errorf("unsupported aggregation kind %q", spec.Kind) - } -} - -func (r *Reader) aggregateTerms(ctx context.Context, dataset FederatedDataset, allowed map[string]struct{}, req AggregationsRequest, filters []Filter, spec AggregationSpec, size int) (AggregationResult, error) { - branches, args, err := r.aggregateValueBranches(dataset, allowed, req, filters, spec.Column) - if err != nil { - return AggregationResult{}, err - } - query := fmt.Sprintf("SELECT `__loom_agg_key`, count() AS `__loom_doc_count` FROM (%s) AS __loom_values GROUP BY `__loom_agg_key` ORDER BY `__loom_doc_count` DESC, `__loom_agg_key` ASC LIMIT %d", strings.Join(branches, " UNION ALL "), size+1) - rows, err := r.ClickHouse.QueryRowsArgs(ctx, query, []string{"__loom_agg_key", "__loom_doc_count"}, args...) - if err != nil { - return AggregationResult{}, backendCallError(err) - } - missing, err := r.missingCount(ctx, dataset, allowed, req, filters, spec.Column) - if err != nil { - return AggregationResult{}, err - } - truncated := len(rows) > size - if truncated { - rows = rows[:size] - } - resultRows := make([]map[string]any, 0, len(rows)) - for _, row := range rows { - resultRows = append(resultRows, map[string]any{"key": row["__loom_agg_key"], "doc_count": row["__loom_doc_count"]}) - } - return AggregationResult{Name: spec.Name, Kind: "TERMS", Columns: []string{"key", "doc_count"}, Rows: resultRows, MissingCount: missing, Truncated: truncated}, nil -} - -func (r *Reader) aggregateHistogram(ctx context.Context, dataset FederatedDataset, allowed map[string]struct{}, req AggregationsRequest, filters []Filter, spec AggregationSpec, size int) (AggregationResult, error) { - branches, args, err := r.aggregateValueBranches(dataset, allowed, req, filters, spec.Column) - if err != nil { - return AggregationResult{}, err - } - key := "floor(toFloat64(`__loom_agg_key`) / ?)*?" - args = append([]any{spec.Interval, spec.Interval}, args...) - query := fmt.Sprintf("SELECT %s AS `__loom_bucket`, count() AS `__loom_doc_count` FROM (%s) AS __loom_values WHERE `__loom_agg_key` IS NOT NULL GROUP BY `__loom_bucket` ORDER BY `__loom_bucket` ASC LIMIT %d", key, strings.Join(branches, " UNION ALL "), size) - rows, err := r.ClickHouse.QueryRowsArgs(ctx, query, []string{"__loom_bucket", "__loom_doc_count"}, args...) - if err != nil { - return AggregationResult{}, backendCallError(err) - } - resultRows := make([]map[string]any, 0, len(rows)) - for _, row := range rows { - resultRows = append(resultRows, map[string]any{"key": row["__loom_bucket"], "doc_count": row["__loom_doc_count"]}) - } - return AggregationResult{Name: spec.Name, Kind: "HISTOGRAM", Columns: []string{"key", "doc_count"}, Rows: resultRows, Truncated: len(rows) >= size}, nil -} - -func (r *Reader) aggregateDateHistogram(ctx context.Context, dataset FederatedDataset, allowed map[string]struct{}, req AggregationsRequest, filters []Filter, spec AggregationSpec, size int) (AggregationResult, error) { - branches, args, err := r.aggregateValueBranches(dataset, allowed, req, filters, spec.Column) - if err != nil { - return AggregationResult{}, err - } - query := fmt.Sprintf("SELECT toStartOfInterval(`__loom_agg_key`, toIntervalSecond(?)) AS `__loom_bucket`, count() AS `__loom_doc_count` FROM (%s) AS __loom_values WHERE `__loom_agg_key` IS NOT NULL GROUP BY `__loom_bucket` ORDER BY `__loom_bucket` ASC LIMIT %d", strings.Join(branches, " UNION ALL "), size) - args = append([]any{spec.DateInterval}, args...) - rows, err := r.ClickHouse.QueryRowsArgs(ctx, query, []string{"__loom_bucket", "__loom_doc_count"}, args...) - if err != nil { - return AggregationResult{}, backendCallError(err) - } - resultRows := make([]map[string]any, 0, len(rows)) - for _, row := range rows { - resultRows = append(resultRows, map[string]any{"key": row["__loom_bucket"], "doc_count": row["__loom_doc_count"]}) - } - return AggregationResult{Name: spec.Name, Kind: "DATE_HISTOGRAM", Columns: []string{"key", "doc_count"}, Rows: resultRows, Truncated: len(rows) >= size}, nil -} - -func (r *Reader) aggregateStats(ctx context.Context, dataset FederatedDataset, allowed map[string]struct{}, req AggregationsRequest, filters []Filter, spec AggregationSpec) (AggregationResult, error) { - branches, args, err := r.aggregateValueBranches(dataset, allowed, req, filters, spec.Column) - if err != nil { - return AggregationResult{}, err - } - query := fmt.Sprintf("SELECT count() AS `count`, countIf(`__loom_agg_key` IS NOT NULL) AS `value_count`, uniqExactIf(`__loom_agg_key`, `__loom_agg_key` IS NOT NULL) AS `distinct_count`, min(`__loom_agg_key`) AS `min`, max(`__loom_agg_key`) AS `max`, sum(`__loom_agg_key`) AS `sum`, avg(`__loom_agg_key`) AS `avg` FROM (%s) AS __loom_values", strings.Join(branches, " UNION ALL ")) - columns := []string{"count", "value_count", "distinct_count", "min", "max", "sum", "avg"} - rows, err := r.ClickHouse.QueryRowsArgs(ctx, query, columns, args...) - if err != nil { - return AggregationResult{}, backendCallError(err) - } - return AggregationResult{Name: spec.Name, Kind: "STATS", Columns: columns, Rows: rows}, nil -} - -func (r *Reader) aggregateMissing(ctx context.Context, dataset FederatedDataset, allowed map[string]struct{}, req AggregationsRequest, filters []Filter, spec AggregationSpec) (AggregationResult, error) { - missing, err := r.missingCount(ctx, dataset, allowed, req, filters, spec.Column) - if err != nil { - return AggregationResult{}, err - } - return AggregationResult{Name: spec.Name, Kind: "MISSING", Columns: []string{"missing_count"}, Rows: []map[string]any{{"missing_count": missing}}}, nil -} - -func (r *Reader) missingCount(ctx context.Context, dataset FederatedDataset, allowed map[string]struct{}, req AggregationsRequest, filters []Filter, column string) (int64, error) { - branches, args, err := r.aggregateValueBranches(dataset, allowed, req, filters, column) - if err != nil { - return 0, err - } - query := fmt.Sprintf("SELECT count() AS `__loom_missing` FROM (%s) AS __loom_values WHERE `__loom_agg_key` IS NULL", strings.Join(branches, " UNION ALL ")) - rows, err := r.ClickHouse.QueryRowsArgs(ctx, query, []string{"__loom_missing"}, args...) - if err != nil { - return 0, backendCallError(err) - } - if len(rows) == 0 { - return 0, nil - } - return numericCount(rows[0]["__loom_missing"]) -} - -func (r *Reader) aggregateValueBranches(dataset FederatedDataset, allowed map[string]struct{}, req AggregationsRequest, filters []Filter, column string) ([]string, []any, error) { - if _, ok := allowed[column]; !ok { - return nil, nil, fmt.Errorf("aggregate column %q is not in federated dataset schema", column) - } - unionColumns := []string{column} - for _, filter := range filters { - if !contains(unionColumns, filter.Column) { - unionColumns = append(unionColumns, filter.Column) - } - } - union, args, err := federatedNormalizedUnion(dataset, unionColumns, req.AccessByProject) - if err != nil { - return nil, nil, err - } - where, whereArgs, err := buildWhere(filters, allowed) - if err != nil { - return nil, nil, err - } - args = append(args, whereArgs...) - branch := fmt.Sprintf("SELECT `%s` AS `__loom_agg_key` FROM (%s) AS __loom_values", column, union) - if len(where) > 0 { - branch += " WHERE " + strings.Join(where, " AND ") - } - return []string{branch}, args, nil -} - -// NormalizeAggregationResults provides deterministic result ordering for -// callers that combine multiple independently executed specifications. -func NormalizeAggregationResults(results []AggregationResult) []AggregationResult { - copyResults := append([]AggregationResult(nil), results...) - sort.Slice(copyResults, func(i, j int) bool { return copyResults[i].Name < copyResults[j].Name }) - return copyResults -} diff --git a/internal/dataframe/published/federation.go b/internal/dataframe/published/federation.go index 1582e1a5..4f60cedf 100644 --- a/internal/dataframe/published/federation.go +++ b/internal/dataframe/published/federation.go @@ -129,22 +129,6 @@ type FederatedStreamRequest struct { AccessByProject map[string]SourceAccess } -// FederatedAggregateRequest describes an aggregate over the same authorized -// union used by row reads. -type FederatedAggregateRequest struct { - GroupBy []string - Filters []Filter - Operation string - Column string - AccessByProject map[string]SourceAccess -} - -type FederatedAggregateResult struct { - Dataset FederatedDataset - Columns []string - Rows []map[string]any -} - func normalizedProjects(projects []string) []string { seen := make(map[string]struct{}, len(projects)) result := make([]string, 0, len(projects)) @@ -892,88 +876,6 @@ func datasetVisibleColumns(dataset FederatedDataset) []string { return result } -func (r *Reader) AggregateFederatedDataset(ctx context.Context, dataset FederatedDataset, req FederatedAggregateRequest) (FederatedAggregateResult, error) { - if r == nil || r.ClickHouse == nil { - return FederatedAggregateResult{}, dataframeerrors.NewError(dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) - } - allowed := make(map[string]struct{}, len(dataset.Columns)) - for _, column := range dataset.Columns { - if column.Name == authResourcePathColumn || column.Name == "__loom_row_id" { - continue - } - allowed[column.Name] = struct{}{} - } - for _, column := range req.GroupBy { - if _, ok := allowed[column]; !ok { - return FederatedAggregateResult{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") - } - } - operation := strings.ToUpper(req.Operation) - if operation != "COUNT" && operation != "COUNT_DISTINCT" && operation != "SUM" && operation != "AVG" && operation != "MIN" && operation != "MAX" { - return FederatedAggregateResult{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") - } - if operation != "COUNT" { - if _, ok := allowed[req.Column]; !ok { - return FederatedAggregateResult{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") - } - } - columns := append([]string(nil), req.GroupBy...) - metricName := strings.ToLower(operation) - if operation == "COUNT" { - metricName = "count" - } - columns = append(columns, metricName) - unionColumns := append([]string(nil), req.GroupBy...) - if operation != "COUNT" && !contains(unionColumns, req.Column) { - unionColumns = append(unionColumns, req.Column) - } - for _, filter := range req.Filters { - if !contains(unionColumns, filter.Column) { - unionColumns = append(unionColumns, filter.Column) - } - } - union, args, err := federatedNormalizedUnion(dataset, unionColumns, req.AccessByProject) - if err != nil { - return FederatedAggregateResult{}, err - } - where, whereArgs, err := buildWhere(req.Filters, allowed) - if err != nil { - return FederatedAggregateResult{}, err - } - args = append(args, whereArgs...) - metric := "count()" - switch operation { - case "COUNT_DISTINCT": - metric = fmt.Sprintf("uniqExact(`%s`)", req.Column) - case "SUM": - metric = fmt.Sprintf("sum(`%s`)", req.Column) - case "AVG": - metric = fmt.Sprintf("avg(`%s`)", req.Column) - case "MIN": - metric = fmt.Sprintf("min(`%s`)", req.Column) - case "MAX": - metric = fmt.Sprintf("max(`%s`)", req.Column) - } - selectExpr := make([]string, 0, len(req.GroupBy)+1) - for _, group := range req.GroupBy { - selectExpr = append(selectExpr, fmt.Sprintf("`%s`", group)) - } - selectExpr = append(selectExpr, metric+" AS `"+metricName+"`") - query := fmt.Sprintf("SELECT %s FROM (%s) AS __loom_aggregate", strings.Join(selectExpr, ", "), union) - if len(where) > 0 { - query += " WHERE " + strings.Join(where, " AND ") - } - query += aggregateGroupOrderClause(req.GroupBy) - rows, err := r.ClickHouse.QueryRowsArgs(ctx, query, columns, args...) - if err != nil { - if r.Logger != nil { - r.Logger.Error("clickhouse federated aggregate failed", "query_id", shortQueryID(query), "query", query, "bind_count", len(args), "error", err) - } - return FederatedAggregateResult{}, backendCallError(err) - } - return FederatedAggregateResult{Dataset: dataset, Columns: columns, Rows: rows}, nil -} - func federatedColumns(dataset FederatedDataset, requested []string, sort *Sort) ([]string, map[string]struct{}, error) { for _, column := range requested { if column == authResourcePathColumn { @@ -1080,14 +982,6 @@ func quotedColumns(columns []string) string { return strings.Join(quoted, ", ") } -func aggregateGroupOrderClause(groupBy []string) string { - if len(groupBy) == 0 { - return "" - } - columns := quotedColumns(groupBy) - return " GROUP BY " + columns + " ORDER BY " + columns -} - func shortQueryID(query string) string { digest := sha256.Sum256([]byte(query)) return hex.EncodeToString(digest[:8]) diff --git a/internal/dataframe/published/federation_test.go b/internal/dataframe/published/federation_test.go index 2c9b71cd..677387e0 100644 --- a/internal/dataframe/published/federation_test.go +++ b/internal/dataframe/published/federation_test.go @@ -151,13 +151,6 @@ func TestFederatedUnionSynthesizesProjectIDForLegacySource(t *testing.T) { } } -func TestAggregateGroupOrderClauseGroupsBeforeOrdering(t *testing.T) { - clause := aggregateGroupOrderClause([]string{"project_id", "status"}) - if clause != " GROUP BY `project_id`, `status` ORDER BY `project_id`, `status`" { - t.Fatalf("aggregate group/order clause = %q", clause) - } -} - type federationCatalog struct { bundlepublication.BundleCatalog executions []bundlepublication.BundleExecution diff --git a/internal/dataframe/published/read.go b/internal/dataframe/published/read.go index 7d151b41..3a12c71f 100644 --- a/internal/dataframe/published/read.go +++ b/internal/dataframe/published/read.go @@ -1,6 +1,7 @@ package published import ( + "context" "encoding/base64" "encoding/json" "fmt" @@ -11,11 +12,15 @@ import ( dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" bundlepublication "github.com/calypr/loom/internal/dataframe/publication" publication "github.com/calypr/loom/internal/dataset" - "github.com/calypr/loom/internal/store/clickhouse" ) +type ClickHouseQueryer interface { + QueryRowsArgs(context.Context, string, []string, ...any) ([]map[string]any, error) + QueryRowsArgsVisit(context.Context, string, []string, func(map[string]any) error, ...any) error +} + type Reader struct { - ClickHouse *clickhouse.Client + ClickHouse ClickHouseQueryer Catalog bundlepublication.BundleCatalog Logger *slog.Logger MaxPage int diff --git a/internal/explorer/config_v2.go b/internal/explorer/config_v2.go index f73e230e..5fd64252 100644 --- a/internal/explorer/config_v2.go +++ b/internal/explorer/config_v2.go @@ -22,6 +22,16 @@ const ConfigV2APIVersion = "loom.calypr.org/explorer-config/v2" var idPattern = regexp.MustCompile(`^[a-z][a-z0-9-]{0,63}$`) +// ConfigManagementForID returns the management value required inside a V2 +// packet for the durable Explorer identity. The repository default keeps its +// repository identity even though Builder users may edit and publish it. +func ConfigManagementForID(explorerID string) string { + if explorerID == "default" { + return "repository" + } + return "interactive" +} + type ConfigV2 struct { APIVersion string `json:"apiVersion"` Kind string `json:"kind"` diff --git a/internal/explorer/service.go b/internal/explorer/service.go index 8b6d0502..fbcc180e 100644 --- a/internal/explorer/service.go +++ b/internal/explorer/service.go @@ -132,12 +132,12 @@ func RepositoryRevisionID(project, sourceCommit, definitionDigest, sourceGenerat return "repository_" + hex.EncodeToString(sum[:]) } -// CreateInteractiveV2 persists a complete V2 draft without compiling or -// materializing it. The raw canonical packet is retained alongside the digest -// so presentation-only fields survive a later read unchanged. +// CreateInteractiveV2 persists a complete custom V2 draft without compiling or +// materializing it. The repository default is created by repository deploys; +// it uses SaveDraftV2 for subsequent Builder edits. func (s *Service) CreateInteractiveV2(ctx context.Context, project, id string, raw []byte, actor string) (*Explorer, error) { if id == "default" { - return nil, fmt.Errorf("default Explorer is repository-managed") + return nil, fmt.Errorf("default Explorer already exists; edit its draft") } cfg, _, canonical, digest, err := CanonicalConfigV2(raw, project, id, "interactive") if err != nil { @@ -150,23 +150,59 @@ func (s *Service) CreateInteractiveV2(ctx context.Context, project, id string, r }) } -// SaveInteractiveDraftV2 is the only V2 draft write path. It performs no -// compilation or materialization and supplies both CAS components to the -// durable adapter. -func (s *Service) SaveInteractiveDraftV2(ctx context.Context, project, id string, raw []byte, expected int64, expectedDigest, actor string) (*Explorer, error) { - if id == "default" { - return nil, fmt.Errorf("default Explorer is repository-managed") - } - cfg, _, canonical, digest, err := CanonicalConfigV2(raw, project, id, "interactive") +// SaveDraftV2 is the only V2 draft write path. It performs no compilation or +// materialization and supplies both CAS components to the durable adapter. +// The repository default is editable; its repository identity is retained in +// the packet so a later ETL deployment can still recognize it. +func (s *Service) SaveDraftV2(ctx context.Context, project, id string, raw []byte, expected int64, expectedDigest, actor string) (*Explorer, error) { + management := ConfigManagementForID(id) + cfg, _, canonical, digest, err := CanonicalConfigV2(raw, project, id, management) if err != nil { return nil, err } current, err := s.store.Get(ctx, project, id) + if errors.Is(err, ErrNotFound) && id == "default" { + repository, repositoryErr := s.store.GetRepositoryConfig(ctx, project) + if repositoryErr != nil { + return nil, repositoryErr + } + baseVersion := repository.DraftVersion + if baseVersion == 0 { + baseVersion = 1 + } + baseDigest := repository.ConfigDigest + if baseDigest == "" { + _, _, _, baseDigest, _ = CanonicalConfigV2(repository.Config, project, "default", "repository") + } + if expected != baseVersion || (expectedDigest != "" && expectedDigest != baseDigest) { + return nil, ErrDraftConflict + } + updatedAt := repository.UpdatedAt + if updatedAt.IsZero() { + updatedAt = s.now() + } + current, err = s.store.CreateRepository(ctx, Explorer{ + Project: project, ExplorerID: "default", Title: cfg.Explorer.Title, + ManagementMode: ManagementRepository, DraftConfig: append([]byte(nil), repository.Config...), + DraftVersion: baseVersion, DraftDigest: baseDigest, + ActiveRevisionID: repository.ActiveRevisionID, ActiveConfig: append([]byte(nil), repository.Config...), + SourceGeneration: repository.SourceGeneration, Materializations: append([]Materialization(nil), repository.Materializations...), + Dataset: repository.Dataset, Publication: repository.Publication, Diagnostics: append([]Diagnostic(nil), repository.Diagnostics...), + UpdatedBy: "repository", UpdatedAt: updatedAt, + }) + if errors.Is(err, ErrDraftConflict) { + current, err = s.store.Get(ctx, project, id) + } + } if err != nil { return nil, err } - if current.ManagementMode != ManagementInteractive { - return nil, fmt.Errorf("Explorer is not interactive") + expectedManagement := ManagementInteractive + if id == "default" { + expectedManagement = ManagementRepository + } + if current.ManagementMode != expectedManagement { + return nil, fmt.Errorf("Explorer management mode does not match its identity") } current.Title = cfg.Explorer.Title current.DraftConfig = canonical @@ -175,9 +211,9 @@ func (s *Service) SaveInteractiveDraftV2(ctx context.Context, project, id string return s.store.SaveDraft(ctx, *current, expected, expectedDigest) } -func (s *Service) InsertInteractiveReadyRevisionV2(ctx context.Context, owner *Explorer, config []byte, configDigest string, compiled Compilation, resolvedSchemaDigest, sourceGeneration, actor string, materializations []Materialization) (*Revision, error) { - if owner == nil || owner.ManagementMode != ManagementInteractive { - return nil, fmt.Errorf("Explorer is not interactive") +func (s *Service) InsertReadyRevisionV2(ctx context.Context, owner *Explorer, config []byte, configDigest string, compiled Compilation, resolvedSchemaDigest, sourceGeneration, actor string, materializations []Materialization) (*Revision, error) { + if owner == nil || (owner.ManagementMode != ManagementInteractive && !(owner.ExplorerID == "default" && owner.ManagementMode == ManagementRepository)) { + return nil, fmt.Errorf("Explorer is not editable") } id, err := NewInteractiveRevisionID() if err != nil { @@ -210,9 +246,9 @@ func datasetMetadata(generation, schemaDigest string, materializations []Materia return DatasetMetadata{Generation: generation, SchemaDigest: schemaDigest, Outputs: outputs} } -func (s *Service) InsertInteractiveFailedRevisionV2(ctx context.Context, owner *Explorer, config []byte, configDigest, sourceGeneration, actor string, diagnostics []Diagnostic) (*Revision, error) { - if owner == nil || owner.ManagementMode != ManagementInteractive { - return nil, fmt.Errorf("Explorer is not interactive") +func (s *Service) InsertFailedRevisionV2(ctx context.Context, owner *Explorer, config []byte, configDigest, sourceGeneration, actor string, diagnostics []Diagnostic) (*Revision, error) { + if owner == nil || (owner.ManagementMode != ManagementInteractive && !(owner.ExplorerID == "default" && owner.ManagementMode == ManagementRepository)) { + return nil, fmt.Errorf("Explorer is not editable") } id, err := NewInteractiveRevisionID() if err != nil { diff --git a/internal/explorer/v2_lifecycle_test.go b/internal/explorer/v2_lifecycle_test.go index a031e517..df24cb4e 100644 --- a/internal/explorer/v2_lifecycle_test.go +++ b/internal/explorer/v2_lifecycle_test.go @@ -33,14 +33,14 @@ func TestV2DraftRoundTripAndDigestCAS(t *testing.T) { if err != nil { t.Fatal(err) } - updated, err := service.SaveInteractiveDraftV2(context.Background(), "project-a", "my-explorer", updatedRaw, 1, created.DraftDigest, "author") + updated, err := service.SaveDraftV2(context.Background(), "project-a", "my-explorer", updatedRaw, 1, created.DraftDigest, "author") if err != nil { t.Fatal(err) } if updated.DraftVersion != 2 || updated.DraftDigest != nextDigest { t.Fatalf("updated metadata = %#v", updated) } - if _, err := service.SaveInteractiveDraftV2(context.Background(), "project-a", "my-explorer", raw, 1, created.DraftDigest, "stale"); err != ErrDraftConflict { + if _, err := service.SaveDraftV2(context.Background(), "project-a", "my-explorer", raw, 1, created.DraftDigest, "stale"); err != ErrDraftConflict { t.Fatalf("stale digest/version save error = %v, want ErrDraftConflict", err) } } diff --git a/internal/server/explorer_v2_engine.go b/internal/server/explorer_v2_engine.go index f7310c20..97f0859b 100644 --- a/internal/server/explorer_v2_engine.go +++ b/internal/server/explorer_v2_engine.go @@ -15,7 +15,7 @@ type explorerV2CatalogReader func(context.Context, string, string, string) (expl func explorerV2Compiler(recipeEngine *engine.Engine, catalogReader explorerV2CatalogReader) ExplorerV2Compiler { return func(ctx context.Context, request ExplorerV2CompileRequest) (ExplorerV2CompileResult, error) { - cfg, bundle, canonical, digest, err := explorer.CanonicalConfigV2(request.Config, request.Project, request.ExplorerID, "interactive") + cfg, bundle, canonical, digest, err := explorer.CanonicalConfigV2(request.Config, request.Project, request.ExplorerID, explorer.ConfigManagementForID(request.ExplorerID)) if err != nil { return ExplorerV2CompileResult{}, err } diff --git a/internal/server/explorer_v2_lifecycle.go b/internal/server/explorer_v2_lifecycle.go index d38ba6dc..2f40a133 100644 --- a/internal/server/explorer_v2_lifecycle.go +++ b/internal/server/explorer_v2_lifecycle.go @@ -58,10 +58,10 @@ type explorerV2State struct { Project string `json:"project"` ExplorerID string `json:"explorerId"` Management explorer.ManagementMode `json:"management"` - // BaselineConfig is present for the repository default. It is always the - // presentation-free recipe/schema baseline, even when the published - // repository packet also contains an ETL-authored presentation layer. - BaselineConfig json.RawMessage `json:"baselineConfig,omitempty"` + // BaselineConfig is present for the repository default. It is the + // presentation-free recipe/schema projection of the current default draft. + BaselineConfig json.RawMessage `json:"baselineConfig,omitempty"` + // DraftConfig is returned for custom Explorers and for the editable default. DraftConfig json.RawMessage `json:"draftConfig,omitempty"` DraftVersion int64 `json:"draftVersion"` DraftDigest string `json:"draftDigest"` @@ -146,7 +146,7 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author "resolvedSchemaDigest": snapshot.ResolvedSchemaDigest, "nodes": nodes, "selections": selections, "routeEdges": edges, "completeness": fiber.Map{"complete": snapshot.Complete, "truncated": snapshot.Truncated, "diagnostics": snapshot.Diagnostics}, - "diagnostics": snapshot.Diagnostics, + "diagnostics": snapshot.Diagnostics, }) }) @@ -175,7 +175,7 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author } id := explorer.StableExplorerID(name) if id == "default" { - return explorerV2Error(c, http.StatusForbidden, "DEFAULT_READ_ONLY", "the repository default is read-only") + return explorerV2Error(c, http.StatusConflict, "EXPLORER_EXISTS", "the repository default already exists; edit its draft") } title := strings.TrimSpace(request.Title) if title == "" { @@ -213,9 +213,6 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author app.Put("/api/v1/projects/:project/explorers/:explorerId/draft", func(c fiber.Ctx) error { project, id := strings.TrimSpace(c.Params("project")), strings.TrimSpace(c.Params("explorerId")) - if id == "default" { - return explorerV2Error(c, http.StatusForbidden, "DEFAULT_READ_ONLY", "the repository default is read-only") - } if err := authorizeExplorerWrite(c, authorizer, project); err != nil { return err } @@ -230,16 +227,16 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author } return explorerV2Error(c, http.StatusBadRequest, "MALFORMED_REQUEST", err.Error()) } - _, _, canonical, _, err := explorer.CanonicalConfigV2(request.Config, project, id, "interactive") + _, _, canonical, _, err := explorer.CanonicalConfigV2(request.Config, project, id, explorer.ConfigManagementForID(id)) if err != nil { return explorerV2Error(c, http.StatusUnprocessableEntity, "INVALID_CONFIG", err.Error()) } - value, err := explorers.SaveInteractiveDraftV2(c.Context(), project, id, canonical, *request.ExpectedDraftVersion, request.ExpectedDraftDigest, subjectFromFiber(c)) + value, err := explorers.SaveDraftV2(c.Context(), project, id, canonical, *request.ExpectedDraftVersion, request.ExpectedDraftDigest, subjectFromFiber(c)) if errors.Is(err, explorer.ErrDraftConflict) { return draftConflictResponse(c, explorers, project, id) } if errors.Is(err, explorer.ErrNotFound) { - return explorerV2Error(c, http.StatusNotFound, "EXPLORER_NOT_FOUND", "custom Explorer not found") + return explorerV2Error(c, http.StatusNotFound, "EXPLORER_NOT_FOUND", "Explorer not found") } if err != nil { return explorerV2Error(c, http.StatusUnprocessableEntity, "DRAFT_SAVE_FAILED", err.Error()) @@ -249,9 +246,6 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author app.Post("/api/v1/projects/:project/explorers/:explorerId/authoring/compile", func(c fiber.Ctx) error { project, id := strings.TrimSpace(c.Params("project")), strings.TrimSpace(c.Params("explorerId")) - if id == "default" { - return explorerV2Error(c, http.StatusForbidden, "DEFAULT_READ_ONLY", "the repository default is read-only") - } if err := authorizeExplorerWrite(c, authorizer, project); err != nil { return err } @@ -323,9 +317,6 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author app.Post("/api/v1/projects/:project/explorers/:explorerId/publish", func(c fiber.Ctx) error { project, id := strings.TrimSpace(c.Params("project")), strings.TrimSpace(c.Params("explorerId")) - if id == "default" { - return explorerV2Error(c, http.StatusForbidden, "DEFAULT_READ_ONLY", "the repository default is read-only") - } if err := authorizeExplorerWrite(c, authorizer, project); err != nil { return err } @@ -341,7 +332,7 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author } owner, err := explorers.Get(c.Context(), project, id) if errors.Is(err, explorer.ErrNotFound) { - return explorerV2Error(c, http.StatusNotFound, "EXPLORER_NOT_FOUND", "custom Explorer not found") + return explorerV2Error(c, http.StatusNotFound, "EXPLORER_NOT_FOUND", "Explorer not found") } if err != nil { return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error()) @@ -371,12 +362,18 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author if sourceGeneration == "" { sourceGeneration = execution.SourceGeneration } - revision, err := explorers.InsertInteractiveReadyRevisionV2(c.Context(), owner, result.Config, digest, compiled, result.ResolvedSchemaDigest, sourceGeneration, subjectFromFiber(c), materializations) + revision, err := explorers.InsertReadyRevisionV2(c.Context(), owner, result.Config, digest, compiled, result.ResolvedSchemaDigest, sourceGeneration, subjectFromFiber(c), materializations) if err != nil { return explorerV2Error(c, http.StatusInternalServerError, "REVISION_INSERT_FAILED", err.Error()) } - if err := explorers.ActivateInteractive(c.Context(), project, id, revision.ID); err != nil { - return explorerV2Error(c, http.StatusConflict, "ACTIVATION_FAILED", err.Error()) + var activationErr error + if id == "default" { + activationErr = explorers.ActivateRepository(c.Context(), project, revision.ID) + } else { + activationErr = explorers.ActivateInteractive(c.Context(), project, id, revision.ID) + } + if activationErr != nil { + return explorerV2Error(c, http.StatusConflict, "ACTIVATION_FAILED", activationErr.Error()) } state, err := getExplorerV2State(c.Context(), explorers, project, id) if err != nil { @@ -469,7 +466,8 @@ type v2HTTPError struct { func (e *v2HTTPError) Error() string { return e.message } func compileExplorerV2(ctx context.Context, compiler ExplorerV2Compiler, request ExplorerV2CompileRequest) (ExplorerV2CompileResult, string, error) { - _, bundle, canonical, digest, err := explorer.CanonicalConfigV2(request.Config, request.Project, request.ExplorerID, "interactive") + management := explorer.ConfigManagementForID(request.ExplorerID) + _, bundle, canonical, digest, err := explorer.CanonicalConfigV2(request.Config, request.Project, request.ExplorerID, management) if err != nil { return ExplorerV2CompileResult{}, digest, err } @@ -481,7 +479,7 @@ func compileExplorerV2(ctx context.Context, compiler ExplorerV2Compiler, request if len(result.Config) == 0 { result.Config = canonical } - if _, _, normalized, _, err := explorer.CanonicalConfigV2(result.Config, request.Project, request.ExplorerID, "interactive"); err != nil { + if _, _, normalized, _, err := explorer.CanonicalConfigV2(result.Config, request.Project, request.ExplorerID, management); err != nil { return ExplorerV2CompileResult{}, digest, err } else { result.Config = normalized @@ -562,7 +560,7 @@ func executionMaterializations(bundle recipe.Bundle, execution graphresolver.Rec } func insertFailedV2Revision(ctx context.Context, service *explorer.Service, owner *explorer.Explorer, config []byte, digest, generation, actor string, diagnostics []explorer.Diagnostic) error { - _, err := service.InsertInteractiveFailedRevisionV2(ctx, owner, config, digest, generation, actor, diagnostics) + _, err := service.InsertFailedRevisionV2(ctx, owner, config, digest, generation, actor, diagnostics) return err } @@ -623,7 +621,7 @@ func getExplorerV2State(ctx context.Context, service *explorer.Service, project, if version == 0 { version = 1 } - return &explorerV2State{Project: project, ExplorerID: "default", Management: explorer.ManagementRepository, BaselineConfig: repositoryBaselineConfig(repository.Config), DraftVersion: version, DraftDigest: digest, ActiveConfig: cloneRaw(repository.Config), ActiveRevisionID: repository.ActiveRevisionID, SourceGeneration: repository.SourceGeneration, Materializations: repository.Materializations, Dataset: repository.Dataset, Publication: repository.Publication, Diagnostics: repository.Diagnostics, PublicationState: repository.Publication.State, ActiveURL: explorerURL(project, "default"), UpdatedAt: repository.UpdatedAt}, nil + return &explorerV2State{Project: project, ExplorerID: "default", Management: explorer.ManagementRepository, BaselineConfig: repositoryBaselineConfig(repository.Config), DraftConfig: cloneRaw(repository.Config), DraftVersion: version, DraftDigest: digest, ActiveConfig: cloneRaw(repository.Config), ActiveRevisionID: repository.ActiveRevisionID, SourceGeneration: repository.SourceGeneration, Materializations: repository.Materializations, Dataset: repository.Dataset, Publication: repository.Publication, Diagnostics: repository.Diagnostics, PublicationState: repository.Publication.State, ActiveURL: explorerURL(project, "default"), UpdatedAt: repository.UpdatedAt}, nil } func listExplorerV2States(ctx context.Context, service *explorer.Service, project string) ([]*explorerV2State, error) { @@ -675,7 +673,7 @@ func listExplorerV2States(ctx context.Context, service *explorer.Service, projec func stateFromExplorer(value *explorer.Explorer) *explorerV2State { if value.ManagementMode == explorer.ManagementRepository { - return &explorerV2State{Project: value.Project, ExplorerID: value.ExplorerID, Management: value.ManagementMode, BaselineConfig: repositoryBaselineConfig(value.DraftConfig), DraftVersion: value.DraftVersion, DraftDigest: value.DraftDigest, ActiveConfig: cloneRaw(value.ActiveConfig), ActiveRevisionID: value.ActiveRevisionID, RecipeDigest: value.RecipeDigest, ResolvedSchemaDigest: value.ResolvedSchemaDigest, SourceGeneration: value.SourceGeneration, EmittedColumns: append([]explorer.EmittedColumn(nil), value.EmittedColumns...), Materializations: append([]explorer.Materialization(nil), value.Materializations...), Dataset: value.Dataset, Publication: value.Publication, Diagnostics: append([]explorer.Diagnostic(nil), value.Diagnostics...), PublicationState: value.Publication.State, ActiveURL: explorerURL(value.Project, value.ExplorerID), UpdatedBy: value.UpdatedBy, UpdatedAt: value.UpdatedAt} + return &explorerV2State{Project: value.Project, ExplorerID: value.ExplorerID, Management: value.ManagementMode, BaselineConfig: repositoryBaselineConfig(value.DraftConfig), DraftConfig: cloneRaw(value.DraftConfig), DraftVersion: value.DraftVersion, DraftDigest: value.DraftDigest, ActiveConfig: cloneRaw(value.ActiveConfig), ActiveRevisionID: value.ActiveRevisionID, RecipeDigest: value.RecipeDigest, ResolvedSchemaDigest: value.ResolvedSchemaDigest, SourceGeneration: value.SourceGeneration, EmittedColumns: append([]explorer.EmittedColumn(nil), value.EmittedColumns...), Materializations: append([]explorer.Materialization(nil), value.Materializations...), Dataset: value.Dataset, Publication: value.Publication, Diagnostics: append([]explorer.Diagnostic(nil), value.Diagnostics...), PublicationState: value.Publication.State, ActiveURL: explorerURL(value.Project, value.ExplorerID), UpdatedBy: value.UpdatedBy, UpdatedAt: value.UpdatedAt} } return &explorerV2State{Project: value.Project, ExplorerID: value.ExplorerID, Management: value.ManagementMode, DraftConfig: cloneRaw(value.DraftConfig), DraftVersion: value.DraftVersion, DraftDigest: value.DraftDigest, ActiveConfig: cloneRaw(value.ActiveConfig), ActiveRevisionID: value.ActiveRevisionID, RecipeDigest: value.RecipeDigest, ResolvedSchemaDigest: value.ResolvedSchemaDigest, SourceGeneration: value.SourceGeneration, EmittedColumns: append([]explorer.EmittedColumn(nil), value.EmittedColumns...), Materializations: append([]explorer.Materialization(nil), value.Materializations...), Dataset: value.Dataset, Publication: value.Publication, Diagnostics: append([]explorer.Diagnostic(nil), value.Diagnostics...), PublicationState: publicationState(value.ActiveRevisionID), ActiveURL: explorerURL(value.Project, value.ExplorerID), UpdatedBy: value.UpdatedBy, UpdatedAt: value.UpdatedAt} } diff --git a/internal/server/explorer_v2_lifecycle_test.go b/internal/server/explorer_v2_lifecycle_test.go index 9221ba7f..9476b395 100644 --- a/internal/server/explorer_v2_lifecycle_test.go +++ b/internal/server/explorer_v2_lifecycle_test.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + "fmt" "io" "net/http" "net/http/httptest" @@ -37,10 +38,15 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { if _, err := service.SaveRepositoryConfig(context.Background(), explorer.RepositoryConfig{Project: "project-a", Config: repository, SourceGeneration: "generation-a"}); err != nil { t.Fatal(err) } + repositoryBundle := testV2Bundle("repository") bundle := testV2Bundle("explorer-custom") compile := func(_ context.Context, request ExplorerV2CompileRequest) (ExplorerV2CompileResult, error) { - digest, _ := bundle.Digest() - return ExplorerV2CompileResult{Config: request.Config, Bundle: bundle, RecipeDigest: digest, SourceGeneration: "generation-a", EmittedColumns: []explorer.EmittedColumn{{OutputID: "DocumentReference", PublicColumn: "id", SelectionID: "id", LogicalType: "string"}}}, nil + compiledBundle := bundle + if request.ExplorerID == "default" { + compiledBundle = repositoryBundle + } + digest, _ := compiledBundle.Digest() + return ExplorerV2CompileResult{Config: request.Config, Bundle: compiledBundle, RecipeDigest: digest, SourceGeneration: "generation-a", EmittedColumns: []explorer.EmittedColumn{{OutputID: "DocumentReference", PublicColumn: "id", SelectionID: "id", LogicalType: "string"}}}, nil } preview := func(_ context.Context, _ recipe.Bundle, _ recipe.RuntimeBindings) (map[string][]map[string]any, error) { return map[string][]map[string]any{"DocumentReference": {{"id": "dr-1"}}}, nil @@ -88,7 +94,7 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { } var defaultState explorerV2State decodeBody(t, defaultResponse.Body, &defaultState) - if len(defaultState.BaselineConfig) == 0 || len(defaultState.ActiveConfig) == 0 || len(defaultState.DraftConfig) != 0 { + if len(defaultState.BaselineConfig) == 0 || len(defaultState.DraftConfig) == 0 || len(defaultState.ActiveConfig) == 0 { t.Fatalf("default state lifecycle config mismatch: %#v", defaultState) } var defaultConfig explorer.ConfigV2 @@ -101,10 +107,38 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { if len(activeDefaultConfig.Views) != 1 || activeDefaultConfig.Views[0].Output != "DocumentReference" { t.Fatalf("default active config lost presentation: %#v", activeDefaultConfig.Views) } - defaultWrite := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/default/draft", `{}`) - if defaultWrite.StatusCode != http.StatusForbidden || !strings.Contains(defaultWrite.Body, `"code":"DEFAULT_READ_ONLY"`) { + var defaultDraft map[string]any + if err := json.Unmarshal(defaultState.DraftConfig, &defaultDraft); err != nil { + t.Fatal(err) + } + defaultDraft["explorer"].(map[string]any)["title"] = "Edited Default" + defaultDraftBytes, _ := json.Marshal(defaultDraft) + defaultDraftRequest, _ := json.Marshal(map[string]any{"config": json.RawMessage(defaultDraftBytes), "expectedDraftVersion": defaultState.DraftVersion, "expectedDraftDigest": defaultState.DraftDigest}) + defaultWrite := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/default/draft", string(defaultDraftRequest)) + if defaultWrite.StatusCode != http.StatusOK { t.Fatalf("default draft write status=%d body=%s", defaultWrite.StatusCode, defaultWrite.Body) } + var updatedDefault explorerV2State + decodeBody(t, defaultWrite.Body, &updatedDefault) + if updatedDefault.DraftVersion != defaultState.DraftVersion+1 || updatedDefault.DraftDigest == defaultState.DraftDigest { + t.Fatalf("default draft state=%#v", updatedDefault) + } + defaultCompileRequest, _ := json.Marshal(map[string]any{"output": "DocumentReference", "config": json.RawMessage(updatedDefault.DraftConfig), "expectedDraftVersion": updatedDefault.DraftVersion}) + defaultCompiled := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/default/authoring/compile", string(defaultCompileRequest)) + if defaultCompiled.StatusCode != http.StatusOK { + t.Fatalf("default compile status=%d body=%s", defaultCompiled.StatusCode, defaultCompiled.Body) + } + defaultPublishRequest := `{"expectedDraftVersion":` + fmt.Sprint(updatedDefault.DraftVersion) + `,"expectedDraftDigest":"` + updatedDefault.DraftDigest + `"}` + defaultPublished := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/default/publish", defaultPublishRequest) + if defaultPublished.StatusCode != http.StatusOK || !strings.Contains(defaultPublished.Body, `"publicationId"`) { + t.Fatalf("default publish status=%d body=%s", defaultPublished.StatusCode, defaultPublished.Body) + } + defaultAfterPublish := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/default", "") + var activeDefaultState explorerV2State + decodeBody(t, defaultAfterPublish.Body, &activeDefaultState) + if defaultAfterPublish.StatusCode != http.StatusOK || activeDefaultState.ActiveRevisionID == "" || string(activeDefaultState.ActiveConfig) != string(activeDefaultState.DraftConfig) { + t.Fatalf("default active state=%#v", activeDefaultState) + } var draft map[string]any if err := json.Unmarshal(created.DraftConfig, &draft); err != nil { @@ -215,7 +249,7 @@ func TestRepositoryStateExposesPublishedPacketAndPresentationFreeBaseline(t *tes var baseline, active explorer.ConfigV2 decodeBody(t, string(state.BaselineConfig), &baseline) decodeBody(t, string(state.ActiveConfig), &active) - if len(baseline.Views) != 0 || len(active.Views) != 1 || active.Views[0].Output != "DocumentReference" || len(state.DraftConfig) != 0 { + if len(baseline.Views) != 0 || len(active.Views) != 1 || active.Views[0].Output != "DocumentReference" || len(state.DraftConfig) == 0 { t.Fatalf("repository state did not separate lifecycle configs: baseline=%#v active=%#v state=%#v", baseline.Views, active.Views, state) } } From 6c49754442856e1bd5f3f9770d37d459464ef377 Mon Sep 17 00:00:00 2001 From: matthewpeterkort Date: Tue, 18 Aug 2026 15:34:45 -0700 Subject: [PATCH 05/15] perf improvements --- README.md | 1 + ...ONTEND_DATAFRAME_FACET_PERFORMANCE_PLAN.md | 467 ++++++++++++++++++ docs/FRONTEND_EXPLORER_V2_MIGRATION.md | 14 +- docs/loom-reliability-contract.md | 6 + .../graph/aggregate_http_integration_test.go | 104 ++++ .../graphql/graph/materialization/service.go | 24 +- .../publication/arango/bundle_registry.go | 36 ++ internal/dataframe/publication/bundle.go | 7 + .../aggregate_clickhouse_integration_test.go | 19 +- .../published/aggregate_plan_test.go | 35 ++ internal/dataframe/published/aggregate_sql.go | 6 +- internal/dataframe/published/federation.go | 68 +++ internal/dataframe/published/read.go | 15 +- internal/dataset/release_test.go | 33 ++ internal/server/explorer_config_route.go | 7 + internal/server/explorer_config_route_test.go | 14 +- internal/server/explorer_v2_lifecycle.go | 21 + internal/server/explorer_v2_lifecycle_test.go | 47 +- internal/server/federation_status.go | 33 +- internal/server/server.go | 18 +- 20 files changed, 942 insertions(+), 33 deletions(-) create mode 100644 docs/FRONTEND_DATAFRAME_FACET_PERFORMANCE_PLAN.md diff --git a/README.md b/README.md index e48ee12b..43e976d0 100644 --- a/README.md +++ b/README.md @@ -299,6 +299,7 @@ without rebuilding the server image. | [`internal/ingest`](internal/ingest) | NDJSON loading, validation, graph extraction, and ingest lifecycle. | | [`internal/dataset`](internal/dataset) | Immutable generation and active-manifest contracts. | | [`internal/catalog`](internal/catalog) | Evidence of populated fields, references, and authorization paths. | +| [`internal/explorer`](internal/explorer) | Editable Explorer V2 configs, drafts, immutable revisions, and publication state. | | [`internal/dataframe/compiler`](internal/dataframe/compiler) | Typed plan IR, lowering, optimization, and AQL rendering. | | [`internal/dataframe/recipe`](internal/dataframe/recipe) | Recipe contract, validation, schema resolution, execution, and control services. | | [`internal/dataframe/publication`](internal/dataframe/publication) | Backend-neutral bounded streaming publication contract. | diff --git a/docs/FRONTEND_DATAFRAME_FACET_PERFORMANCE_PLAN.md b/docs/FRONTEND_DATAFRAME_FACET_PERFORMANCE_PLAN.md new file mode 100644 index 00000000..76278f5a --- /dev/null +++ b/docs/FRONTEND_DATAFRAME_FACET_PERFORMANCE_PLAN.md @@ -0,0 +1,467 @@ +# Frontend Dataframe Facet Performance Plan + +## Purpose + +Use this document as the implementation plan in the frontend Codex workspace. +It is intentionally framework-neutral: the implementing agent should first +locate the existing Explorer table hooks, GraphQL documents, generated types, +and request-cache library, then map the steps below onto those components. + +The goal is to make the Explorer table feel fast without changing Loom's +GraphQL schema or inventing another endpoint. + +## Current problem and measured baseline + +The current table render eagerly requests 156 aliased `dataframeAggregate` +fields, including distributions for identifiers and reference-like columns. +It also sends dataset metadata, table rows, scalar counts, and facet +distributions as separate GraphQL operations. + +Measurements from the local Loom deployment on 2026-08-18: + +- The 156-facet operation takes approximately 1.05-1.22 seconds. +- It is already one ClickHouse statement, not 156 statements. +- Federation/project metadata takes approximately 653-669 ms. +- Aggregate planning, ClickHouse execution, and result decoding take + approximately 374-559 ms. +- A separate one-job count takes approximately 666 ms end-to-end even when + ClickHouse takes only 5 ms, demonstrating that repeated metadata resolution + is a major cost. +- Dataset, count, facet, and row requests have different request IDs, so Loom's + request-scoped project/federation cache cannot be shared across them. + +The 156 aliases are not themselves the bug. They are GraphQL response names. +The remaining problems are eager overfetching, unbounded legacy facet results, +and multiple HTTP operations for one logical table render. + +## Desired user experience + +1. Initial navigation renders the table, count, and immediately visible filter + controls from one GraphQL operation. +2. The page does not calculate distributions for every dataset column. +3. A facet is loaded only when it is visible, explicitly configured for eager + display, or opened by the user. +4. Facet menus return a bounded number of terms and clearly represent missing + and truncated results. +5. Reopening an unchanged facet is instant from the frontend cache. +6. Filter, sort, pagination, and publication changes cannot display stale + results from an older request. + +## Frozen backend contract + +Do not require Loom schema or route changes. Continue using: + +- `POST /loom/graphql/graph` (or the frontend's configured Loom GraphQL base). +- `dataframeRows(input: DataframeRowsInput!)`. +- `dataframeAggregate(input: DataframeAggregateInput!)` where a distinct + scalar count is genuinely required. +- `dataframeAggregations(input: DataframeAggregationsInput!)` for bounded + `TERMS` facets. + +The exact selector remains: + +```graphql +input DataframeSelectorInput { + recipe: String! + translationVersion: String! + output: String! +} +``` + +Never send a physical table name or infer a selector from a display label. + +## Target request architecture + +### Initial table render + +Replace separate dataset, rows, filtered-count, unfiltered-count, and eager +facet operations with one operation wherever their selector and filter state +are the same. + +Use this representative shape and adapt field names to the frontend's query +generator: + +```graphql +query ExplorerTableRender( + $rows: DataframeRowsInput! + $facets: DataframeAggregationsInput! +) { + table: dataframeRows(input: $rows) { + materialization { + id + name + revision + rowCount + availability + completeness + columns { + name + logicalType + nullable + repeated + filterable + sortable + aggregatable + } + } + columns + rows + totalCount + pageInfo { + hasNextPage + endCursor + } + } + + facets: dataframeAggregations(input: $facets) { + materialization { + id + revision + } + aggregations + } +} +``` + +The rows and facets variables must use the same selector and current filter +snapshot. Do not make the dataset metadata request separately: the +`dataframeRows.materialization` object already provides the column and +revision metadata needed by the table. + +Use `dataframeRows.totalCount` as the filtered row count. Do not issue another +ungrouped `COUNT` for the same filters. Add an aliased `dataframeAggregate` +field to this same operation only when the UI displays a genuinely different +count scope that cannot be derived from `totalCount` or materialization +metadata. + +If there are no eager facets, use a rows-only version of the document. Do not +send an empty `dataframeAggregations.specs` list because Loom rejects it. + +### Bounded facet specifications + +Represent facet menus with `TERMS`, not legacy unbounded `COUNT + groupBy`: + +```json +{ + "selector": { + "recipe": "calypr-meta-default", + "translationVersion": "...", + "output": "Patient" + }, + "filters": [], + "specs": [ + { + "name": "facet__project_id", + "kind": "TERMS", + "column": "project_id", + "size": 50, + "excludeSelfFilter": true + } + ] +} +``` + +Rules: + +- Default `size` to 50; make it configurable per filter and cap normal UI use + at 100. +- Use stable, collision-free spec names derived from the public column name. +- Use `excludeSelfFilter: true` for a column's own filter menu so selected + values remain visible while other active filters still constrain counts. +- Consume `missingCount` and `truncated` from the returned aggregation JSON. +- When `truncated` is true, label the list as partial and offer text entry or + another refinement mechanism. Do not imply that every distinct value was + returned. +- A `dataframeAggregations` field supports at most 50 specifications. Normal + initial rendering should remain well below that. If a deliberate bulk load + exceeds 50, split it deterministically into multiple aliased + `dataframeAggregations` fields in the same GraphQL operation. + +## Facet demand policy + +Do not derive eager facets from every column where `aggregatable == true`. +That flag means the operation is legal, not that it is useful at page load. + +Define one explicit frontend policy function, for example: + +```text +facetMode(column, explorerConfig) -> eager | lazy | none +``` + +Recommended policy: + +- `eager`: explicitly configured filter controls that are visible without user + interaction, such as project, status, category, or small enumerations. +- `lazy`: useful categorical/date/number filters whose menus are collapsed at + initial render. +- `none`: row identifiers, subject/patient identifiers, opaque identifiers, + free text, URLs, resource references, attachment paths, and other fields + whose distributions are high-cardinality or not meaningful as a menu. + +Prefer explicit Explorer configuration over name heuristics. A conservative +name heuristic may be used only as a fallback and must be overridable. In +particular, do not eagerly facet columns ending in `_id`, identifier values, +or `*_reference` merely because the backend says they are aggregatable. + +Set an initial safety budget, such as at most 12 eager facets. Additional +facets become lazy even if configured eager, with a development warning so a +configuration author can correct the layout. + +## Lazy facet loading + +When a facet control opens or becomes visible: + +1. Capture one immutable snapshot of selector and filters. +2. Remove only that facet's own predicates when `excludeSelfFilter` semantics + are desired; retain every other predicate. +3. Submit a bounded `dataframeAggregations` request containing that facet and + any other newly requested facets collected during a short batching window + (approximately one animation frame or 10-25 ms). +4. Deduplicate identical in-flight requests. +5. Cancel obsolete network requests with `AbortController` or the equivalent + supported by the existing GraphQL client. +6. Apply a response only if its selector, filter signature, and + materialization revision still match current table state. + +Do not fire one request per facet when several controls mount together. Batch +newly demanded facets into one `dataframeAggregations` field, up to 50 specs. + +## Frontend cache model + +Cache each facet independently even when several arrive in one response. + +The cache key must include: + +```text +selector recipe/version/output ++ materialization revision ++ public column name ++ aggregation kind and size ++ canonical effective filters after self-filter exclusion +``` + +Canonical filter rules: + +- Trim column and operation names; uppercase operations. +- Sort the final filter list because filters are combined with `AND`. +- Sort members of `IN`, `NOT_IN`, and `ARRAY_OVERLAPS` by stable JSON because + member order is not semantic. +- Preserve duplicate predicates. +- Use stable JSON encoding for values. + +The materialization revision makes published data immutable for the key. When +the revision changes, old entries may remain in the cache but must no longer +be selected. Apply a bounded LRU/TTL policy to prevent unlimited growth. + +Suggested freshness behavior: + +- Fresh for the current revision during the browser session. +- Revalidate after a configurable interval if the existing client library + requires it. +- Never reuse across different principals unless the application's existing + cache is already scoped to the authenticated session. + +## State management and race safety + +Create one table-render input model containing: + +- exact selector; +- selected row columns; +- canonical filters; +- sort; +- pagination cursor/page size; +- demanded facet columns; and +- materialization revision once known. + +Derive GraphQL variables from that model in one place. Do not let rows, count, +and facets independently read mutable filter state during the same render. + +On filter or sort changes: + +- reset the row cursor; +- preserve cached facets whose effective filter signature did not change; +- invalidate/refetch affected facets; +- cancel stale table-render requests; and +- retain the last successful rows/facets according to the product's existing + loading-state convention, rather than flashing an empty table unnecessarily. + +On selector or publication revision changes, invalidate the complete logical +table view. + +## Implementation sequence for the frontend Codex agent + +### 1. Discover the current request graph + +Search for: + +- `dataframeAggregate`, `dataframeAggregations`, and `dataframeRows` GraphQL + documents or query builders; +- the code that assigns aliases such as `a0` through `a155`; +- hooks/stores for dataset metadata, total count, rows, and facets; +- Explorer column/filter configuration types; +- the GraphQL client's request deduplication and cancellation support; and +- current performance telemetry and request-ID handling. + +Document which component triggers each current HTTP operation before editing. + +### 2. Add pure policy and canonicalization utilities + +Implement and unit-test: + +- facet mode selection (`eager`, `lazy`, `none`); +- eager facet budget enforcement; +- stable facet spec naming; +- canonical filter signatures; and +- independent facet cache keys. + +Keep these functions framework-independent. + +### 3. Introduce one table-render query builder + +Build one GraphQL operation containing rows, materialization metadata, and +bounded eager facets. Reuse `rows.totalCount` and remove redundant count and +dataset operations for the same state. + +If the frontend uses generated GraphQL artifacts, regenerate them using the +repository's normal generator. Do not hand-edit generated files. + +### 4. Replace eager all-column facet loading + +Stop mapping every dataset column to a legacy aliased aggregate. Request only +the bounded eager set on initial render. Mark remaining eligible controls lazy. + +### 5. Implement lazy batched facet loading + +Add open/visibility-driven loading, the 10-25 ms batching window, request +deduplication, cancellation, and revision/filter race guards. + +### 6. Add cache integration + +Store normalized results per facet key. Ensure results returned together can +be read and invalidated independently. + +### 7. Instrument and compare + +Record at least: + +- initial GraphQL POST count; +- initial requested facet count; +- total GraphQL request bytes and response bytes; +- time to first table rows; +- time until eager filters are usable; +- lazy facet cold and cache-hit latency; +- canceled/stale request count; and +- GraphQL error codes grouped by operation. + +Use browser performance marks and the existing telemetry layer. Preserve Loom +request IDs when available so browser measurements can be correlated with +backend logs. + +## Tests + +### Unit tests + +- Identifier/reference/free-text columns are not eager by default. +- Explicit configuration can opt a valid column into or out of faceting. +- The eager budget is deterministic. +- Equivalent filter order and `IN` member order produce the same cache key. +- Different selector, revision, column, size, or effective filter produces a + different key. +- Self-filter exclusion removes only predicates for the facet's own column. +- Duplicate filters are retained. +- Facet response normalization preserves missing counts and truncation. + +### Component/integration tests + +- Initial table mount sends one GraphQL operation containing rows and eager + facets. +- No initial request contains all 156 dataset columns. +- No redundant dataset or same-filter count operation is sent. +- Opening one lazy facet requests only that facet. +- Opening several controls together produces one batched request. +- Reopening an unchanged facet uses cache without a network request. +- Changing an unrelated filter refetches the facet with the correct effective + filters. +- Changing only a facet's self-filter does not fragment its cache when + self-filter exclusion makes the effective predicate set identical. +- A response from an older filter/revision snapshot is ignored. +- Pagination changes rows without refetching unaffected facets. +- Partial/truncated results are visibly distinguished from a complete list. +- GraphQL alias-specific errors do not erase successful rows or other facets. + +### End-to-end test + +Use the `HTAN_INT-BForePC` Patient selector and a schema with approximately 156 +columns: + +1. Load the Explorer table. +2. Assert one initial `/loom/graphql/graph` POST. +3. Assert the initial facet spec count is at most the configured eager budget. +4. Assert rows and count render correctly. +5. Open a lazy categorical facet and verify its values against the legacy + implementation. +6. Open a high-cardinality identifier filter and verify it does not preload an + unbounded distribution. +7. Apply and remove filters, paginate, and change sort while checking for stale + responses. +8. Capture performance and payload metrics for comparison with the baseline. + +## Acceptance criteria + +- Initial render uses one GraphQL POST for rows, row materialization metadata, + filtered total count, and eager facets sharing one selector/filter snapshot. +- Initial render never eagerly requests all 156 facets. +- Initial eager facets are bounded to 12 by default, or another explicitly + documented product limit no greater than 20. +- Every facet request uses bounded `TERMS` with `size <= 100` unless a reviewed + use case explicitly requires another aggregation kind. +- Identifier/reference/free-text distributions are lazy or disabled by + default. +- Opening multiple facets in the same render interval produces one batched + request, not one request per facet. +- Cache keys include selector, revision, column, size, and canonical effective + filters. +- Stale requests cannot overwrite newer table state. +- Requested facet values, counts, missing counts, filters, pagination, and + sorting match the existing UI for the same bounded result set. +- Browser tests show at least a 75% reduction in initially requested logical + facet jobs and at least a 50% reduction in GraphQL HTTP operations for one + table render. +- Record p50/p95 time-to-first-rows before and after. The change is accepted + only if time-to-first-rows improves materially without moving the delay to a + blocking loading state elsewhere in the UI. + +## Non-goals + +- Do not change Loom's GraphQL schema or generated backend files. +- Do not add a frontend-specific Loom endpoint. +- Do not replace aliases with 156 separate HTTP requests. +- Do not preload every facet into a global cache. +- Do not claim a truncated `TERMS` response is the complete domain. +- Do not make physical ClickHouse table names part of frontend state. + +## Separate backend follow-up + +This frontend work removes unnecessary demand and allows Loom's existing +request-scoped cache to work as designed. A separate Loom task should then: + +1. make active project releases the authoritative source-selection path; +2. remove the legacy source-discovery fallback after existing projects are + migrated to active releases; +3. batch active-release/execution metadata lookup instead of resolving projects + sequentially; and +4. consider a bounded release-revision-aware metadata/result cache. + +That backend follow-up targets the remaining approximately 650 ms metadata +cost. It should not block the frontend changes in this plan. + +## Definition of done handoff + +The frontend pull request should include: + +- a short before/after request diagram; +- the old and new initial GraphQL POST counts; +- old and new eager facet job counts; +- representative browser performance traces; +- unit, component, and end-to-end coverage described above; and +- a note confirming that Loom routes and schemas were unchanged. diff --git a/docs/FRONTEND_EXPLORER_V2_MIGRATION.md b/docs/FRONTEND_EXPLORER_V2_MIGRATION.md index dcaa90db..e04d3c14 100644 --- a/docs/FRONTEND_EXPLORER_V2_MIGRATION.md +++ b/docs/FRONTEND_EXPLORER_V2_MIGRATION.md @@ -325,10 +325,16 @@ Content-Type: application/json Publish reads the server-owned draft. The frontend does not send a config in this request. Loom recompiles the draft, materializes every referenced output, -checks that every output is queryable, inserts an immutable revision, and then -activates it. This applies to both custom Explorers and `default`. A failed -publication leaves the previous active revision in place and records -diagnostics on the failed revision. +checks that every output is queryable, inserts an immutable revision, updates +the project's active release with those outputs, and then activates the +Explorer revision. This applies to both custom Explorers and `default`. +Existing publications from other Explorers remain in the active release. A +failed publication or release activation leaves the previous Explorer revision +in place and records diagnostics on the failed revision. + +The authoring UI exposes Preview and Publish; it does not expose separate +create-release, save-release, or activate-release controls. Release records are +internal atomic visibility and audit metadata managed by Publish. On success, update the local store from the returned `state` rather than manually inferring active metadata: diff --git a/docs/loom-reliability-contract.md b/docs/loom-reliability-contract.md index 72ef4cb3..fba7e040 100644 --- a/docs/loom-reliability-contract.md +++ b/docs/loom-reliability-contract.md @@ -48,6 +48,12 @@ Creation and activation are separate. Activation is compare-and-swap against the observed active release revision. A failed generation load, verification, or publication never changes the active pointer. +Those are internal persistence operations, not separate Explorer authoring +steps. Explorer Preview is read-only. Explorer Publish materializes the config +outputs and creates and activates the corresponding project release in one +server workflow for both repository-managed defaults and user-created +Explorers. The UI does not save or activate releases directly. + ## GraphQL and Flat API ```graphql diff --git a/internal/api/graphql/graph/aggregate_http_integration_test.go b/internal/api/graphql/graph/aggregate_http_integration_test.go index 8a0aa2bb..26fd2925 100644 --- a/internal/api/graphql/graph/aggregate_http_integration_test.go +++ b/internal/api/graphql/graph/aggregate_http_integration_test.go @@ -160,3 +160,107 @@ func TestGraphQLAggregateAliasesUseOneGroupingStatement(t *testing.T) { t.Fatalf("catalog discovery calls = %d, want 1", catalog.lists.Load()) } } + +func TestGraphQLTableRenderCombinesRowsAndTermsFacets(t *testing.T) { + columns := []dfpublication.PhysicalColumn{{Name: "__loom_row_id", ClickHouse: "String"}} + for i := 0; i < 3; i++ { + columns = append(columns, dfpublication.PhysicalColumn{Name: fmt.Sprintf("facet_%03d", i), ClickHouse: "Nullable(String)"}) + } + now := time.Now().UTC() + catalog := &aggregateHTTPCatalog{execution: dfpublication.BundleExecution{ + ID: "execution", BundleIdentity: dfpublication.BundleIdentity{ + Name: "recipe", TranslationVersion: "v1", Project: "P1", DatasetGeneration: "generation", + }, + State: dfpublication.BundlePublished, UpdatedAt: now, + Outputs: []dfpublication.BundleOutputRecord{{ + Name: "Patient", PhysicalTable: "physical_patient", Columns: columns, + State: dfpublication.BundlePublished, + }}, + }} + queryer := &aggregateHTTPQueryer{} + root := graphresolver.NewResolver(graphresolver.ResolverConfig{ + MaterializationReader: &dfpublished.Reader{ClickHouse: queryer, Catalog: catalog}, + }) + server, err := newGraphServer(root, authscope.StaticAuthenticator{Principal: authscope.Principal{Subject: "user", Projects: []string{"P1"}}}) + if err != nil { + t.Fatal(err) + } + + query := `query TableRender($rows: DataframeRowsInput!, $facets: DataframeAggregationsInput!) { + table: dataframeRows(input: $rows) { + materialization { id revision } + columns rows totalCount + pageInfo { hasNextPage endCursor } + } + facets: dataframeAggregations(input: $facets) { + materialization { id revision } + aggregations + } + }` + selector := map[string]any{"recipe": "recipe", "translationVersion": "v1", "output": "Patient"} + specs := make([]map[string]any, 0, 3) + for i := 0; i < 3; i++ { + specs = append(specs, map[string]any{ + "name": fmt.Sprintf("facet_%03d", i), "kind": "TERMS", "column": fmt.Sprintf("facet_%03d", i), + "size": 50, "excludeSelfFilter": true, + }) + } + body, err := json.Marshal(map[string]any{ + "query": query, + "variables": map[string]any{ + "rows": map[string]any{"selector": selector, "columns": []string{"facet_000", "facet_001", "facet_002"}, "filters": []any{}, "first": 10}, + "facets": map[string]any{"selector": selector, "filters": []any{}, "specs": specs}, + }, + }) + if err != nil { + t.Fatal(err) + } + request := httptest.NewRequest(http.MethodPost, "/graphql/graph", strings.NewReader(string(body))) + request.Header.Set("Content-Type", "application/json") + response, err := server.App().Test(request) + if err != nil { + t.Fatal(err) + } + defer response.Body.Close() + if response.StatusCode != http.StatusOK { + t.Fatalf("status = %d, want 200", response.StatusCode) + } + var payload map[string]any + if err := json.NewDecoder(response.Body).Decode(&payload); err != nil { + t.Fatal(err) + } + if errorsValue, ok := payload["errors"].([]any); ok && len(errorsValue) != 0 { + t.Fatalf("unexpected GraphQL errors: %#v", errorsValue) + } + data, ok := payload["data"].(map[string]any) + if !ok || data["table"] == nil || data["facets"] == nil { + t.Fatalf("response is missing table or facets: %#v", payload) + } + + queryer.mu.Lock() + queries := append([]string(nil), queryer.queries...) + queryer.mu.Unlock() + termsCalls := 0 + missingCalls := 0 + for _, statement := range queries { + if strings.Contains(statement, "row_number() OVER") { + termsCalls++ + projected := strings.Index(statement, "AS __loom_terms_projected") + if projected < 0 { + t.Fatalf("terms projection boundary is missing: %s", statement) + } + if !strings.Contains(statement, "`__loom_slot` = 0") || strings.Contains(statement[projected:], "__loom_mask_") { + t.Fatalf("terms ranking references the wrong projection scope: %s", statement) + } + } + if strings.Contains(statement, "__loom_0_missing_count") { + missingCalls++ + } + } + if termsCalls != 1 || missingCalls != 1 { + t.Fatalf("aggregate calls = terms %d missing %d, want 1 and 1 (all calls %d)", termsCalls, missingCalls, len(queries)) + } + if catalog.lists.Load() != 1 { + t.Fatalf("catalog discovery calls = %d, want 1", catalog.lists.Load()) + } +} diff --git a/internal/api/graphql/graph/materialization/service.go b/internal/api/graphql/graph/materialization/service.go index 5b96ea11..552cd950 100644 --- a/internal/api/graphql/graph/materialization/service.go +++ b/internal/api/graphql/graph/materialization/service.go @@ -9,6 +9,7 @@ import ( "errors" "log/slog" "strings" + "time" "github.com/calypr/loom/generated/graphql/graph/model" httpapi "github.com/calypr/loom/internal/api/http" @@ -228,16 +229,16 @@ func AggregationsJSON(result dfmaterialization.AggregationsResult) (json.RawMess } func (s *Service) authorizedFederationUncached(ctx context.Context, principal *authscope.Principal, selector dfmaterialization.DataframeSelector, candidates []string) (dfmaterialization.FederatedDataset, map[string]dfmaterialization.SourceAccess, error) { - sources, err := s.reader.CurrentFederatedSources(ctx, candidates, selector) + started := time.Now() + sources, statuses, err := s.reader.CurrentFederatedSnapshot(ctx, candidates, selector) + snapshotElapsed := time.Since(started) if err != nil { s.logReadFailure(ctx, "published_source_discovery", selector.Output, err, "projects", candidates) return dfmaterialization.FederatedDataset{}, nil, mapReaderError(err) } if len(sources) == 0 { dataset, reconcileErr := dfmaterialization.ReconcileFederatedDataset(selector, candidates, nil) - if statuses, statusErr := s.reader.FederationProjectStatuses(ctx, candidates, selector); statusErr != nil { - return dfmaterialization.FederatedDataset{}, nil, mapReaderError(statusErr) - } else if len(statuses) > 0 { + if len(statuses) > 0 { dataset.ProjectStatuses = filterAuthorizedStatuses(candidates, statuses) } return dataset, map[string]dfmaterialization.SourceAccess{}, reconcileErr @@ -246,6 +247,7 @@ func (s *Service) authorizedFederationUncached(ctx context.Context, principal *a access := make(map[string]dfmaterialization.SourceAccess, len(sources)) authorizedSources := make([]dfmaterialization.Materialization, 0, len(sources)) rowCountComplete := true + authorizationStarted := time.Now() for _, source := range sources { if s.scopeResolver != nil { scope, err := s.scopeResolver.ResolveReadScopeForGeneration(ctx, principal, source.Project, source.DatasetGeneration, nil) @@ -278,16 +280,17 @@ func (s *Service) authorizedFederationUncached(ctx context.Context, principal *a if len(access) == 0 { return dfmaterialization.FederatedDataset{}, nil, dataframeerrors.NewError(dataframeerrors.CodeDatasetNotFound, "") } + authorizationElapsed := time.Since(authorizationStarted) + reconcileStarted := time.Now() dataset, err := dfmaterialization.ReconcileFederatedDataset(selector, candidates, authorizedSources) if err != nil { s.logReadFailure(ctx, "published_schema_reconciliation", selector.Output, err, "source_ids", materializationIDs(authorizedSources), "physical_tables", physicalTables(authorizedSources)) return dfmaterialization.FederatedDataset{}, nil, err } - if statuses, statusErr := s.reader.FederationProjectStatuses(ctx, candidates, selector); statusErr != nil { - return dfmaterialization.FederatedDataset{}, nil, mapReaderError(statusErr) - } else if len(statuses) > 0 { + if len(statuses) > 0 { dataset.ProjectStatuses = filterAuthorizedStatuses(candidates, statuses) } + reconciliationElapsed := time.Since(reconcileStarted) discovered := make(map[string]struct{}, len(sources)) for _, source := range sources { discovered[source.Project] = struct{}{} @@ -303,6 +306,13 @@ func (s *Service) authorizedFederationUncached(ctx context.Context, principal *a } dataset.RowCountComplete = rowCountComplete refreshAvailability(&dataset) + s.logger.Info("dataframe federation metadata resolved", + "request_id", httpapi.RequestIDFromContext(ctx), "selector", selector.Key(), + "candidate_project_count", len(candidates), "source_count", len(sources), + "snapshot_ms", snapshotElapsed.Milliseconds(), + "authorization_ms", authorizationElapsed.Milliseconds(), + "reconciliation_ms", reconciliationElapsed.Milliseconds(), + ) return dataset, access, nil } diff --git a/internal/dataframe/publication/arango/bundle_registry.go b/internal/dataframe/publication/arango/bundle_registry.go index e5aa2ed8..91215d71 100644 --- a/internal/dataframe/publication/arango/bundle_registry.go +++ b/internal/dataframe/publication/arango/bundle_registry.go @@ -75,6 +75,42 @@ func (r *Registry) ListExecutions(ctx context.Context, state publication.BundleS return out, err } +// ListSelectorExecutions avoids the five full lifecycle scans otherwise +// required to assemble dataframe project status. Exact output matching stays +// in the caller so queued executions (which intentionally have no outputs yet) +// remain visible as BUILDING. +func (r *Registry) ListSelectorExecutions(ctx context.Context, selector publication.DataframeSelector, before time.Time) ([]publication.BundleExecution, error) { + out := []publication.BundleExecution{} + states := []publication.BundleState{ + publication.BundleQueued, publication.BundlePending, + publication.BundleRunning, publication.BundlePreflight, publication.BundleLoading, + publication.BundleValidating, + publication.BundlePublished, publication.BundleReady, + publication.BundleFailed, + } + err := r.client.QueryRows(ctx, `FOR doc IN @@collection +FILTER (doc.name == @recipe OR doc.Name == @recipe) + AND (doc.translationVersion == @translationVersion OR doc.TranslationVersion == @translationVersion) + AND doc.state IN @states AND doc.updatedAt < @before +SORT doc.updatedAt ASC RETURN doc`, r.batchSize, map[string]interface{}{ + "@collection": BundleExecutionsCollection, + "recipe": selector.Recipe, "translationVersion": selector.TranslationVersion, + "states": states, "before": before, + }, func(row map[string]any) error { + data, err := json.Marshal(row) + if err != nil { + return err + } + var execution publication.BundleExecution + if err := json.Unmarshal(data, &execution); err != nil { + return err + } + out = append(out, execution.CanonicalizeLegacy()) + return nil + }) + return out, err +} + func (r *Registry) FindExecutionBySelector(ctx context.Context, project, generation string, selector publication.DataframeSelector) (publication.BundleExecution, publication.BundleOutputRecord, error) { if err := selector.Validate(); err != nil { return publication.BundleExecution{}, publication.BundleOutputRecord{}, err diff --git a/internal/dataframe/publication/bundle.go b/internal/dataframe/publication/bundle.go index 98561de2..821f7a2c 100644 --- a/internal/dataframe/publication/bundle.go +++ b/internal/dataframe/publication/bundle.go @@ -202,6 +202,13 @@ type BundleCatalog interface { ReleaseBundleLease(context.Context, string, string) error } +// SelectorExecutionCatalog is the optimized read seam used by federation +// status discovery. Implementations return all lifecycle attempts for one +// exact selector with a single backing-store query. +type SelectorExecutionCatalog interface { + ListSelectorExecutions(context.Context, DataframeSelector, time.Time) ([]BundleExecution, error) +} + // ExactExecutionCatalog is consumed by project release verification. It never // falls back to latest-by-output or a name-only recipe. type ExactExecutionCatalog interface { diff --git a/internal/dataframe/published/aggregate_clickhouse_integration_test.go b/internal/dataframe/published/aggregate_clickhouse_integration_test.go index 31d3ed75..96734543 100644 --- a/internal/dataframe/published/aggregate_clickhouse_integration_test.go +++ b/internal/dataframe/published/aggregate_clickhouse_integration_test.go @@ -40,6 +40,7 @@ func TestAggregateBatchClickHouseIntegration(t *testing.T) { physicalColumns := []storeclickhouse.Column{ {Name: "__loom_row_id", Type: "UInt64"}, {Name: "facet", Type: "Nullable(String)"}, + {Name: "facet_other", Type: "Nullable(String)"}, {Name: "value", Type: "Nullable(Float64)"}, {Name: "auth_resource_path", Type: "String"}, } @@ -49,26 +50,28 @@ func TestAggregateBatchClickHouseIntegration(t *testing.T) { } } if err := client.InsertRows(ctx, tableA, physicalColumns, []map[string]any{ - {"__loom_row_id": uint64(1), "facet": "a", "value": 2.0, "auth_resource_path": "allowed"}, - {"__loom_row_id": uint64(2), "facet": nil, "value": 3.0, "auth_resource_path": "allowed"}, - {"__loom_row_id": uint64(3), "facet": "secret", "value": 100.0, "auth_resource_path": "denied"}, + {"__loom_row_id": uint64(1), "facet": "a", "facet_other": "x", "value": 2.0, "auth_resource_path": "allowed"}, + {"__loom_row_id": uint64(2), "facet": nil, "facet_other": "x", "value": 3.0, "auth_resource_path": "allowed"}, + {"__loom_row_id": uint64(3), "facet": "secret", "facet_other": "secret", "value": 100.0, "auth_resource_path": "denied"}, }); err != nil { t.Fatal(err) } if err := client.InsertRows(ctx, tableB, physicalColumns, []map[string]any{ - {"__loom_row_id": uint64(1), "facet": "b", "value": 5.0, "auth_resource_path": "anything"}, + {"__loom_row_id": uint64(1), "facet": "b", "facet_other": "y", "value": 5.0, "auth_resource_path": "anything"}, }); err != nil { t.Fatal(err) } sourceColumns := []Column{ {Name: "__loom_row_id", ClickHouse: "UInt64"}, {Name: "facet", ClickHouse: "Nullable(String)"}, + {Name: "facet_other", ClickHouse: "Nullable(String)"}, {Name: "value", ClickHouse: "Nullable(Float64)"}, {Name: authResourcePathColumn, ClickHouse: "String"}, } dataset := FederatedDataset{ Columns: []Column{ {Name: "facet", ClickHouse: "Nullable(String)"}, + {Name: "facet_other", ClickHouse: "Nullable(String)"}, {Name: "value", ClickHouse: "Nullable(Float64)"}, {Name: projectIDColumn, ClickHouse: "String"}, }, @@ -82,6 +85,8 @@ func TestAggregateBatchClickHouseIntegration(t *testing.T) { {ID: 1, ResponseMode: AggregateResponseLegacy, GroupBy: []string{"facet"}, Operation: "COUNT"}, {ID: 2, ResponseMode: AggregateResponseLegacy, Operation: "COUNT"}, {ID: 3, ResponseMode: AggregateResponseLegacy, Operation: "SUM", Column: "value"}, + {ID: 4, ResponseMode: AggregateResponseTerms, Column: "facet", Size: 2}, + {ID: 5, ResponseMode: AggregateResponseTerms, Column: "facet_other", Size: 1}, }, AccessByProject: map[string]SourceAccess{ "a": {ResourcePaths: []string{"allowed"}}, @@ -102,4 +107,10 @@ func TestAggregateBatchClickHouseIntegration(t *testing.T) { if got, err := numericCount(result.Jobs[1].Rows[0]["count"]); err != nil || got != 3 { t.Fatalf("ungrouped count = %v, err = %v", result.Jobs[1].Rows, err) } + if got := result.Jobs[3]; len(got.Rows) != 2 || got.Truncated || got.MissingCount != 1 { + t.Fatalf("facet terms = %#v", got) + } + if got := result.Jobs[4]; len(got.Rows) != 1 || !got.Truncated || got.MissingCount != 0 || got.Rows[0]["key"] != "x" { + t.Fatalf("facet_other terms = %#v", got) + } } diff --git a/internal/dataframe/published/aggregate_plan_test.go b/internal/dataframe/published/aggregate_plan_test.go index 0823615a..1afb657f 100644 --- a/internal/dataframe/published/aggregate_plan_test.go +++ b/internal/dataframe/published/aggregate_plan_test.go @@ -101,6 +101,41 @@ func TestAggregatePlanCombines156CountFacets(t *testing.T) { } } +func TestAggregatePlanRanksMultipleTermsByProjectedSlot(t *testing.T) { + dataset := aggregateTestDataset(2) + fake := &aggregateFakeQueryer{} + result, err := (&Reader{ClickHouse: fake}).ExecuteAggregateBatch(context.Background(), dataset, AggregateBatchRequest{ + Jobs: []AggregateJob{ + {ID: 1, ResponseMode: AggregateResponseTerms, Column: "facet_000", Size: 10}, + {ID: 2, ResponseMode: AggregateResponseTerms, Column: "facet_001", Size: 10}, + }, + AccessByProject: map[string]SourceAccess{"project": {Unrestricted: true}}, + }) + if err != nil { + t.Fatal(err) + } + if result.GroupingStatements != 1 || result.ScalarStatements != 1 { + t.Fatalf("statement counts = grouping %d scalar %d, want 1 and 1", result.GroupingStatements, result.ScalarStatements) + } + if len(fake.calls) != 2 { + t.Fatalf("ClickHouse calls = %d, want 2", len(fake.calls)) + } + query := fake.calls[0].query + if !strings.Contains(query, "multiIf(`__loom_slot` = 0, `facet_000`, `__loom_slot` = 1, `facet_001`, NULL) AS `__loom_order_key`") { + t.Fatalf("terms order key is not selected by projected slot: %s", query) + } + if strings.Contains(query, "SELECT *") { + t.Fatalf("terms ranking uses an implicit projection: %s", query) + } + projected := strings.Index(query, "AS __loom_terms_projected") + if projected < 0 { + t.Fatalf("terms projection boundary is missing: %s", query) + } + if strings.Contains(query[projected:], "__loom_mask_") { + t.Fatalf("grouping mask escaped its projection scope: %s", query[projected:]) + } +} + func TestAggregatePlanCanonicalizesFilterAndMemberOrder(t *testing.T) { dataset := aggregateTestDataset(2) first := []Filter{{Column: "facet_001", Op: "IN", Value: []any{"b", "a"}}, {Column: "facet_000", Op: "EQ", Value: "x"}} diff --git a/internal/dataframe/published/aggregate_sql.go b/internal/dataframe/published/aggregate_sql.go index 7885b7c9..adbc5094 100644 --- a/internal/dataframe/published/aggregate_sql.go +++ b/internal/dataframe/published/aggregate_sql.go @@ -235,13 +235,13 @@ func buildTermsGroupingSetSQL(dataset FederatedDataset, access map[string]Source orderKey := "`" + statement.jobs[0].job.Column + "`" if len(statement.jobs) > 1 { parts := make([]string, 0, len(statement.jobs)*2+1) - for i, condition := range conditions { - parts = append(parts, condition, "`"+statement.jobs[i].job.Column+"`") + for i, planned := range statement.jobs { + parts = append(parts, fmt.Sprintf("`__loom_slot` = %d", i), "`"+planned.job.Column+"`") } parts = append(parts, "NULL") orderKey = "multiIf(" + strings.Join(parts, ", ") + ")" } - query = fmt.Sprintf("SELECT `__loom_slot`, `__loom_group_json`, `__loom_metric` FROM (SELECT *, row_number() OVER (PARTITION BY `__loom_slot` ORDER BY `__loom_metric` DESC, `__loom_order_key` ASC) AS `__loom_rank` FROM (SELECT *, %s AS `__loom_order_key` FROM (%s) AS __loom_terms_projected) AS __loom_terms WHERE `__loom_group_json` != '[null]') AS __loom_ranked WHERE `__loom_rank` <= %s ORDER BY `__loom_slot`, `__loom_metric` DESC, `__loom_order_key` ASC", orderKey, query, limitExpr) + query = fmt.Sprintf("SELECT `__loom_slot`, `__loom_group_json`, `__loom_metric` FROM (SELECT `__loom_slot`, `__loom_group_json`, `__loom_metric`, `__loom_order_key`, row_number() OVER (PARTITION BY `__loom_slot` ORDER BY `__loom_metric` DESC, `__loom_order_key` ASC) AS `__loom_rank` FROM (SELECT `__loom_slot`, `__loom_group_json`, `__loom_metric`, %s AS `__loom_order_key` FROM (%s) AS __loom_terms_projected) AS __loom_terms WHERE `__loom_group_json` != '[null]') AS __loom_ranked WHERE `__loom_rank` <= %s ORDER BY `__loom_slot`, `__loom_metric` DESC, `__loom_order_key` ASC", orderKey, query, limitExpr) return aggregateSQL{ query: query, columns: []string{"__loom_slot", "__loom_group_json", "__loom_metric"}, args: args, sourceColumns: sourceColumns, groupingSets: len(statement.jobs), diff --git a/internal/dataframe/published/federation.go b/internal/dataframe/published/federation.go index 4f60cedf..8243cdce 100644 --- a/internal/dataframe/published/federation.go +++ b/internal/dataframe/published/federation.go @@ -83,6 +83,13 @@ type ReleaseExecutionResolver interface { ActiveReleaseSelectors(context.Context, []string) ([]DataframeSelector, map[string]bool, error) } +// FederationSnapshotResolver resolves active release execution IDs and their +// project statuses together. This lets interactive reads avoid independently +// rediscovering the same release and publication lifecycle metadata. +type FederationSnapshotResolver interface { + ResolveFederationSnapshot(context.Context, []string, DataframeSelector) (map[string]string, []ProjectStatus, bool, error) +} + func (r *Reader) FederationProjectStatuses(ctx context.Context, projects []string, selector DataframeSelector) ([]ProjectStatus, error) { if r != nil && r.ProjectStatusResolver != nil { return r.ProjectStatusResolver.DataframeProjectStatuses(ctx, append([]string(nil), projects...), selector) @@ -90,6 +97,67 @@ func (r *Reader) FederationProjectStatuses(ctx context.Context, projects []strin return nil, nil } +// CurrentFederatedSnapshot resolves sources and project status through the +// combined release fast path when available. The legacy discovery methods are +// retained as a fallback for alternate catalogs and tests. +func (r *Reader) CurrentFederatedSnapshot(ctx context.Context, projects []string, selector DataframeSelector) ([]Materialization, []ProjectStatus, error) { + projects = normalizedProjects(projects) + if r != nil && r.FederationSnapshotResolver != nil { + if r.Catalog == nil { + return nil, nil, fmt.Errorf("bundle catalog dependency is required") + } + executionIDs, statuses, complete, err := r.FederationSnapshotResolver.ResolveFederationSnapshot(ctx, projects, selector) + if err != nil { + return nil, nil, err + } + if !complete { + sources, err := r.CurrentFederatedSources(ctx, projects, selector) + if err != nil { + return nil, nil, err + } + statuses, err := r.FederationProjectStatuses(ctx, projects, selector) + return sources, statuses, err + } + sources := make([]Materialization, 0, len(executionIDs)) + for _, project := range projects { + executionID := strings.TrimSpace(executionIDs[project]) + if executionID == "" { + continue + } + execution, err := r.Catalog.GetExecution(ctx, executionID) + if err != nil { + return nil, nil, err + } + if execution.Project != project || !execution.State.Successful() { + continue + } + for _, output := range execution.Outputs { + if output.Name != selector.Output { + continue + } + executionSelector := output.Selector + if !executionSelector.Valid() { + executionSelector = execution.Selector(selector.Output) + } + if executionSelector != selector { + continue + } + materialization := publishedMaterialization(execution, output, selector.Output) + materialization.Selector = selector + sources = append(sources, materialization) + break + } + } + return sources, statuses, nil + } + sources, err := r.CurrentFederatedSources(ctx, projects, selector) + if err != nil { + return nil, nil, err + } + statuses, err := r.FederationProjectStatuses(ctx, projects, selector) + return sources, statuses, err +} + // SourceAccess is the already-resolved visibility for one published project. // Missing entries are intentionally treated as restricted with no paths. type SourceAccess struct { diff --git a/internal/dataframe/published/read.go b/internal/dataframe/published/read.go index 3a12c71f..1d95e9b2 100644 --- a/internal/dataframe/published/read.go +++ b/internal/dataframe/published/read.go @@ -20,13 +20,14 @@ type ClickHouseQueryer interface { } type Reader struct { - ClickHouse ClickHouseQueryer - Catalog bundlepublication.BundleCatalog - Logger *slog.Logger - MaxPage int - ActiveManifestResolver publication.ActiveResolver - ProjectStatusResolver ProjectStatusResolver - ReleaseExecutionResolver ReleaseExecutionResolver + ClickHouse ClickHouseQueryer + Catalog bundlepublication.BundleCatalog + Logger *slog.Logger + MaxPage int + ActiveManifestResolver publication.ActiveResolver + ProjectStatusResolver ProjectStatusResolver + ReleaseExecutionResolver ReleaseExecutionResolver + FederationSnapshotResolver FederationSnapshotResolver } type Filter struct { diff --git a/internal/dataset/release_test.go b/internal/dataset/release_test.go index 8007e1fa..4add6e35 100644 --- a/internal/dataset/release_test.go +++ b/internal/dataset/release_test.go @@ -85,6 +85,39 @@ func TestReleaseActivationCarriesOptionalPublicationAsStale(t *testing.T) { } } +func TestReleaseActivationAddsPublicationWithoutDroppingSameGenerationPublications(t *testing.T) { + ctx := context.Background() + store := NewMemoryLifecycleStore() + now := time.Date(2026, 8, 18, 12, 0, 0, 0, time.UTC) + stageSnapshot(t, store, "project-a", "commit-a", now) + firstSelector := DataframeSelector{Recipe: "explorer-one", TranslationVersion: "v1", Output: "Patient"} + secondSelector := DataframeSelector{Recipe: "explorer-two", TranslationVersion: "v1", Output: "Observation"} + verifier := &verificationFixture{results: map[string]PublicationVerification{ + firstSelector.Key(): published(firstSelector, "execution-a", "commit-a", now), + secondSelector.Key(): published(secondSelector, "execution-b", "commit-a", now), + }, errors: map[string]error{}} + service := ReleaseService{Snapshots: store, Releases: store, Verifier: verifier, Now: func() time.Time { return now }} + + first, err := service.Activate(ctx, ActivationRequest{Project: "project-a", Generation: "commit-a", ExpectedRevision: 0, OptionalSelectors: []DataframeSelector{firstSelector}}) + if err != nil { + t.Fatal(err) + } + second, err := service.Activate(ctx, ActivationRequest{Project: "project-a", Generation: "commit-a", ExpectedRevision: first.Revision, OptionalSelectors: []DataframeSelector{secondSelector}}) + if err != nil { + t.Fatal(err) + } + if second.Revision != 2 || len(second.Release.Publications) != 2 { + t.Fatalf("second activation = %#v", second) + } + bySelector := map[string]ReleasePublication{} + for _, publication := range second.Release.Publications { + bySelector[publication.Selector.Key()] = publication + } + if bySelector[firstSelector.Key()].ExecutionID != "execution-a" || bySelector[firstSelector.Key()].Stale || bySelector[secondSelector.Key()].ExecutionID != "execution-b" || bySelector[secondSelector.Key()].Stale { + t.Fatalf("same-generation publications = %#v", second.Release.Publications) + } +} + func TestConcurrentReleaseActivationUsesCompareAndSwap(t *testing.T) { ctx := context.Background() store := NewMemoryLifecycleStore() diff --git a/internal/server/explorer_config_route.go b/internal/server/explorer_config_route.go index bc09ca17..55c10ee5 100644 --- a/internal/server/explorer_config_route.go +++ b/internal/server/explorer_config_route.go @@ -74,6 +74,13 @@ func RegisterExplorerConfigV2Route(app *fiber.App, authorizer authscope.Authoriz if owner.ManagementMode != explorer.ManagementRepository { return c.Status(http.StatusConflict).JSON(fiber.Map{"error": "default Explorer has invalid management mode"}) } + if len(lifecycle) == 0 || lifecycle[0].ActivateRelease == nil { + return c.Status(http.StatusServiceUnavailable).JSON(fiber.Map{"error": "release activation is not configured", "executionId": execution.ID}) + } + if err := lifecycle[0].ActivateRelease(c.Context(), project, generation, selectorsForBundle(bundle)); err != nil { + _, _ = explorers.FailRevision(c.Context(), revision.ID, []explorer.Diagnostic{{Severity: "ERROR", Code: "RELEASE_ACTIVATION_FAILED", Message: err.Error(), Retryable: true}}) + return c.Status(http.StatusConflict).JSON(fiber.Map{"error": fmt.Sprintf("activate published ExplorerConfigV2: %v", err), "executionId": execution.ID}) + } if err := explorers.ActivateRepositoryGeneration(c.Context(), project, generation, revision.ID); err != nil { return c.Status(http.StatusConflict).JSON(fiber.Map{"error": fmt.Sprintf("activate ExplorerConfigV2: %v", err), "executionId": execution.ID}) } diff --git a/internal/server/explorer_config_route_test.go b/internal/server/explorer_config_route_test.go index a7e2f65d..c54bd42e 100644 --- a/internal/server/explorer_config_route_test.go +++ b/internal/server/explorer_config_route_test.go @@ -11,6 +11,7 @@ import ( graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" "github.com/calypr/loom/internal/authscope" "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataset" "github.com/calypr/loom/internal/explorer" "github.com/gofiber/fiber/v3" ) @@ -26,8 +27,16 @@ func TestRepositoryDeploymentPersistsExecutableDataframeSelectors(t *testing.T) } return graphresolver.RecipeExecution{ID: "execution-a", SourceGeneration: "generation-a", State: "PUBLISHED", Outputs: []graphresolver.RecipeExecutionOutput{{Name: "DocumentReference", State: "PUBLISHED"}}}, nil } + activationCount := 0 + activateRelease := func(_ context.Context, project, generation string, selectors []dataset.DataframeSelector) error { + activationCount++ + if project != "project-a" || generation != "generation-a" || len(selectors) != 1 || selectors[0].Output != "DocumentReference" { + t.Fatalf("release activation = %s/%s %#v", project, generation, selectors) + } + return nil + } app := fiber.New() - RegisterExplorerConfigV2Route(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, materialize) + RegisterExplorerConfigV2Route(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, materialize, ExplorerV2LifecycleConfig{ActivateRelease: activateRelease}) request := requestJSONWithHeaders(t, app, http.MethodPost, "/api/v1/projects/project-a/generations/generation-a/explorer-config", string(baselineExplorerConfigV2("project-a", "Default")), map[string]string{"X-Loom-Source-Commit": "commit-a"}) if request.StatusCode != http.StatusOK { @@ -37,6 +46,9 @@ func TestRepositoryDeploymentPersistsExecutableDataframeSelectors(t *testing.T) if repeated.StatusCode != http.StatusOK { t.Fatalf("repeated deploy status=%d body=%s", repeated.StatusCode, repeated.Body) } + if activationCount != 2 { + t.Fatalf("release activation count = %d, want 2", activationCount) + } state, err := getExplorerV2State(context.Background(), service, "project-a", "default") if err != nil { t.Fatal(err) diff --git a/internal/server/explorer_v2_lifecycle.go b/internal/server/explorer_v2_lifecycle.go index 2f40a133..1ffaad4a 100644 --- a/internal/server/explorer_v2_lifecycle.go +++ b/internal/server/explorer_v2_lifecycle.go @@ -14,6 +14,7 @@ import ( "github.com/calypr/loom/internal/authscope" "github.com/calypr/loom/internal/dataframe/publication" "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataset" "github.com/calypr/loom/internal/explorer" "github.com/gofiber/fiber/v3" ) @@ -43,6 +44,7 @@ type ExplorerV2CompileResult struct { type ExplorerV2Compiler func(context.Context, ExplorerV2CompileRequest) (ExplorerV2CompileResult, error) type ExplorerV2Previewer func(context.Context, recipe.Bundle, recipe.RuntimeBindings) (map[string][]map[string]any, error) type ExplorerV2Materializer = graphresolver.ExplorerBundleMaterializer +type ExplorerV2ReleaseActivator func(context.Context, string, string, []dataset.DataframeSelector) error // ExplorerV2LifecycleConfig contains explicit capabilities for the REST // surface. The HTTP layer does not reach into catalog, compiler, or storage @@ -52,6 +54,9 @@ type ExplorerV2LifecycleConfig struct { Catalog explorerV2CatalogReader Preview ExplorerV2Previewer Materialize ExplorerV2Materializer + // ActivateRelease makes Publish the sole visibility switch: callers never + // create or save a release as a separate user-facing step. + ActivateRelease ExplorerV2ReleaseActivator } type explorerV2State struct { @@ -366,6 +371,14 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author if err != nil { return explorerV2Error(c, http.StatusInternalServerError, "REVISION_INSERT_FAILED", err.Error()) } + if capabilities.ActivateRelease == nil { + _, _ = explorers.FailRevision(c.Context(), revision.ID, []explorer.Diagnostic{{Severity: "ERROR", Code: "RELEASE_ACTIVATION_UNAVAILABLE", Message: "release activation is not configured", Retryable: true}}) + return explorerV2Error(c, http.StatusServiceUnavailable, "RELEASE_ACTIVATION_UNAVAILABLE", "release activation is not configured") + } + if err := capabilities.ActivateRelease(c.Context(), project, sourceGeneration, selectorsForBundle(result.Bundle)); err != nil { + _, _ = explorers.FailRevision(c.Context(), revision.ID, []explorer.Diagnostic{{Severity: "ERROR", Code: "RELEASE_ACTIVATION_FAILED", Message: err.Error(), Retryable: true}}) + return explorerV2Error(c, http.StatusConflict, "RELEASE_ACTIVATION_FAILED", err.Error()) + } var activationErr error if id == "default" { activationErr = explorers.ActivateRepository(c.Context(), project, revision.ID) @@ -383,6 +396,14 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author }) } +func selectorsForBundle(bundle recipe.Bundle) []dataset.DataframeSelector { + selectors := make([]dataset.DataframeSelector, 0, len(bundle.Outputs)) + for _, output := range bundle.Outputs { + selectors = append(selectors, dataset.DataframeSelector{Recipe: bundle.Name, TranslationVersion: bundle.TranslationVersion, Output: output.Name}) + } + return selectors +} + func decodeStrict(raw []byte, value any) error { decoder := json.NewDecoder(strings.NewReader(string(raw))) decoder.DisallowUnknownFields() diff --git a/internal/server/explorer_v2_lifecycle_test.go b/internal/server/explorer_v2_lifecycle_test.go index 9476b395..d273228a 100644 --- a/internal/server/explorer_v2_lifecycle_test.go +++ b/internal/server/explorer_v2_lifecycle_test.go @@ -14,6 +14,7 @@ import ( graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" "github.com/calypr/loom/internal/authscope" "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataset" "github.com/calypr/loom/internal/explorer" "github.com/gofiber/fiber/v3" ) @@ -58,6 +59,18 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { } return graphresolver.RecipeExecution{ID: "execution-a", SourceGeneration: "generation-a", State: "PUBLISHED", Outputs: []graphresolver.RecipeExecutionOutput{{Name: "DocumentReference", State: "PUBLISHED"}}}, nil } + var releaseActivations [][]dataset.DataframeSelector + releaseFails := false + activateRelease := func(_ context.Context, project, generation string, selectors []dataset.DataframeSelector) error { + if project != "project-a" || generation != "generation-a" { + t.Fatalf("release identity = %s/%s", project, generation) + } + if releaseFails { + return errors.New("release conflict") + } + releaseActivations = append(releaseActivations, append([]dataset.DataframeSelector(nil), selectors...)) + return nil + } catalog := func(_ context.Context, project, _ string, _ string) (explorer.CatalogSnapshot, error) { return explorer.NewCatalogSnapshot(project, "generation-a", "scope-a", explorer.Catalog{ Nodes: []explorer.CatalogNode{{ID: "node-document-reference", ResourceType: "DocumentReference"}}, @@ -67,7 +80,7 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { }, true, false, nil) } app := fiber.New() - RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{Compile: compile, Catalog: catalog, Preview: preview, Materialize: materialize}) + RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{Compile: compile, Catalog: catalog, Preview: preview, Materialize: materialize, ActivateRelease: activateRelease}) catalogResponse := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom-explorer/authoring/catalog", "") if catalogResponse.StatusCode != http.StatusOK || !strings.Contains(catalogResponse.Body, `"snapshotToken":"sha256:`) || !strings.Contains(catalogResponse.Body, `"selectionId":"selection-id"`) { @@ -133,6 +146,9 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { if defaultPublished.StatusCode != http.StatusOK || !strings.Contains(defaultPublished.Body, `"publicationId"`) { t.Fatalf("default publish status=%d body=%s", defaultPublished.StatusCode, defaultPublished.Body) } + if len(releaseActivations) != 1 || len(releaseActivations[0]) != 1 || releaseActivations[0][0].Output != "DocumentReference" { + t.Fatalf("default release activations = %#v", releaseActivations) + } defaultAfterPublish := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/default", "") var activeDefaultState explorerV2State decodeBody(t, defaultAfterPublish.Body, &activeDefaultState) @@ -186,6 +202,9 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { if published.StatusCode != http.StatusOK || !strings.Contains(published.Body, `"publicationId"`) || !strings.Contains(published.Body, `"activeUrl"`) { t.Fatalf("publish status=%d body=%s", published.StatusCode, published.Body) } + if len(releaseActivations) != 2 || len(releaseActivations[1]) != 1 || releaseActivations[1][0].Recipe != bundle.Name { + t.Fatalf("custom release activations = %#v", releaseActivations) + } stateResponse := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom-explorer", "") var active explorerV2State decodeBody(t, stateResponse.Body, &active) @@ -193,17 +212,39 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { t.Fatalf("active state=%#v", active) } priorActiveRevision := active.ActiveRevisionID + releaseFails = true + draftExplorer["title"] = "Failed release draft" + draftBytes, _ = json.Marshal(draft) + draftRequest, _ = json.Marshal(map[string]any{"config": json.RawMessage(draftBytes), "expectedDraftVersion": active.DraftVersion, "expectedDraftDigest": active.DraftDigest}) + failedReleaseDraft := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/custom-explorer/draft", string(draftRequest)) + if failedReleaseDraft.StatusCode != http.StatusOK { + t.Fatalf("failed release draft save status=%d body=%s", failedReleaseDraft.StatusCode, failedReleaseDraft.Body) + } + var failedReleaseState explorerV2State + decodeBody(t, failedReleaseDraft.Body, &failedReleaseState) + failedReleasePublish := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom-explorer/publish", `{"expectedDraftVersion":`+fmt.Sprint(failedReleaseState.DraftVersion)+`,"expectedDraftDigest":"`+failedReleaseState.DraftDigest+`"}`) + if failedReleasePublish.StatusCode != http.StatusConflict || !strings.Contains(failedReleasePublish.Body, `"code":"RELEASE_ACTIVATION_FAILED"`) { + t.Fatalf("failed release publish status=%d body=%s", failedReleasePublish.StatusCode, failedReleasePublish.Body) + } + unchangedAfterReleaseFailure := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom-explorer", "") + var releaseUnchanged explorerV2State + decodeBody(t, unchangedAfterReleaseFailure.Body, &releaseUnchanged) + if releaseUnchanged.ActiveRevisionID != priorActiveRevision || string(releaseUnchanged.ActiveConfig) == string(releaseUnchanged.DraftConfig) { + t.Fatalf("failed release activation changed active state: %#v", releaseUnchanged) + } + + releaseFails = false materializeFails = true draftExplorer["title"] = "Failed publication draft" draftBytes, _ = json.Marshal(draft) - draftRequest, _ = json.Marshal(map[string]any{"config": json.RawMessage(draftBytes), "expectedDraftVersion": active.DraftVersion, "expectedDraftDigest": active.DraftDigest}) + draftRequest, _ = json.Marshal(map[string]any{"config": json.RawMessage(draftBytes), "expectedDraftVersion": failedReleaseState.DraftVersion, "expectedDraftDigest": failedReleaseState.DraftDigest}) failedDraft := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/custom-explorer/draft", string(draftRequest)) if failedDraft.StatusCode != http.StatusOK { t.Fatalf("failed publication draft save status=%d body=%s", failedDraft.StatusCode, failedDraft.Body) } var failedDraftState explorerV2State decodeBody(t, failedDraft.Body, &failedDraftState) - failedPublish := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom-explorer/publish", `{"expectedDraftVersion":3,"expectedDraftDigest":"`+failedDraftState.DraftDigest+`"}`) + failedPublish := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom-explorer/publish", `{"expectedDraftVersion":`+fmt.Sprint(failedDraftState.DraftVersion)+`,"expectedDraftDigest":"`+failedDraftState.DraftDigest+`"}`) if failedPublish.StatusCode != http.StatusUnprocessableEntity { t.Fatalf("failed publish status=%d body=%s", failedPublish.StatusCode, failedPublish.Body) } diff --git a/internal/server/federation_status.go b/internal/server/federation_status.go index 3b1255f2..dfd54b61 100644 --- a/internal/server/federation_status.go +++ b/internal/server/federation_status.go @@ -19,16 +19,26 @@ type releaseProjectStatusResolver struct { } func (r releaseProjectStatusResolver) DataframeProjectStatuses(ctx context.Context, projects []string, selector dataset.DataframeSelector) ([]published.ProjectStatus, error) { + _, statuses, _, err := r.ResolveFederationSnapshot(ctx, projects, selector) + return statuses, err +} + +func (r releaseProjectStatusResolver) ResolveFederationSnapshot(ctx context.Context, projects []string, selector dataset.DataframeSelector) (map[string]string, []published.ProjectStatus, bool, error) { latest, err := r.latestAttempts(ctx, selector) if err != nil { - return nil, err + return nil, nil, false, err } + executionIDs := make(map[string]string, len(projects)) result := make([]published.ProjectStatus, 0, len(projects)) + complete := true for _, project := range projects { status := published.ProjectStatus{ProjectID: project, State: published.ProjectMissing} active, activeErr := r.releases.ReadActiveRelease(ctx, project) if activeErr != nil && !errors.Is(activeErr, dataset.ErrNoActiveRelease) { - return nil, activeErr + return nil, nil, false, activeErr + } + if errors.Is(activeErr, dataset.ErrNoActiveRelease) { + complete = false } if activeErr == nil { for _, binding := range active.Release.Publications { @@ -40,6 +50,7 @@ func (r releaseProjectStatusResolver) DataframeProjectStatuses(ctx context.Conte status.State = published.ProjectStale } status.Generation, status.ExecutionID = binding.Generation, binding.ExecutionID + executionIDs[project] = binding.ExecutionID status.UpdatedAt = binding.VerifiedAt break } @@ -64,7 +75,7 @@ func (r releaseProjectStatusResolver) DataframeProjectStatuses(ctx context.Conte } result = append(result, status) } - return result, nil + return executionIDs, result, complete, nil } func (r releaseProjectStatusResolver) ActiveReleaseExecutionIDs(ctx context.Context, projects []string, selector dataset.DataframeSelector) (map[string]string, error) { @@ -116,6 +127,21 @@ func (r releaseProjectStatusResolver) latestAttempts(ctx context.Context, select if r.executions == nil { return latest, nil } + if catalog, ok := r.executions.(publication.SelectorExecutionCatalog); ok { + executions, err := catalog.ListSelectorExecutions(ctx, selector, time.Now().UTC().Add(time.Second)) + if err != nil { + return nil, err + } + for _, execution := range executions { + if execution.Project == "" || !executionContainsSelector(execution, selector) { + continue + } + if prior, exists := latest[execution.Project]; !exists || execution.UpdatedAt.After(prior.UpdatedAt) { + latest[execution.Project] = execution + } + } + return latest, nil + } for _, state := range []publication.BundleState{publication.BundleQueued, publication.BundleRunning, publication.BundleValidating, publication.BundlePublished, publication.BundleFailed} { executions, err := r.executions.ListExecutions(ctx, state, time.Now().UTC().Add(time.Second)) if err != nil { @@ -150,3 +176,4 @@ func executionContainsSelector(execution publication.BundleExecution, selector d var _ published.ProjectStatusResolver = releaseProjectStatusResolver{} var _ published.ReleaseExecutionResolver = releaseProjectStatusResolver{} +var _ published.FederationSnapshotResolver = releaseProjectStatusResolver{} diff --git a/internal/server/server.go b/internal/server/server.go index 2cc7e43f..0bff5ea5 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -219,6 +219,20 @@ func run(ctx context.Context, serverConfig Config) error { } verificationStore := publicationVerificationStore{executions: publishedRegistry, query: lifecycleClient} releaseService := &publicationcontract.ReleaseService{Snapshots: lifecycleStore, Releases: lifecycleStore, Verifier: verificationStore, Required: serverConfig.Server.RequiredDataframeSelectors} + activateExplorerRelease := func(ctx context.Context, project, generation string, selectors []publicationcontract.DataframeSelector) error { + expectedRevision := int64(0) + active, err := releaseService.Active(ctx, project) + if err == nil { + expectedRevision = active.Revision + } else if !errors.Is(err, publicationcontract.ErrNoActiveRelease) { + return err + } + _, err = releaseService.Activate(ctx, publicationcontract.ActivationRequest{ + Project: project, Generation: generation, GitCommit: generation, + ExpectedRevision: expectedRevision, OptionalSelectors: selectors, + }) + return err + } noAuthEnabled := serverConfig.Server.AllowUnauthenticated || serverConfig.Auth.AllowUnauthenticated var candidateProjects func(context.Context) ([]string, error) if noAuthEnabled { @@ -231,6 +245,7 @@ func run(ctx context.Context, serverConfig Config) error { statusResolver := releaseProjectStatusResolver{releases: lifecycleStore, executions: publishedRegistry} materializationReader.ProjectStatusResolver = statusResolver materializationReader.ReleaseExecutionResolver = statusResolver + materializationReader.FederationSnapshotResolver = statusResolver } var exactStarter graphresolver.ExactMaterializationStarter if publicationWorker != nil { @@ -368,7 +383,8 @@ func run(ctx context.Context, serverConfig Config) error { Preview: func(ctx context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (map[string][]map[string]any, error) { return recipeEngine.PreviewBundle(ctx, bundle, bindings) }, - Materialize: explorerMaterializer, + Materialize: explorerMaterializer, + ActivateRelease: activateExplorerRelease, }) if publicationWorker != nil { go func() { From 3dabc30a83a50c54262a0bbad43e90b12ca8a8bc Mon Sep 17 00:00:00 2001 From: matthewpeterkort Date: Wed, 19 Aug 2026 16:00:30 -0700 Subject: [PATCH 06/15] begin stabilizing preview and publish api --- docs/FRONTEND_EXPLORER_V2_MIGRATION.md | 30 +- internal/dataframe/publication/bundle.go | 14 +- .../publication/clickhouse/bundle_store.go | 2 +- .../publication/clickhouse/target.go | 8 +- .../publication/clickhouse/target_test.go | 16 + internal/dataframe/publication/runner.go | 53 +- internal/dataframe/publication/runner_test.go | 28 + internal/dataframe/publication/types.go | 13 + internal/dataframe/recipe/json_encoding.go | 46 ++ internal/dataframe/recipe/types_test.go | 25 + .../dataset/arango/snapshot_release_store.go | 1 - internal/dataset/arango/store_test.go | 5 +- internal/dataset/release.go | 54 +- internal/dataset/release_test.go | 89 +++ internal/explorer/arango/store.go | 78 ++- internal/explorer/arango/store_test.go | 14 + internal/explorer/memory_store.go | 35 +- internal/explorer/service.go | 35 +- internal/explorer/store.go | 6 +- internal/explorer/types.go | 29 +- internal/explorer/v2_lifecycle_test.go | 29 +- internal/server/explorer_v2_engine.go | 44 +- internal/server/explorer_v2_engine_test.go | 150 +++++ internal/server/explorer_v2_lifecycle.go | 587 ++++++++++++++++-- internal/server/explorer_v2_lifecycle_test.go | 269 +++++++- internal/server/recipe_publication.go | 13 +- internal/server/server.go | 11 +- internal/store/clickhouse/client.go | 161 +++++ internal/store/clickhouse/client_test.go | 37 ++ internal/store/clickhouse/integration_test.go | 70 +++ 30 files changed, 1788 insertions(+), 164 deletions(-) diff --git a/docs/FRONTEND_EXPLORER_V2_MIGRATION.md b/docs/FRONTEND_EXPLORER_V2_MIGRATION.md index e04d3c14..099081da 100644 --- a/docs/FRONTEND_EXPLORER_V2_MIGRATION.md +++ b/docs/FRONTEND_EXPLORER_V2_MIGRATION.md @@ -324,17 +324,31 @@ Content-Type: application/json ``` Publish reads the server-owned draft. The frontend does not send a config in -this request. Loom recompiles the draft, materializes every referenced output, -checks that every output is queryable, inserts an immutable revision, updates -the project's active release with those outputs, and then activates the -Explorer revision. This applies to both custom Explorers and `default`. -Existing publications from other Explorers remain in the active release. A -failed publication or release activation leaves the previous Explorer revision -in place and records diagnostics on the failed revision. +this request. Loom recompiles the draft against the current active dataset +generation, reuses outputs whose generation and output fingerprint still +match, and materializes only missing or changed outputs. Loom then atomically +activates the matching dataset release, persists its materialization metadata, +inserts an immutable Explorer revision, and activates that revision. This +applies to both custom Explorers and `default`. + +The generation resolved during compilation is authoritative for the entire +publish operation. Loom validates that its immutable snapshot is staged before +starting materialization, so a stale or incomplete generation does not leave +behind an expensive partial build. A failed publish leaves the previous +Explorer revision and dataset release active. The authoring UI exposes Preview and Publish; it does not expose separate create-release, save-release, or activate-release controls. Release records are -internal atomic visibility and audit metadata managed by Publish. +internal visibility and audit metadata managed by the ingestion/deployment +pipeline. + +Publish failures use stable frontend-safe error codes and do not expose raw +database errors. `DATASET_GENERATION_UNAVAILABLE` and +`DATASET_GENERATION_NOT_READY` mean data loading has not produced an activatable +generation; `DATASET_RELEASE_CONFLICT` means the active generation changed +during publish. These responses set `retryable: true` and include `requestId` +when available. Clear the Publishing state, retain the draft, show the friendly +`message`, and offer Retry; include `requestId` in support diagnostics. On success, update the local store from the returned `state` rather than manually inferring active metadata: diff --git a/internal/dataframe/publication/bundle.go b/internal/dataframe/publication/bundle.go index 821f7a2c..f15e6f3e 100644 --- a/internal/dataframe/publication/bundle.go +++ b/internal/dataframe/publication/bundle.go @@ -69,6 +69,7 @@ func (s BundleState) Successful() bool { return s.Canonical() == BundlePublished type BundleIdentity struct { Name string `json:"name"` TranslationVersion string `json:"translationVersion,omitempty"` + OutputName string `json:"outputName,omitempty"` Project string `json:"project"` DatasetGeneration string `json:"datasetGeneration"` RecipeDigest string `json:"recipeDigest"` @@ -83,21 +84,26 @@ type BundleIdentity struct { // Project and generation are part of the key so two tenants can publish the // same recipe/output name without racing a shared pointer. func (i BundleIdentity) PointerName() string { - if strings.TrimSpace(i.TranslationVersion) == "" { - return strings.Join([]string{i.Project, i.DatasetGeneration, i.Name}, "\x00") + parts := []string{i.Project, i.DatasetGeneration, i.Name} + if strings.TrimSpace(i.TranslationVersion) != "" { + parts = append(parts, i.TranslationVersion) } - return strings.Join([]string{i.Project, i.DatasetGeneration, i.Name, i.TranslationVersion}, "\x00") + if strings.TrimSpace(i.OutputName) != "" { + parts = append(parts, i.OutputName) + } + return strings.Join(parts, "\x00") } func (i BundleIdentity) Key() string { b, _ := json.Marshal(struct { Name, Project, DatasetGeneration string TranslationVersion string `json:"TranslationVersion,omitempty"` + OutputName string `json:"OutputName,omitempty"` RecipeDigest, SchemaDigest string ScopeDigest, EngineVersion string AuthScopeMode string `json:"AuthScopeMode,omitempty"` AuthResourcePaths []string `json:"AuthResourcePaths,omitempty"` - }{i.Name, i.Project, i.DatasetGeneration, i.TranslationVersion, i.RecipeDigest, i.SchemaDigest, i.ScopeDigest, i.EngineVersion, i.AuthScopeMode, i.AuthResourcePaths}) + }{i.Name, i.Project, i.DatasetGeneration, i.TranslationVersion, i.OutputName, i.RecipeDigest, i.SchemaDigest, i.ScopeDigest, i.EngineVersion, i.AuthScopeMode, i.AuthResourcePaths}) sum := sha256.Sum256(b) return hex.EncodeToString(sum[:]) } diff --git a/internal/dataframe/publication/clickhouse/bundle_store.go b/internal/dataframe/publication/clickhouse/bundle_store.go index 4bc15deb..bd45d6cb 100644 --- a/internal/dataframe/publication/clickhouse/bundle_store.go +++ b/internal/dataframe/publication/clickhouse/bundle_store.go @@ -675,7 +675,7 @@ func (t *clickHouseBundleTx) failPhase(ctx context.Context, phase, output string var bundleOutputRE = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*$`) var schemaIdentifierRE = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*$`) -var supportedSchemaScalarRE = regexp.MustCompile(`^(String|UUID|Bool|Int8|Int16|Int32|Int64|Int128|Int256|UInt8|UInt16|UInt32|UInt64|UInt128|UInt256|Float32|Float64|Date|Date32|DateTime|DateTime64(\([^)]*\))?)$`) +var supportedSchemaScalarRE = regexp.MustCompile(`^(String|JSON|UUID|Bool|Int8|Int16|Int32|Int64|Int128|Int256|UInt8|UInt16|UInt32|UInt64|UInt128|UInt256|Float32|Float64|Date|Date32|DateTime|DateTime64(\([^)]*\))?)$`) func validateBundleColumn(column publication.PhysicalColumn) error { if column.Name == "" || !schemaIdentifierRE.MatchString(column.Name) || column.Name == "__loom_row_id" { diff --git a/internal/dataframe/publication/clickhouse/target.go b/internal/dataframe/publication/clickhouse/target.go index 3cdea381..15a73b2b 100644 --- a/internal/dataframe/publication/clickhouse/target.go +++ b/internal/dataframe/publication/clickhouse/target.go @@ -18,6 +18,10 @@ type Target struct { OwnerID string } +// SupportsObjectValues tells the generic publication runner that this target +// can persist logical object values as native ClickHouse JSON columns. +func (t *Target) SupportsObjectValues() bool { return true } + func New(bundleStore IdentityBundleStore) (*Target, error) { if bundleStore == nil { return nil, fmt.Errorf("ClickHouse bundle store is required") @@ -26,7 +30,7 @@ func New(bundleStore IdentityBundleStore) (*Target, error) { } func (t *Target) Begin(ctx context.Context, identity publication.PublicationIdentity, schemas []publication.OutputSchema) (publication.Transaction, error) { - bundleIdentity := publication.BundleIdentity{Name: identity.Name, TranslationVersion: identity.TranslationVersion, Project: identity.Project, DatasetGeneration: identity.DatasetGeneration, RecipeDigest: identity.RecipeDigest, SchemaDigest: identity.SchemaDigest, ScopeDigest: identity.ScopeDigest, EngineVersion: identity.EngineVersion, AuthScopeMode: identity.AuthScopeMode, AuthResourcePaths: append([]string(nil), identity.AuthResourcePaths...)} + bundleIdentity := publication.BundleIdentity{Name: identity.Name, TranslationVersion: identity.TranslationVersion, OutputName: identity.OutputName, Project: identity.Project, DatasetGeneration: identity.DatasetGeneration, RecipeDigest: identity.RecipeDigest, SchemaDigest: identity.SchemaDigest, ScopeDigest: identity.ScopeDigest, EngineVersion: identity.EngineVersion, AuthScopeMode: identity.AuthScopeMode, AuthResourcePaths: append([]string(nil), identity.AuthResourcePaths...)} var tx publication.AtomicBundleTx var err error if t.ExecutionID != "" { @@ -189,7 +193,7 @@ func toColumns(columns []publication.LogicalColumn) ([]store.Column, error) { case "code": columnType = "String" case "object": - return nil, fmt.Errorf("object-valued column %q is not supported", column.Name) + columnType = "JSON" } if column.Repeated { columnType = "Array(" + columnType + ")" diff --git a/internal/dataframe/publication/clickhouse/target_test.go b/internal/dataframe/publication/clickhouse/target_test.go index 216f7551..dfa00b88 100644 --- a/internal/dataframe/publication/clickhouse/target_test.go +++ b/internal/dataframe/publication/clickhouse/target_test.go @@ -21,3 +21,19 @@ func TestToColumnsPreservesNullableFlatTypes(t *testing.T) { t.Fatalf("tags type = %q", columns[1].Type) } } + +func TestToColumnsUsesNativeJSONForObjectValues(t *testing.T) { + columns, err := toColumns([]publication.LogicalColumn{ + {Name: "method", Kind: "object", Nullable: true}, + {Name: "methods", Kind: "object", Repeated: true}, + }) + if err != nil { + t.Fatal(err) + } + if columns[0].Type != "Nullable(JSON)" { + t.Fatalf("method type = %q", columns[0].Type) + } + if columns[1].Type != "Array(JSON)" { + t.Fatalf("methods type = %q", columns[1].Type) + } +} diff --git a/internal/dataframe/publication/runner.go b/internal/dataframe/publication/runner.go index 783523ee..ec7ff7bf 100644 --- a/internal/dataframe/publication/runner.go +++ b/internal/dataframe/publication/runner.go @@ -26,7 +26,11 @@ func Publish(ctx context.Context, target Target, identity PublicationIdentity, o if err != nil { return Result{}, err } - schemas, err := validateOutputs(normalizedOutputs) + supportsObjects := false + if objectTarget, ok := target.(ObjectValueTarget); ok { + supportsObjects = objectTarget.SupportsObjectValues() + } + schemas, err := validateOutputs(normalizedOutputs, supportsObjects) if err != nil { return Result{}, dataframeerrors.Wrap(err, dataframeerrors.CodeInvalidData, "") } @@ -76,7 +80,7 @@ func Publish(ctx context.Context, target Target, identity PublicationIdentity, o if err := ctx.Err(); err != nil { return err } - if err := validateRow(output.Columns, row); err != nil { + if err := validateRow(output.Columns, row, supportsObjects); err != nil { return dataframeerrors.Wrap(err, dataframeerrors.CodeInvalidData, "") } for _, column := range output.Columns { @@ -211,7 +215,7 @@ func cloneRow(row map[string]any) map[string]any { return copy } -func validateOutputs(outputs []OutputStream) ([]OutputSchema, error) { +func validateOutputs(outputs []OutputStream, supportsObjects bool) ([]OutputSchema, error) { seen := map[string]struct{}{} schemas := make([]OutputSchema, 0, len(outputs)) for _, output := range outputs { @@ -232,6 +236,9 @@ func validateOutputs(outputs []OutputStream) ([]OutputSchema, error) { if strings.TrimSpace(column.Name) == "" || strings.TrimSpace(column.Kind) == "" { return nil, fmt.Errorf("output %q has an invalid column", name) } + if strings.EqualFold(strings.TrimSpace(column.Kind), "object") && !supportsObjects { + return nil, fmt.Errorf("output %q object-valued column %q is not supported by the publication target", name, column.Name) + } if _, ok := columnSeen[column.Name]; ok { return nil, fmt.Errorf("output %q column %q is duplicated", name, column.Name) } @@ -242,7 +249,7 @@ func validateOutputs(outputs []OutputStream) ([]OutputSchema, error) { return schemas, nil } -func validateRow(columns []LogicalColumn, row map[string]any) error { +func validateRow(columns []LogicalColumn, row map[string]any, supportsObjects bool) error { if row == nil { return fmt.Errorf("row is nil") } @@ -259,7 +266,7 @@ func validateRow(columns []LogicalColumn, row map[string]any) error { } continue } - if err := validateValue(column, value); err != nil { + if err := validateValue(column, value, supportsObjects); err != nil { return err } } @@ -284,23 +291,23 @@ func populatedValue(column LogicalColumn, value any) bool { return true } -func validateValue(column LogicalColumn, value any) error { +func validateValue(column LogicalColumn, value any, supportsObjects bool) error { if column.Repeated { v := reflect.ValueOf(value) if v.Kind() != reflect.Array && v.Kind() != reflect.Slice { return fmt.Errorf("column %q must be repeated", column.Name) } for i := 0; i < v.Len(); i++ { - if err := validateScalar(column, v.Index(i).Interface()); err != nil { + if err := validateScalar(column, v.Index(i).Interface(), supportsObjects); err != nil { return err } } return nil } - return validateScalar(column, value) + return validateScalar(column, value, supportsObjects) } -func validateScalar(column LogicalColumn, value any) error { +func validateScalar(column LogicalColumn, value any, supportsObjects bool) error { if value == nil { return nil } @@ -322,7 +329,13 @@ func validateScalar(column LogicalColumn, value any) error { case "boolean": _, valid = value.(bool) case "object": - return fmt.Errorf("object-valued column %q is not supported by the flat publication contract", column.Name) + if !supportsObjects { + return fmt.Errorf("object-valued column %q is not supported by the flat publication contract", column.Name) + } + if err := validateObjectValue(value); err != nil { + return fmt.Errorf("object-valued column %q is invalid: %w", column.Name, err) + } + valid = true default: return fmt.Errorf("column %q has unsupported logical kind %q", column.Name, column.Kind) } @@ -336,3 +349,23 @@ func validateScalar(column LogicalColumn, value any) error { } return nil } + +func validateObjectValue(value any) error { + rv := reflect.ValueOf(value) + for rv.IsValid() && (rv.Kind() == reflect.Interface || rv.Kind() == reflect.Pointer) { + if rv.IsNil() { + return nil + } + rv = rv.Elem() + } + if !rv.IsValid() { + return nil + } + if rv.Kind() != reflect.Map && rv.Kind() != reflect.Struct { + return fmt.Errorf("expected an object, got %T", value) + } + if _, err := json.Marshal(value); err != nil { + return fmt.Errorf("cannot encode as JSON: %w", err) + } + return nil +} diff --git a/internal/dataframe/publication/runner_test.go b/internal/dataframe/publication/runner_test.go index 0fd92cbb..8c984aa2 100644 --- a/internal/dataframe/publication/runner_test.go +++ b/internal/dataframe/publication/runner_test.go @@ -51,6 +51,10 @@ func (t *finalizingTarget) Begin(_ context.Context, _ PublicationIdentity, _ []O return t.tx, nil } +type objectTarget struct{ fakeTarget } + +func (t *objectTarget) SupportsObjectValues() bool { return true } + func TestPublishPrunesOnlyUnpopulatedDiscoveredColumns(t *testing.T) { target := &finalizingTarget{} columns := []LogicalColumn{ @@ -131,6 +135,30 @@ func TestPublishValidatesAndBoundsBatches(t *testing.T) { } } +func TestPublishAllowsObjectsOnlyForObjectCapableTargets(t *testing.T) { + row := map[string]any{"value": map[string]any{"code": "M1", "active": true}} + columns := []LogicalColumn{{Name: "value", Kind: "object"}} + unsupported := &fakeTarget{} + _, err := Publish(context.Background(), unsupported, PublicationIdentity{Name: "r"}, []OutputStream{{ + Name: "objects", Columns: columns, Stream: func(_ context.Context, visit func(map[string]any) error) error { + return visit(row) + }, + }}, Limits{}) + if err == nil { + t.Fatal("expected generic target to reject object schema") + } + + target := &objectTarget{} + _, err = Publish(context.Background(), target, PublicationIdentity{Name: "r"}, []OutputStream{{ + Name: "objects", Columns: columns, Stream: func(_ context.Context, visit func(map[string]any) error) error { + return visit(row) + }, + }}, Limits{}) + if err != nil { + t.Fatal(err) + } +} + func TestPublishProjectIDIsTrustedAndDeduplicated(t *testing.T) { target := &fakeTarget{} _, err := Publish(context.Background(), target, PublicationIdentity{Name: "r", Project: "trusted"}, []OutputStream{{ diff --git a/internal/dataframe/publication/types.go b/internal/dataframe/publication/types.go index 15e4c835..76663d4d 100644 --- a/internal/dataframe/publication/types.go +++ b/internal/dataframe/publication/types.go @@ -51,6 +51,10 @@ type OutputStream struct { type PublicationIdentity struct { Name string TranslationVersion string + // OutputName scopes single-output publications. The field is empty for + // legacy/full-bundle publications and is used by incremental Explorer + // loads so each output can retain its own visibility pointer. + OutputName string Project string DatasetGeneration string RecipeDigest string @@ -73,6 +77,15 @@ type Target interface { Begin(context.Context, PublicationIdentity, []OutputSchema) (Transaction, error) } +// ObjectValueTarget is implemented by publication targets that can persist +// logical object columns without flattening or stringifying them. Targets +// that do not implement this capability continue to receive the generic flat +// publication contract, where object values are rejected before any rows are +// written. +type ObjectValueTarget interface { + SupportsObjectValues() bool +} + type Transaction interface { WriteBatch(context.Context, string, []map[string]any) error Commit(context.Context) ([]PublishedOutput, error) diff --git a/internal/dataframe/recipe/json_encoding.go b/internal/dataframe/recipe/json_encoding.go index 161385b2..60a2ce12 100644 --- a/internal/dataframe/recipe/json_encoding.go +++ b/internal/dataframe/recipe/json_encoding.go @@ -7,6 +7,7 @@ import ( "bytes" "encoding/json" "fmt" + "io" "strings" ) @@ -179,6 +180,51 @@ func (e *Expression) UnmarshalJSON(data []byte) error { return nil } +// UnmarshalJSON accepts the small amount of field metadata emitted by the +// Explorer Builder while keeping that presentation metadata out of the +// executable recipe. The Builder historically included catalog information +// alongside the semantic field declaration; those values are useful to the +// UI, but the recipe compiler derives them from the expression and schema. +// Keep this compatibility surface explicit so unrelated recipe typos remain +// strict parse errors. +func (f *Field) UnmarshalJSON(data []byte) error { + type fieldJSON struct { + Name string `json:"name"` + FieldRef string `json:"fieldRef,omitempty"` + Expr Expression `json:"expr"` + Fallbacks []Expression `json:"fallbacks,omitempty"` + ValueMode ValueMode `json:"valueMode,omitempty"` + + // Explorer Builder catalog/presentation metadata. These fields are + // intentionally not copied into Field. + LogicalType string `json:"logicalType,omitempty"` + Repeated bool `json:"repeated,omitempty"` + Family string `json:"family,omitempty"` + SelectionKey string `json:"selectionKey,omitempty"` + ValueSelector string `json:"valueSelector,omitempty"` + FamilyName string `json:"familyName,omitempty"` + FamilyKind string `json:"familyKind,omitempty"` + } + var value fieldJSON + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + if err := decoder.Decode(&value); err != nil { + return err + } + var trailing any + if err := decoder.Decode(&trailing); err != io.EOF { + if err == nil { + return fmt.Errorf("field contains trailing JSON") + } + return err + } + *f = Field{ + Name: value.Name, FieldRef: value.FieldRef, Expr: value.Expr, + Fallbacks: value.Fallbacks, ValueMode: value.ValueMode, + } + return nil +} + // Parse strictly decodes and validates a recipe document. func Parse(data []byte) (Bundle, error) { if err := detectDuplicateKeys(data); err != nil { diff --git a/internal/dataframe/recipe/types_test.go b/internal/dataframe/recipe/types_test.go index 200fd81b..c036d3b1 100644 --- a/internal/dataframe/recipe/types_test.go +++ b/internal/dataframe/recipe/types_test.go @@ -78,6 +78,31 @@ func TestParseRejectsDuplicateUnknownAndStorageFields(t *testing.T) { } } +func TestParseAcceptsBuilderFieldMetadataWithoutPersistingIt(t *testing.T) { + input := `{"recipeSchemaVersion":1,"name":"builder","translationVersion":"interactive","outputs":[{"name":"DocumentReference","rootResourceType":"DocumentReference","rowGrain":"resource","fields":[{"name":"status","fieldRef":"DocumentReference.status","expr":{"select":"root.status"},"logicalType":"scalar","repeated":false,"family":"field","selectionKey":"DocumentReference.status","valueSelector":"status","familyName":"Fields","familyKind":"FIELD"}]}]}` + bundle, err := Parse([]byte(input)) + if err != nil { + t.Fatal(err) + } + canonical, err := bundle.CanonicalJSON() + if err != nil { + t.Fatal(err) + } + if bytes.Contains(canonical, []byte("logicalType")) || bytes.Contains(canonical, []byte("selectionKey")) { + t.Fatalf("Builder metadata leaked into executable recipe: %s", canonical) + } + if !bytes.Contains(canonical, []byte(`"fieldRef":"DocumentReference.status"`)) { + t.Fatalf("semantic field provenance was lost: %s", canonical) + } +} + +func TestParseStillRejectsUnknownBuilderFieldMetadata(t *testing.T) { + input := `{"recipeSchemaVersion":1,"name":"builder","translationVersion":"interactive","outputs":[{"name":"DocumentReference","rootResourceType":"DocumentReference","rowGrain":"resource","fields":[{"name":"status","expr":{"select":"root.status"},"logicalTypo":"scalar"}]}]}` + if _, err := Parse([]byte(input)); err == nil || !strings.HasPrefix(err.Error(), "parse_error ") { + t.Fatalf("expected strict parse error, got %v", err) + } +} + func TestValidationRejectsVersionNamesAndArity(t *testing.T) { bad := []string{ `{"recipeSchemaVersion":2,"name":"x","translationVersion":"1","outputs":[]}`, diff --git a/internal/dataset/arango/snapshot_release_store.go b/internal/dataset/arango/snapshot_release_store.go index 1264eccd..495c19eb 100644 --- a/internal/dataset/arango/snapshot_release_store.go +++ b/internal/dataset/arango/snapshot_release_store.go @@ -176,7 +176,6 @@ func (s *Store) CompareAndSwapActivateRelease(ctx context.Context, release datas releaseDocument["recordType"] = releaseRecordType binds := lifecycleCollectionBindVars() binds["project"] = release.Project - binds["release"] = releaseDocument binds["release_key"] = releaseDocument["_key"] binds["release_id"] = release.ID binds["generation"] = release.Generation diff --git a/internal/dataset/arango/store_test.go b/internal/dataset/arango/store_test.go index 1dce7b85..057f36db 100644 --- a/internal/dataset/arango/store_test.go +++ b/internal/dataset/arango/store_test.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "reflect" + "regexp" "strings" "testing" "time" @@ -195,6 +196,7 @@ func TestReleaseActivationAtomicallyUpdatesReleaseAndGenerationPointers(t *testi if got := strings.Count(call.query, "UPDATE "); got != 1 { t.Fatalf("release activation must use one AQL modification operation, got %d:\n%s", got, call.query) } + assertOnlyDeclaredBindVariables(t, call) } func TestSaveReleasePersistsCandidateWithoutMovingVisibility(t *testing.T) { @@ -245,7 +247,8 @@ func TestReadActiveReleasePassesOnlyDeclaredBindVariables(t *testing.T) { func assertOnlyDeclaredBindVariables(t *testing.T, call queryCall) { t.Helper() for name := range call.bindVars { - if !strings.Contains(call.query, "@"+name) { + pattern := "@" + regexp.QuoteMeta(name) + `\b` + if !regexp.MustCompile(pattern).MatchString(call.query) { t.Errorf("bind variable %q is not declared in query", name) } } diff --git a/internal/dataset/release.go b/internal/dataset/release.go index b736a855..42d1249a 100644 --- a/internal/dataset/release.go +++ b/internal/dataset/release.go @@ -85,6 +85,10 @@ type PublicationVerifier interface { VerifyPublication(context.Context, string, string, DataframeSelector) (PublicationVerification, error) } +type ManifestReader interface { + ReadManifest(context.Context, Ref) (Manifest, error) +} + type ReleaseRepository interface { SaveRelease(context.Context, ProjectRelease) (ProjectRelease, error) ReadRelease(context.Context, string, string) (ProjectRelease, error) @@ -95,12 +99,56 @@ type ReleaseRepository interface { type ReleaseService struct { Snapshots SnapshotRepository + // Manifests provides compatibility for valid generations created before + // upload-tracking snapshot records were introduced. Release activation is + // already guarded by this same immutable staged manifest. + Manifests ManifestReader Releases ReleaseRepository Verifier PublicationVerifier Required []DataframeSelector Now func() time.Time } +// ValidateGeneration verifies the immutable graph-generation prerequisite used +// by release creation. Callers that perform expensive work before activating a +// release can use this as a preflight and avoid producing orphaned dataframe +// publications for a generation that cannot be activated. +func (s ReleaseService) ValidateGeneration(ctx context.Context, project, generation string) error { + if s.Snapshots == nil { + return fmt.Errorf("snapshot repository is required") + } + ref, err := NewRef(strings.TrimSpace(project), strings.TrimSpace(generation)) + if err != nil { + return err + } + return s.validateGeneration(ctx, ref) +} + +func (s ReleaseService) validateGeneration(ctx context.Context, ref Ref) error { + snapshot, err := s.Snapshots.ReadSnapshot(ctx, ref) + if err == nil { + if snapshot.State != StateStaged { + return fmt.Errorf("%w: generation %s is %s", ErrReleaseRequirementsUnmet, ref.Generation, snapshot.State) + } + return nil + } + if !errors.Is(err, ErrSnapshotNotFound) || s.Manifests == nil { + return err + } + // Legacy loads can have the durable manifest and active graph pointer but no + // snapshot_generation upload-audit document. The manifest is the exact + // generation record checked again by the atomic activation transaction, so a + // staged legacy manifest is sufficient and does not need fabricated uploads. + manifest, manifestErr := s.Manifests.ReadManifest(ctx, ref) + if manifestErr != nil { + return err + } + if !manifest.IsStaged() { + return fmt.Errorf("%w: generation %s manifest is %s", ErrReleaseRequirementsUnmet, ref.Generation, manifest.State) + } + return nil +} + func (s ReleaseService) Create(ctx context.Context, request ActivationRequest) (ProjectRelease, error) { if s.Snapshots == nil || s.Releases == nil || s.Verifier == nil { return ProjectRelease{}, fmt.Errorf("release service dependencies are required") @@ -115,13 +163,9 @@ func (s ReleaseService) Create(ctx context.Context, request ActivationRequest) ( if request.GitCommit != ref.Generation { return ProjectRelease{}, fmt.Errorf("gitCommit must match generation") } - snapshot, err := s.Snapshots.ReadSnapshot(ctx, ref) - if err != nil { + if err := s.validateGeneration(ctx, ref); err != nil { return ProjectRelease{}, err } - if snapshot.State != StateStaged { - return ProjectRelease{}, fmt.Errorf("%w: generation %s is %s", ErrReleaseRequirementsUnmet, ref.Generation, snapshot.State) - } previous, previousErr := s.Releases.ReadActiveRelease(ctx, ref.Project) if previousErr != nil && !errors.Is(previousErr, ErrNoActiveRelease) { diff --git a/internal/dataset/release_test.go b/internal/dataset/release_test.go index 4add6e35..4b7ef995 100644 --- a/internal/dataset/release_test.go +++ b/internal/dataset/release_test.go @@ -15,6 +15,15 @@ type verificationFixture struct { errors map[string]error } +type manifestReaderFixture struct { + manifest Manifest + err error +} + +func (f manifestReaderFixture) ReadManifest(context.Context, Ref) (Manifest, error) { + return f.manifest, f.err +} + func (f *verificationFixture) VerifyPublication(_ context.Context, _, _ string, selector DataframeSelector) (PublicationVerification, error) { f.mu.Lock() defer f.mu.Unlock() @@ -53,6 +62,86 @@ func TestReleaseActivationRequiresPublishedQueryableGenerationAndPreservesPointe } } +func TestValidateGenerationRequiresExistingStagedSnapshot(t *testing.T) { + ctx := context.Background() + store := NewMemoryLifecycleStore() + service := ReleaseService{Snapshots: store} + + if err := service.ValidateGeneration(ctx, "project-a", "missing"); !errors.Is(err, ErrSnapshotNotFound) { + t.Fatalf("missing generation validation = %v", err) + } + + now := time.Date(2026, 8, 19, 12, 0, 0, 0, time.UTC) + snapshot, err := NewSnapshotGeneration("project-a", "loading", "", []string{"Patient"}, now) + if err != nil { + t.Fatal(err) + } + if _, err := store.CreateOrResumeSnapshot(ctx, snapshot); err != nil { + t.Fatal(err) + } + if err := service.ValidateGeneration(ctx, "project-a", "loading"); !errors.Is(err, ErrReleaseRequirementsUnmet) { + t.Fatalf("loading generation validation = %v", err) + } + + stageSnapshot(t, store, "project-a", "staged", now) + if err := service.ValidateGeneration(ctx, "project-a", "staged"); err != nil { + t.Fatalf("staged generation validation = %v", err) + } +} + +func TestValidateGenerationAcceptsLegacyStagedManifestWithoutSnapshot(t *testing.T) { + ctx := context.Background() + store := NewMemoryLifecycleStore() + ref, err := NewRef("project-a", "legacy-generation") + if err != nil { + t.Fatal(err) + } + schema, err := NewSchemaSnapshot("schema-a", "R4", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", []string{"Patient"}) + if err != nil { + t.Fatal(err) + } + manifest, err := NewManifest(ref, schema) + if err != nil { + t.Fatal(err) + } + manifest, err = manifest.Transition(StateReady) + if err != nil { + t.Fatal(err) + } + selector := DataframeSelector{Recipe: "explorer", TranslationVersion: "v1", Output: "Patient"} + verifier := &verificationFixture{results: map[string]PublicationVerification{ + selector.Key(): published(selector, "execution-a", ref.Generation, time.Now().UTC()), + }, errors: map[string]error{}} + service := ReleaseService{Snapshots: store, Manifests: manifestReaderFixture{manifest: manifest}, Releases: store, Verifier: verifier, Required: []DataframeSelector{selector}} + if err := service.ValidateGeneration(ctx, ref.Project, ref.Generation); err != nil { + t.Fatalf("legacy staged manifest validation = %v", err) + } + if release, err := service.Create(ctx, ActivationRequest{Project: ref.Project, Generation: ref.Generation}); err != nil || release.Generation != ref.Generation { + t.Fatalf("legacy staged manifest release = %#v, %v", release, err) + } +} + +func TestValidateGenerationRejectsLegacyLoadingManifestWithoutSnapshot(t *testing.T) { + ctx := context.Background() + store := NewMemoryLifecycleStore() + ref, err := NewRef("project-a", "legacy-loading") + if err != nil { + t.Fatal(err) + } + schema, err := NewSchemaSnapshot("schema-a", "R4", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", []string{"Patient"}) + if err != nil { + t.Fatal(err) + } + manifest, err := NewManifest(ref, schema) + if err != nil { + t.Fatal(err) + } + service := ReleaseService{Snapshots: store, Manifests: manifestReaderFixture{manifest: manifest}} + if err := service.ValidateGeneration(ctx, ref.Project, ref.Generation); !errors.Is(err, ErrReleaseRequirementsUnmet) { + t.Fatalf("legacy loading manifest validation = %v", err) + } +} + func TestReleaseActivationCarriesOptionalPublicationAsStale(t *testing.T) { ctx := context.Background() store := NewMemoryLifecycleStore() diff --git a/internal/explorer/arango/store.go b/internal/explorer/arango/store.go index 4f0d5c87..178e7f24 100644 --- a/internal/explorer/arango/store.go +++ b/internal/explorer/arango/store.go @@ -58,11 +58,7 @@ func (s *Store) ListConfigs(ctx context.Context, project string) ([]explorer.Rep } func (s *Store) GetConfig(ctx context.Context, project, id string) (*explorer.RepositoryConfig, error) { var out *explorer.RepositoryConfig - keys := []string{configKey(project, id)} - if id == "default" { - keys = append(keys, repositoryConfigKey(project)) - } - err := s.client.QueryRows(ctx, `FOR d IN @@c FILTER d._key IN @keys SORT d.updatedAt DESC RETURN d`, 1, map[string]any{"@c": RepositoryConfigsCollection, "keys": keys}, func(row map[string]any) error { v, err := decode[explorer.RepositoryConfig](row); out = &v; return err }) + err := s.client.QueryRows(ctx, `FOR d IN @@c FILTER d._key == @key RETURN d`, 1, map[string]any{"@c": RepositoryConfigsCollection, "key": configKey(project, id)}, func(row map[string]any) error { v, err := decode[explorer.RepositoryConfig](row); out = &v; return err }) if err != nil { return nil, err } @@ -88,11 +84,32 @@ func (s *Store) SaveConfig(ctx context.Context, value explorer.RepositoryConfig) return out, nil } func (s *Store) GetRepositoryConfig(ctx context.Context, project string) (*explorer.RepositoryConfig, error) { - return s.GetConfig(ctx, project, "default") + var out *explorer.RepositoryConfig + err := s.client.QueryRows(ctx, `FOR d IN @@c FILTER d._key == @key RETURN d`, 1, map[string]any{"@c": RepositoryConfigsCollection, "key": repositoryConfigKey(project)}, func(row map[string]any) error { v, err := decode[explorer.RepositoryConfig](row); out = &v; return err }) + if err != nil { + return nil, err + } + if out == nil { + return nil, explorer.ErrNotFound + } + if out.ExplorerID == "" { + out.ExplorerID, out.Management = "default", explorer.ManagementRepository + } + return out, nil } func (s *Store) SaveRepositoryConfig(ctx context.Context, value explorer.RepositoryConfig) (*explorer.RepositoryConfig, error) { value.ExplorerID, value.Management = "default", explorer.ManagementRepository - return s.SaveConfig(ctx, value) + value.UpdatedAt = time.Now().UTC() + doc, err := document(value, repositoryConfigKey(value.Project)) + if err != nil { + return nil, err + } + var out *explorer.RepositoryConfig + err = s.client.QueryRows(ctx, `UPSERT { _key: @key } INSERT @doc UPDATE @doc IN @@c RETURN NEW`, 1, map[string]any{"@c": RepositoryConfigsCollection, "key": repositoryConfigKey(value.Project), "doc": doc}, func(row map[string]any) error { v, err := decode[explorer.RepositoryConfig](row); out = &v; return err }) + if err != nil { + return nil, err + } + return out, nil } func (s *Store) List(ctx context.Context, project string) ([]explorer.Explorer, error) { out := []explorer.Explorer{} @@ -135,18 +152,13 @@ func (s *Store) CreateRepository(ctx context.Context, e explorer.Explorer) (*exp return s.CreateInteractive(ctx, e) } func (s *Store) SaveDraft(ctx context.Context, e explorer.Explorer, expected int64, expectedDigest ...string) (*explorer.Explorer, error) { - e.DraftVersion = expected + 1 e.UpdatedAt = time.Now().UTC() raw, err := document(e, explorerKey(e.Project, e.ExplorerID)) if err != nil { return nil, err } var out *explorer.Explorer - digest := "" - if len(expectedDigest) > 0 { - digest = expectedDigest[0] - } - err = s.client.QueryRows(ctx, `FOR d IN @@c FILTER d._key == @key AND d.draftVersion == @expected AND (@expectedDigest == "" OR d.draftDigest == @expectedDigest) UPDATE d WITH @doc IN @@c RETURN NEW`, 1, map[string]any{"@c": ExplorersCollection, "key": explorerKey(e.Project, e.ExplorerID), "expected": expected, "expectedDigest": digest, "doc": raw}, func(row map[string]any) error { v, err := decode[explorer.Explorer](row); out = &v; return err }) + err = s.client.QueryRows(ctx, `FOR d IN @@c FILTER d._key == @key UPDATE d WITH MERGE(@doc, { draftVersion: d.draftVersion + 1 }) IN @@c RETURN NEW`, 1, map[string]any{"@c": ExplorersCollection, "key": explorerKey(e.Project, e.ExplorerID), "doc": raw}, func(row map[string]any) error { v, err := decode[explorer.Explorer](row); out = &v; return err }) if err != nil { return nil, err } @@ -449,13 +461,51 @@ var _ explorer.Store = (*Store)(nil) func decode[T any](value any) (T, error) { var out T - raw, err := json.Marshal(value) + raw, err := json.Marshal(normalizeUpdatedAt(value)) if err != nil { return out, err } err = json.Unmarshal(raw, &out) return out, err } + +// normalizeUpdatedAt keeps reads tolerant of the numeric Arango timestamp +// written by the short-lived last-write-wins regression. New writes use the +// normal JSON time string representation, but existing documents must remain +// readable so they can be repaired by a subsequent draft save. +func normalizeUpdatedAt(value any) any { + row, ok := value.(map[string]any) + if !ok { + return value + } + normalized := make(map[string]any, len(row)) + for key, item := range row { + normalized[key] = item + } + if timestamp, ok := numericTimestamp(row["updatedAt"]); ok { + normalized["updatedAt"] = timestamp + } + return normalized +} + +func numericTimestamp(value any) (string, bool) { + var millis int64 + switch number := value.(type) { + case float64: + millis = int64(number) + case float32: + millis = int64(number) + case int: + millis = int64(number) + case int64: + millis = number + case uint64: + millis = int64(number) + default: + return "", false + } + return time.UnixMilli(millis).UTC().Format(time.RFC3339Nano), true +} func document(value any, k string) (map[string]any, error) { raw, err := json.Marshal(value) if err != nil { diff --git a/internal/explorer/arango/store_test.go b/internal/explorer/arango/store_test.go index f386aa79..db130514 100644 --- a/internal/explorer/arango/store_test.go +++ b/internal/explorer/arango/store_test.go @@ -4,10 +4,24 @@ import ( "context" "strings" "testing" + "time" storepkg "github.com/calypr/loom/internal/store/arango" ) +func TestDecodeNormalizesNumericUpdatedAt(t *testing.T) { + timestamp := float64(1776620000000) + value, err := decode[struct { + UpdatedAt time.Time `json:"updatedAt"` + }](map[string]any{"updatedAt": timestamp}) + if err != nil { + t.Fatal(err) + } + if value.UpdatedAt.UnixMilli() != int64(timestamp) { + t.Fatalf("updatedAt=%v, want %d", value.UpdatedAt, int64(timestamp)) + } +} + type queryCall struct { query string binds map[string]any diff --git a/internal/explorer/memory_store.go b/internal/explorer/memory_store.go index 3d5a44f0..5544238f 100644 --- a/internal/explorer/memory_store.go +++ b/internal/explorer/memory_store.go @@ -10,14 +10,15 @@ import ( // MemoryStore is used by service tests and local wiring; durable deployments // use the Arango implementation. type MemoryStore struct { - mu sync.Mutex - explorers map[string]Explorer - revisions map[string]Revision - configs map[string]RepositoryConfig + mu sync.Mutex + explorers map[string]Explorer + revisions map[string]Revision + configs map[string]RepositoryConfig + repositoryConfigs map[string]RepositoryConfig } func NewMemoryStore() *MemoryStore { - return &MemoryStore{explorers: map[string]Explorer{}, revisions: map[string]Revision{}, configs: map[string]RepositoryConfig{}} + return &MemoryStore{explorers: map[string]Explorer{}, revisions: map[string]Revision{}, configs: map[string]RepositoryConfig{}, repositoryConfigs: map[string]RepositoryConfig{}} } func configKey(project, id string) string { return project + "\x00" + id } func (s *MemoryStore) ListConfigs(_ context.Context, project string) ([]RepositoryConfig, error) { @@ -29,6 +30,9 @@ func (s *MemoryStore) ListConfigs(_ context.Context, project string) ([]Reposito out = append(out, value) } } + if value, ok := s.repositoryConfigs[project]; ok { + out = append(out, value) + } sort.Slice(out, func(i, j int) bool { return out[i].ExplorerID < out[j].ExplorerID }) return out, nil } @@ -50,11 +54,22 @@ func (s *MemoryStore) SaveConfig(_ context.Context, value RepositoryConfig) (*Re return &value, nil } func (s *MemoryStore) GetRepositoryConfig(ctx context.Context, project string) (*RepositoryConfig, error) { - return s.GetConfig(ctx, project, "default") + s.mu.Lock() + defer s.mu.Unlock() + v, ok := s.repositoryConfigs[project] + if !ok { + return nil, ErrNotFound + } + return &v, nil } func (s *MemoryStore) SaveRepositoryConfig(ctx context.Context, value RepositoryConfig) (*RepositoryConfig, error) { + s.mu.Lock() + defer s.mu.Unlock() value.ExplorerID, value.Management = "default", ManagementRepository - return s.SaveConfig(ctx, value) + value.UpdatedAt = time.Now().UTC() + value.Config = append([]byte(nil), value.Config...) + s.repositoryConfigs[value.Project] = value + return &value, nil } func explorerKey(project, id string) string { return project + "\x00" + id } func (s *MemoryStore) List(_ context.Context, project string) ([]Explorer, error) { @@ -99,12 +114,6 @@ func (s *MemoryStore) SaveDraft(_ context.Context, e Explorer, expected int64, e if !ok { return nil, ErrNotFound } - if old.DraftVersion != expected { - return nil, ErrDraftConflict - } - if len(expectedDigest) > 0 && expectedDigest[0] != "" && old.DraftDigest != expectedDigest[0] { - return nil, ErrDraftConflict - } e.DraftVersion = old.DraftVersion + 1 e.UpdatedAt = time.Now().UTC() e.DraftConfig = append([]byte(nil), e.DraftConfig...) diff --git a/internal/explorer/service.go b/internal/explorer/service.go index fbcc180e..af22654f 100644 --- a/internal/explorer/service.go +++ b/internal/explorer/service.go @@ -151,7 +151,10 @@ func (s *Service) CreateInteractiveV2(ctx context.Context, project, id string, r } // SaveDraftV2 is the only V2 draft write path. It performs no compilation or -// materialization and supplies both CAS components to the durable adapter. +// materialization. Draft writes are intentionally last-write-wins: the +// expected version and digest are retained for API compatibility and +// observability, but a stale Builder cannot block the latest valid draft from +// being saved. // The repository default is editable; its repository identity is retained in // the packet so a later ETL deployment can still recognize it. func (s *Service) SaveDraftV2(ctx context.Context, project, id string, raw []byte, expected int64, expectedDigest, actor string) (*Explorer, error) { @@ -174,9 +177,6 @@ func (s *Service) SaveDraftV2(ctx context.Context, project, id string, raw []byt if baseDigest == "" { _, _, _, baseDigest, _ = CanonicalConfigV2(repository.Config, project, "default", "repository") } - if expected != baseVersion || (expectedDigest != "" && expectedDigest != baseDigest) { - return nil, ErrDraftConflict - } updatedAt := repository.UpdatedAt if updatedAt.IsZero() { updatedAt = s.now() @@ -212,6 +212,14 @@ func (s *Service) SaveDraftV2(ctx context.Context, project, id string, raw []byt } func (s *Service) InsertReadyRevisionV2(ctx context.Context, owner *Explorer, config []byte, configDigest string, compiled Compilation, resolvedSchemaDigest, sourceGeneration, actor string, materializations []Materialization) (*Revision, error) { + return s.InsertReadyRevisionV2WithMetadata(ctx, owner, config, configDigest, compiled, resolvedSchemaDigest, sourceGeneration, actor, materializations, datasetMetadata(sourceGeneration, resolvedSchemaDigest, materializations), PublicationMetadata{}) +} + +// InsertReadyRevisionV2WithMetadata records a configuration revision against +// an already materialized dataset. Callers that publish an Explorer +// configuration without rebuilding data pass the active release's frozen +// dataset/materialization metadata here so the revision remains queryable. +func (s *Service) InsertReadyRevisionV2WithMetadata(ctx context.Context, owner *Explorer, config []byte, configDigest string, compiled Compilation, resolvedSchemaDigest, sourceGeneration, actor string, materializations []Materialization, dataset DatasetMetadata, publication PublicationMetadata) (*Revision, error) { if owner == nil || (owner.ManagementMode != ManagementInteractive && !(owner.ExplorerID == "default" && owner.ManagementMode == ManagementRepository)) { return nil, fmt.Errorf("Explorer is not editable") } @@ -220,13 +228,28 @@ func (s *Service) InsertReadyRevisionV2(ctx context.Context, owner *Explorer, co return nil, err } now := s.now() + if dataset.Generation == "" { + dataset.Generation = sourceGeneration + } + if dataset.SchemaDigest == "" { + dataset.SchemaDigest = resolvedSchemaDigest + } + if publication.State == "" { + publication.State = string(RevisionReady) + } + if publication.Generation == "" { + publication.Generation = sourceGeneration + } + if publication.UpdatedAt.IsZero() { + publication.UpdatedAt = now + } return s.store.InsertRevision(ctx, Revision{ ID: id, Project: owner.Project, ExplorerID: owner.ExplorerID, Config: append([]byte(nil), config...), ConfigDigest: configDigest, Recipe: compiled.Bundle, RecipeDigest: compiled.RecipeDigest, ResolvedSchemaDigest: resolvedSchemaDigest, SourceGeneration: sourceGeneration, - Dataset: datasetMetadata(sourceGeneration, resolvedSchemaDigest, materializations), - Publication: PublicationMetadata{State: string(RevisionReady), Generation: sourceGeneration, UpdatedAt: now}, + Dataset: dataset, + Publication: publication, EmittedColumns: append([]EmittedColumn(nil), compiled.EmittedColumns...), Materializations: append([]Materialization(nil), materializations...), Status: RevisionReady, CreatedBy: actor, CreatedAt: now, ReadyAt: &now, diff --git a/internal/explorer/store.go b/internal/explorer/store.go index 1d395dab..8ae5d9d1 100644 --- a/internal/explorer/store.go +++ b/internal/explorer/store.go @@ -26,8 +26,10 @@ type Store interface { Get(context.Context, string, string) (*Explorer, error) CreateInteractive(context.Context, Explorer) (*Explorer, error) CreateRepository(context.Context, Explorer) (*Explorer, error) - // expectedDigest is optional so callers can perform a version-only compare; - // when supplied, adapters must include it in the CAS predicate. + // expected and expectedDigest are retained for adapter compatibility and + // observability. Draft writes are last-write-wins; adapters must increment + // the stored draft version from the current value rather than trusting the + // caller's expected version. SaveDraft(context.Context, Explorer, int64, ...string) (*Explorer, error) InsertRevision(context.Context, Revision) (*Revision, error) GetRevision(context.Context, string) (*Revision, error) diff --git a/internal/explorer/types.go b/internal/explorer/types.go index 5d7d218b..615251b7 100644 --- a/internal/explorer/types.go +++ b/internal/explorer/types.go @@ -69,11 +69,12 @@ type DatasetMetadata struct { } type DatasetOutput struct { - Name string `json:"name"` - State string `json:"state"` - Queryable bool `json:"queryable"` - Selector *dataset.DataframeSelector `json:"selector,omitempty"` - Columns []publication.PhysicalColumn `json:"columns,omitempty"` + Name string `json:"name"` + State string `json:"state"` + Queryable bool `json:"queryable"` + Fingerprint string `json:"fingerprint,omitempty"` + Selector *dataset.DataframeSelector `json:"selector,omitempty"` + Columns []publication.PhysicalColumn `json:"columns,omitempty"` } type PublicationMetadata struct { @@ -111,25 +112,17 @@ type Materialization struct { OutputID string `json:"outputId"` Output string `json:"output"` MaterializationID string `json:"materializationId"` + Fingerprint string `json:"fingerprint,omitempty"` Selector *dataset.DataframeSelector `json:"selector,omitempty"` Columns []publication.PhysicalColumn `json:"columns"` } -// WithDataframeSelectors projects the immutable executable recipe identity -// onto server-derived publication metadata. This also upgrades lifecycle -// records written before selectors were persisted without mutating the -// authored ExplorerConfigV2 packet or immutable revision. -func WithDataframeSelectors(bundle recipe.Bundle, materializations []Materialization, metadata DatasetMetadata) ([]Materialization, DatasetMetadata) { +// WithDataframeSelectors clones canonical publication metadata while +// preserving the selectors that identify the active dataset release. Missing +// selectors are invalid and are not synthesized. +func WithDataframeSelectors(_ recipe.Bundle, materializations []Materialization, metadata DatasetMetadata) ([]Materialization, DatasetMetadata) { materializations = append([]Materialization(nil), materializations...) metadata.Outputs = append([]DatasetOutput(nil), metadata.Outputs...) - for index := range materializations { - selector := dataset.DataframeSelector{Recipe: bundle.Name, TranslationVersion: bundle.TranslationVersion, Output: materializations[index].Output} - materializations[index].Selector = &selector - } - for index := range metadata.Outputs { - selector := dataset.DataframeSelector{Recipe: bundle.Name, TranslationVersion: bundle.TranslationVersion, Output: metadata.Outputs[index].Name} - metadata.Outputs[index].Selector = &selector - } return materializations, metadata } diff --git a/internal/explorer/v2_lifecycle_test.go b/internal/explorer/v2_lifecycle_test.go index df24cb4e..51573835 100644 --- a/internal/explorer/v2_lifecycle_test.go +++ b/internal/explorer/v2_lifecycle_test.go @@ -5,7 +5,7 @@ import ( "testing" ) -func TestV2DraftRoundTripAndDigestCAS(t *testing.T) { +func TestV2DraftRoundTripLastWriteWins(t *testing.T) { service, err := NewService(NewMemoryStore()) if err != nil { t.Fatal(err) @@ -40,7 +40,30 @@ func TestV2DraftRoundTripAndDigestCAS(t *testing.T) { if updated.DraftVersion != 2 || updated.DraftDigest != nextDigest { t.Fatalf("updated metadata = %#v", updated) } - if _, err := service.SaveDraftV2(context.Background(), "project-a", "my-explorer", raw, 1, created.DraftDigest, "stale"); err != ErrDraftConflict { - t.Fatalf("stale digest/version save error = %v, want ErrDraftConflict", err) + stale, err := service.SaveDraftV2(context.Background(), "project-a", "my-explorer", raw, 1, created.DraftDigest, "stale") + if err != nil { + t.Fatal(err) + } + if stale.DraftVersion != 3 || stale.DraftDigest == updated.DraftDigest || string(stale.DraftConfig) == string(updated.DraftConfig) { + t.Fatalf("last-write-wins draft = %#v", stale) + } +} + +func TestRepositoryConfigDoesNotFallBackToInteractiveDefault(t *testing.T) { + store := NewMemoryStore() + interactive := RepositoryConfig{Project: "project-a", ExplorerID: "default", Management: ManagementInteractive, SourceGeneration: "interactive-generation"} + repository := RepositoryConfig{Project: "project-a", ExplorerID: "default", Management: ManagementRepository, SourceGeneration: "repository-generation"} + if _, err := store.SaveConfig(context.Background(), interactive); err != nil { + t.Fatal(err) + } + if _, err := store.SaveRepositoryConfig(context.Background(), repository); err != nil { + t.Fatal(err) + } + got, err := store.GetRepositoryConfig(context.Background(), "project-a") + if err != nil { + t.Fatal(err) + } + if got.SourceGeneration != repository.SourceGeneration || got.Management != ManagementRepository { + t.Fatalf("repository config = %#v", got) } } diff --git a/internal/server/explorer_v2_engine.go b/internal/server/explorer_v2_engine.go index 97f0859b..b7ed307a 100644 --- a/internal/server/explorer_v2_engine.go +++ b/internal/server/explorer_v2_engine.go @@ -2,6 +2,9 @@ package server import ( "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" "fmt" "strings" @@ -40,16 +43,24 @@ func explorerV2Compiler(recipeEngine *engine.Engine, catalogReader explorerV2Cat } for nodeID, candidateIDs := range request.SelectedCandidateIDsByNode { lookupNodeID := nodeID - if nodeID == "root" && len(bundle.Outputs) > 0 { - lookupNodeID = explorer.OpaqueID("n_", bundle.Outputs[0].RootResourceType) + if nodeID == "root" { + for _, output := range bundle.Outputs { + if output.Name == request.Output { + lookupNodeID = explorer.OpaqueID("n_", output.RootResourceType) + break + } + } } if _, ok := catalogNodeForREST(snapshot.Catalog, lookupNodeID); !ok { return ExplorerV2CompileResult{}, fmt.Errorf("unresolved catalog node %q", nodeID) } for _, candidateID := range candidateIDs { selection, ok := catalogSelectionForREST(snapshot.Catalog, candidateID) - if !ok || selection.NodeID != lookupNodeID { - return ExplorerV2CompileResult{}, fmt.Errorf("unresolved catalog candidate %q for node %q", candidateID, nodeID) + if !ok { + return ExplorerV2CompileResult{}, fmt.Errorf("catalog candidate %q is absent from the current snapshot for node %q", candidateID, nodeID) + } + if selection.NodeID != lookupNodeID { + return ExplorerV2CompileResult{}, fmt.Errorf("catalog candidate %q belongs to node %q, not requested node %q (resolved as %q)", candidateID, selection.NodeID, nodeID, lookupNodeID) } } } @@ -75,8 +86,31 @@ func explorerV2Compiler(recipeEngine *engine.Engine, catalogReader explorerV2Cat if err := synchronizeExplorerV2Views(cfg, resolved.Compiled.Outputs); err != nil { return ExplorerV2CompileResult{}, err } - return ExplorerV2CompileResult{Config: canonical, Bundle: bundle, RecipeDigest: resolved.StoredRecipeDigest, ResolvedSchemaDigest: resolved.ResolvedSchemaDigest, SourceGeneration: resolved.Compiled.SourceGeneration, EmittedColumns: emitted}, nil + return ExplorerV2CompileResult{Config: canonical, Bundle: bundle, RecipeDigest: resolved.StoredRecipeDigest, ResolvedSchemaDigest: resolved.ResolvedSchemaDigest, SourceGeneration: resolved.Compiled.SourceGeneration, OutputFingerprints: resolvedOutputFingerprints(resolved), EmittedColumns: emitted}, nil + } +} + +// resolvedOutputFingerprints are intentionally output-scoped. A bundle-level +// schema digest changes when any output changes, which would defeat reuse of +// the other tables. The lowered physical plan captures catalog resolution, +// discovered columns, filters, and row shape for only this output. +func resolvedOutputFingerprints(resolved engine.Resolved) map[string]string { + result := make(map[string]string, len(resolved.Compiled.Outputs)) + for _, output := range resolved.Compiled.Outputs { + payload, err := json.Marshal(struct { + Version int `json:"version"` + Name string `json:"name"` + Scope string `json:"scope"` + Generation string `json:"generation"` + Output any `json:"output"` + }{Version: 1, Name: output.Name, Scope: resolved.Semantic.ScopeDigest, Generation: resolved.Compiled.SourceGeneration, Output: output}) + if err != nil { + continue + } + sum := sha256.Sum256(payload) + result[output.Name] = hex.EncodeToString(sum[:]) } + return result } // The explorer package intentionally keeps Catalog's internal lookup methods diff --git a/internal/server/explorer_v2_engine_test.go b/internal/server/explorer_v2_engine_test.go index 83009cae..0b6bc7cf 100644 --- a/internal/server/explorer_v2_engine_test.go +++ b/internal/server/explorer_v2_engine_test.go @@ -3,6 +3,8 @@ package server import ( "context" "encoding/json" + "strconv" + "strings" "testing" "github.com/calypr/loom/internal/dataframe/recipe" @@ -73,3 +75,151 @@ func TestExplorerV2CompilerUsesActiveGenerationWithoutSnapshotToken(t *testing.T t.Fatalf("compiler generation = %q, resolver generation = %q; want generation-live", result.SourceGeneration, resolvedGeneration) } } + +func TestExplorerV2CompilerResolvesRootCandidatesForRequestedOutput(t *testing.T) { + firstOutput := testV2Bundle("compiler-test").Outputs[0] + secondOutput := recipe.Output{ + Name: "SubstanceDefinition", + RootResourceType: "SubstanceDefinition", + RowGrain: "substance_definition", + Fields: []recipe.Field{{ + Name: "id", + FieldRef: "SubstanceDefinition.id", + Expr: recipe.Expression{Select: "root.id"}, + }}, + } + bundle := recipe.Bundle{ + RecipeSchemaVersion: recipe.CurrentSchemaVersion, + Name: "compiler-test", + TranslationVersion: "interactive", + Outputs: []recipe.Output{firstOutput, secondOutput}, + } + configV2 := explorer.ConfigV2{ + APIVersion: explorer.ConfigV2APIVersion, + Kind: "ExplorerConfig", + Project: "project-a", + Explorer: explorer.ConfigExplorer{ + ID: "custom", + Title: "Custom", + Management: "interactive", + }, + Views: []explorer.ConfigView{{ + ID: "substance-definition", Title: "Substance definitions", Output: secondOutput.Name, + Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "id", Visible: true}}}, + }}, + } + configV2.Recipe, _ = json.Marshal(bundle) + config, err := json.Marshal(configV2) + if err != nil { + t.Fatal(err) + } + + firstNodeID := explorer.OpaqueID("n_", firstOutput.RootResourceType) + secondNodeID := explorer.OpaqueID("n_", secondOutput.RootResourceType) + secondSelectionID := explorer.OpaqueID("s_", "SubstanceDefinition\x00id") + snapshot, err := explorer.NewCatalogSnapshot( + "project-a", + "generation-live", + "scope", + explorer.Catalog{ + Nodes: []explorer.CatalogNode{ + {ID: firstNodeID, ResourceType: firstOutput.RootResourceType}, + {ID: secondNodeID, ResourceType: secondOutput.RootResourceType}, + }, + Selections: map[string]explorer.CatalogSelection{ + secondSelectionID: { + ID: secondSelectionID, + NodeID: secondNodeID, + }, + }, + }, + true, + false, + nil, + ) + if err != nil { + t.Fatal(err) + } + + compiler := explorerV2Compiler(nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { + return snapshot, nil + }) + _, err = compiler(context.Background(), ExplorerV2CompileRequest{ + Project: "project-a", + ExplorerID: "custom", + Config: config, + SnapshotToken: snapshot.Token, + Output: secondOutput.Name, + SelectedCandidateIDsByNode: map[string][]string{ + "root": {secondSelectionID}, + }, + }) + if err != nil { + t.Fatalf("requested output root candidate was rejected: %v", err) + } +} + +func TestExplorerV2CompilerDistinguishesMissingAndWrongNodeCandidates(t *testing.T) { + bundle := testV2Bundle("compiler-test") + configV2 := explorer.ConfigV2{ + APIVersion: explorer.ConfigV2APIVersion, + Kind: "ExplorerConfig", + Project: "project-a", + Explorer: explorer.ConfigExplorer{ + ID: "custom", Title: "Custom", Management: "interactive", + }, + Views: []explorer.ConfigView{{ + ID: "documents", Title: "Documents", Output: bundle.Outputs[0].Name, + Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "id", Visible: true}}}, + }}, + } + configV2.Recipe, _ = json.Marshal(bundle) + config, err := json.Marshal(configV2) + if err != nil { + t.Fatal(err) + } + + rootNodeID := explorer.OpaqueID("n_", bundle.Outputs[0].RootResourceType) + otherNodeID := explorer.OpaqueID("n_", "SubstanceDefinition") + wrongSelectionID := explorer.OpaqueID("s_", "SubstanceDefinition\x00id") + snapshot, err := explorer.NewCatalogSnapshot( + "project-a", + "generation-live", + "scope", + explorer.Catalog{ + Nodes: []explorer.CatalogNode{ + {ID: rootNodeID, ResourceType: bundle.Outputs[0].RootResourceType}, + {ID: otherNodeID, ResourceType: "SubstanceDefinition"}, + }, + Selections: map[string]explorer.CatalogSelection{ + wrongSelectionID: {ID: wrongSelectionID, NodeID: otherNodeID}, + }, + }, + true, + false, + nil, + ) + if err != nil { + t.Fatal(err) + } + compiler := explorerV2Compiler(nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { + return snapshot, nil + }) + compile := func(candidateID string) error { + _, err := compiler(context.Background(), ExplorerV2CompileRequest{ + Project: "project-a", ExplorerID: "custom", Config: config, + SnapshotToken: snapshot.Token, Output: bundle.Outputs[0].Name, + SelectedCandidateIDsByNode: map[string][]string{"root": {candidateID}}, + }) + return err + } + + missingErr := compile("s_missing") + if missingErr == nil || !strings.Contains(missingErr.Error(), "is absent from the current snapshot") { + t.Fatalf("missing candidate error = %v", missingErr) + } + wrongNodeErr := compile(wrongSelectionID) + if wrongNodeErr == nil || !strings.Contains(wrongNodeErr.Error(), "belongs to node "+strconv.Quote(otherNodeID)) { + t.Fatalf("wrong-node candidate error = %v", wrongNodeErr) + } +} diff --git a/internal/server/explorer_v2_lifecycle.go b/internal/server/explorer_v2_lifecycle.go index 1ffaad4a..97603edf 100644 --- a/internal/server/explorer_v2_lifecycle.go +++ b/internal/server/explorer_v2_lifecycle.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "log/slog" "net/http" "sort" "strings" @@ -37,6 +38,7 @@ type ExplorerV2CompileResult struct { RecipeDigest string ResolvedSchemaDigest string SourceGeneration string + OutputFingerprints map[string]string EmittedColumns []explorer.EmittedColumn Diagnostics []explorer.Diagnostic } @@ -44,6 +46,7 @@ type ExplorerV2CompileResult struct { type ExplorerV2Compiler func(context.Context, ExplorerV2CompileRequest) (ExplorerV2CompileResult, error) type ExplorerV2Previewer func(context.Context, recipe.Bundle, recipe.RuntimeBindings) (map[string][]map[string]any, error) type ExplorerV2Materializer = graphresolver.ExplorerBundleMaterializer +type ExplorerV2GenerationValidator func(context.Context, string, string) error type ExplorerV2ReleaseActivator func(context.Context, string, string, []dataset.DataframeSelector) error // ExplorerV2LifecycleConfig contains explicit capabilities for the REST @@ -54,8 +57,12 @@ type ExplorerV2LifecycleConfig struct { Catalog explorerV2CatalogReader Preview ExplorerV2Previewer Materialize ExplorerV2Materializer - // ActivateRelease makes Publish the sole visibility switch: callers never - // create or save a release as a separate user-facing step. + Logger *slog.Logger + // ValidateReleaseGeneration preflights the immutable snapshot required by + // release activation before Publish performs expensive materialization. + ValidateReleaseGeneration ExplorerV2GenerationValidator + // Publish invokes ActivateRelease when the draft requires outputs that are + // not already present in the active dataset release. ActivateRelease ExplorerV2ReleaseActivator } @@ -264,17 +271,19 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author if err := decodeStrict(c.Body(), &request); err != nil { return explorerV2Error(c, http.StatusBadRequest, "MALFORMED_REQUEST", err.Error()) } - if request.ExpectedDraftVersion == nil { - return explorerV2Error(c, http.StatusBadRequest, "MALFORMED_REQUEST", "expectedDraftVersion is required") - } - if err := verifyExpectedVersion(c.Context(), explorers, project, id, request.ExpectedDraftVersion); err != nil { - return stateErrorResponse(c, err) - } result, digest, err := compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, Config: request.Config, SnapshotToken: request.SnapshotToken, SelectedCandidateIDsByNode: request.SelectedCandidateIDsByNode, Output: request.Output}) if err != nil { return explorerV2Error(c, http.StatusUnprocessableEntity, "COMPILE_FAILED", err.Error()) } - return c.JSON(fiber.Map{"project": project, "explorerId": id, "config": json.RawMessage(result.Config), "draftDigest": digest, "snapshotToken": request.SnapshotToken, "recipeDigest": result.RecipeDigest, "resolvedSchemaDigest": result.ResolvedSchemaDigest, "sourceGeneration": result.SourceGeneration, "emittedColumns": result.EmittedColumns, "diagnostics": result.Diagnostics}) + diagnostics := result.Diagnostics + if diagnostics == nil { + diagnostics = []explorer.Diagnostic{} + } + emittedColumns := result.EmittedColumns + if emittedColumns == nil { + emittedColumns = []explorer.EmittedColumn{} + } + return c.JSON(fiber.Map{"project": project, "explorerId": id, "config": json.RawMessage(result.Config), "draftDigest": digest, "snapshotToken": request.SnapshotToken, "recipeDigest": result.RecipeDigest, "resolvedSchemaDigest": result.ResolvedSchemaDigest, "sourceGeneration": result.SourceGeneration, "emittedColumns": emittedColumns, "diagnostics": diagnostics}) }) app.Post("/api/v1/projects/:project/explorers/:explorerId/preview", func(c fiber.Ctx) error { @@ -297,11 +306,6 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author if request.Limit < 1 || request.Limit > 1000 { return explorerV2Error(c, http.StatusBadRequest, "INVALID_LIMIT", "limit must be between 1 and 1000") } - if request.DraftDigest != "" { - if err := verifyExpectedDigest(c.Context(), explorers, project, id, request.DraftDigest); err != nil { - return stateErrorResponse(c, err) - } - } result, digest, err := compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, Config: request.Config, Output: request.Output}) if err != nil { return previewFailure(c, digest, err) @@ -329,12 +333,24 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author ExpectedDraftVersion *int64 `json:"expectedDraftVersion"` ExpectedDraftDigest string `json:"expectedDraftDigest"` } - if err := decodeStrict(c.Body(), &request); err != nil || request.ExpectedDraftVersion == nil { - if err == nil { - err = fmt.Errorf("expectedDraftVersion is required") - } + if err := decodeStrict(c.Body(), &request); err != nil { return explorerV2Error(c, http.StatusBadRequest, "MALFORMED_REQUEST", err.Error()) } + requestID, _ := c.Locals("request_id").(string) + publishInfo := func(event string, args ...any) { + if capabilities.Logger == nil { + return + } + base := []any{"request_id", requestID, "project", project, "explorer_id", id} + capabilities.Logger.Info(event, append(base, args...)...) + } + publishFailure := func(status int, code, message, phase string, details any) error { + if capabilities.Logger != nil { + capabilities.Logger.Error("Explorer publish failed", "request_id", requestID, "project", project, "explorer_id", id, "phase", phase, "code", code, "details", details) + } + return explorerV2ErrorWithDetails(c, status, code, message, publicExplorerPublishDetails(details)) + } + publishInfo("Explorer publish started") owner, err := explorers.Get(c.Context(), project, id) if errors.Is(err, explorer.ErrNotFound) { return explorerV2Error(c, http.StatusNotFound, "EXPLORER_NOT_FOUND", "Explorer not found") @@ -342,43 +358,113 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author if err != nil { return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error()) } - if owner.DraftVersion != *request.ExpectedDraftVersion || (request.ExpectedDraftDigest != "" && owner.DraftDigest != request.ExpectedDraftDigest) { - return draftConflictResponse(c, explorers, project, id) - } result, digest, err := compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, Config: owner.DraftConfig}) if err != nil { - return explorerV2Error(c, http.StatusUnprocessableEntity, "COMPILE_FAILED", err.Error()) + // A persisted canonical draft should compile. Retry against the + // latest draft once so a concurrent last-write-wins save or a + // transient catalog update does not become a user-facing 422. + if latest, readErr := explorers.Get(c.Context(), project, id); readErr == nil { + owner = latest + result, digest, err = compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, Config: owner.DraftConfig}) + } + if err != nil { + return publishFailure(http.StatusInternalServerError, "PUBLISH_PIPELINE_FAILED", "the current Explorer draft could not be compiled", "COMPILE", fiber.Map{"draftVersion": owner.DraftVersion, "draftDigest": owner.DraftDigest, "cause": err.Error()}) + } } - if capabilities.Materialize == nil { - return explorerV2Error(c, http.StatusServiceUnavailable, "PUBLICATION_UNAVAILABLE", "publication materializer is not configured") + publishInfo("Explorer publish compiled", "recipe_digest", result.RecipeDigest, "resolved_schema_digest", result.ResolvedSchemaDigest, "source_generation", result.SourceGeneration, "output_count", len(result.Bundle.Outputs)) + // Publish is the single user-facing visibility operation. Reuse each + // unchanged output and materialize only outputs whose compiled fingerprint + // is absent or different from the active dataset metadata. + repository, repositoryErr := explorers.RepositoryConfig(c.Context(), project) + var activeRelease activeExplorerDataset + var activeErr error + if repositoryErr != nil || repository == nil { + activeErr = &activeExplorerDatasetError{message: fmt.Sprintf("active repository dataset release is unavailable for project %q", project), details: activeDatasetCompatibility{MissingOutputs: missingDatasetOutputs(result.Bundle, "ACTIVE_RELEASE_UNAVAILABLE")}} + } else { + activeRelease = activeExplorerDatasetFromRepository(*repository) + if activeRelease.Generation == "" { + activeErr = &activeExplorerDatasetError{message: fmt.Sprintf("active repository dataset release for project %q has no generation", project), details: activeDatasetCompatibility{MissingOutputs: missingDatasetOutputs(result.Bundle, "ACTIVE_RELEASE_UNAVAILABLE")}} + } else if state := strings.ToUpper(strings.TrimSpace(activeRelease.Publication.State)); state != "" && state != "ACTIVE" && state != "READY" { + activeErr = &activeExplorerDatasetError{message: fmt.Sprintf("active repository dataset release for project %q is not active", project), details: activeDatasetCompatibility{MissingOutputs: missingDatasetOutputs(result.Bundle, "ACTIVE_RELEASE_UNAVAILABLE")}} + } } - execution, err := capabilities.Materialize(c.Context(), result.Bundle, recipe.RuntimeBindings{Project: project, DatasetGeneration: result.SourceGeneration}) - if err != nil { - _ = insertFailedV2Revision(c.Context(), explorers, owner, result.Config, digest, result.SourceGeneration, subjectFromFiber(c), []explorer.Diagnostic{{Severity: "ERROR", Code: "MATERIALIZATION_FAILED", Message: err.Error(), Retryable: true}}) - return explorerV2Error(c, http.StatusUnprocessableEntity, "MATERIALIZATION_FAILED", err.Error()) + // Compilation, fingerprints, materialization, and release activation must + // all use one generation. Repository metadata describes the prior release + // and is only a reuse candidate; it must never override the generation the + // compiler resolved from the active catalog. + generation := strings.TrimSpace(result.SourceGeneration) + if generation == "" { + return publishFailure(http.StatusServiceUnavailable, "DATASET_BUILD_UNAVAILABLE", "publishing this Explorer requires a dataset generation", "RESOLVE_GENERATION", activeDatasetErrorDetails(activeErr, result.Bundle)) + } + if repositoryErr == nil && repository != nil && strings.TrimSpace(repository.SourceGeneration) != "" && strings.TrimSpace(repository.SourceGeneration) != generation { + publishInfo("Explorer dataset generation advanced", "previous_generation", strings.TrimSpace(repository.SourceGeneration), "generation", generation) + } + changedOutputs := result.Bundle.Outputs + if activeErr == nil { + changedOutputs = outputsNeedingMaterialization(result.Bundle, activeRelease, generation, result.OutputFingerprints) + } + publishInfo("Explorer publish output plan", "generation", generation, "changed_outputs", recipeOutputNames(changedOutputs), "reused_output_count", len(result.Bundle.Outputs)-len(changedOutputs)) + if len(changedOutputs) > 0 { + if capabilities.Materialize == nil || capabilities.ActivateRelease == nil { + return publishFailure(http.StatusServiceUnavailable, "DATASET_BUILD_UNAVAILABLE", "publishing this Explorer requires a dataset build that is not configured", "MATERIALIZE_UNAVAILABLE", activeDatasetErrorDetails(activeErr, result.Bundle)) + } + if capabilities.ValidateReleaseGeneration != nil { + if validateErr := capabilities.ValidateReleaseGeneration(c.Context(), project, generation); validateErr != nil { + status, code, message := explorerReleaseFailure(validateErr, true) + return publishFailure(status, code, message, "VALIDATE_DATASET_RELEASE", fiber.Map{"generation": generation, "cause": validateErr.Error()}) + } + } + var executions []graphresolver.RecipeExecution + for _, output := range changedOutputs { + publishInfo("Explorer output materialization started", "output", output.Name) + execution, materializeErr := capabilities.Materialize(c.Context(), result.Bundle, recipe.RuntimeBindings{Project: project, DatasetGeneration: generation, OutputNames: []string{output.Name}}) + if materializeErr != nil { + return publishFailure(http.StatusServiceUnavailable, "DATASET_BUILD_FAILED", "the dataset could not be built for this Explorer", "MATERIALIZE", fiber.Map{"generation": generation, "output": output.Name, "cause": materializeErr.Error(), "details": activeDatasetErrorDetails(activeErr, result.Bundle)}) + } + if verifyErr := verifyQueryableOutput(output.Name, generation, execution); verifyErr != nil { + return publishFailure(http.StatusServiceUnavailable, "DATASET_BUILD_FAILED", "the dataset build did not produce a queryable Explorer output", "VERIFY_MATERIALIZE", fiber.Map{"generation": generation, "output": output.Name, "cause": verifyErr.Error(), "details": activeDatasetErrorDetails(activeErr, result.Bundle)}) + } + publishInfo("Explorer output materialization complete", "output", output.Name, "execution_id", execution.ID) + executions = append(executions, execution) + } + publishInfo("Explorer dataset release activation started", "outputs", recipeOutputNames(changedOutputs)) + if err := activateExplorerReleaseWithRetry(c.Context(), capabilities.ActivateRelease, project, generation, selectorsForOutputs(changedOutputs, result.Bundle)); err != nil { + status, code, message := explorerReleaseFailure(err, false) + return publishFailure(status, code, message, "ACTIVATE_DATASET_RELEASE", fiber.Map{"generation": generation, "cause": err.Error(), "outputs": recipeOutputNames(changedOutputs)}) + } + publishInfo("Explorer dataset release activation complete", "outputs", recipeOutputNames(changedOutputs)) + resolvedSchemaDigest := result.ResolvedSchemaDigest + if len(executions) > 0 && executions[len(executions)-1].ResolvedSchemaDigest != "" { + resolvedSchemaDigest = executions[len(executions)-1].ResolvedSchemaDigest + } + activeRelease = mergeMaterializedExplorerOutputs(result.Bundle, activeRelease, generation, resolvedSchemaDigest, result.OutputFingerprints, executions) + if repositoryErr == nil && repository != nil { + if err := persistActiveExplorerDataset(c.Context(), explorers, *repository, activeRelease); err != nil { + return publishFailure(http.StatusInternalServerError, "DATASET_METADATA_PERSIST_FAILED", "the dataset was built but its release metadata could not be persisted", "PERSIST_DATASET_METADATA", fiber.Map{"generation": generation, "cause": err.Error()}) + } + publishInfo("Explorer dataset metadata persisted", "outputs", recipeOutputNames(changedOutputs)) + } + } else if activeErr != nil { + return publishFailure(http.StatusServiceUnavailable, "DATASET_BUILD_UNAVAILABLE", "the active dataset release could not be resolved", "RESOLVE_ACTIVE_DATASET", activeDatasetErrorDetails(activeErr, result.Bundle)) } - if err := verifyQueryableOutputs(result.Bundle, execution); err != nil { - _ = insertFailedV2Revision(c.Context(), explorers, owner, result.Config, digest, execution.SourceGeneration, subjectFromFiber(c), []explorer.Diagnostic{{Severity: "ERROR", Code: "OUTPUT_NOT_QUERYABLE", Message: err.Error()}}) - return explorerV2Error(c, http.StatusUnprocessableEntity, "OUTPUT_NOT_QUERYABLE", err.Error()) + materializations, datasetMetadata, err := reuseActiveExplorerDataset(result.Bundle, activeRelease) + if err != nil { + return publishFailure(http.StatusInternalServerError, "DATASET_OUTPUT_UNAVAILABLE", "the active dataset metadata became inconsistent during publish", "REUSE_DATASET_METADATA", fiber.Map{"cause": err.Error()}) } - materializations := executionMaterializations(result.Bundle, execution) compiled := explorer.Compilation{Bundle: result.Bundle, RecipeDigest: result.RecipeDigest, EmittedColumns: result.EmittedColumns} - sourceGeneration := result.SourceGeneration - if sourceGeneration == "" { - sourceGeneration = execution.SourceGeneration - } - revision, err := explorers.InsertReadyRevisionV2(c.Context(), owner, result.Config, digest, compiled, result.ResolvedSchemaDigest, sourceGeneration, subjectFromFiber(c), materializations) + sourceGeneration := activeRelease.Generation + resolvedSchemaDigest := activeRelease.SchemaDigest + if resolvedSchemaDigest == "" { + resolvedSchemaDigest = result.ResolvedSchemaDigest + } + publication := activeRelease.Publication + publication.State = string(explorer.RevisionReady) + publication.Generation = sourceGeneration + revision, err := explorers.InsertReadyRevisionV2WithMetadata(c.Context(), owner, result.Config, digest, compiled, resolvedSchemaDigest, sourceGeneration, subjectFromFiber(c), materializations, datasetMetadata, publication) if err != nil { - return explorerV2Error(c, http.StatusInternalServerError, "REVISION_INSERT_FAILED", err.Error()) - } - if capabilities.ActivateRelease == nil { - _, _ = explorers.FailRevision(c.Context(), revision.ID, []explorer.Diagnostic{{Severity: "ERROR", Code: "RELEASE_ACTIVATION_UNAVAILABLE", Message: "release activation is not configured", Retryable: true}}) - return explorerV2Error(c, http.StatusServiceUnavailable, "RELEASE_ACTIVATION_UNAVAILABLE", "release activation is not configured") - } - if err := capabilities.ActivateRelease(c.Context(), project, sourceGeneration, selectorsForBundle(result.Bundle)); err != nil { - _, _ = explorers.FailRevision(c.Context(), revision.ID, []explorer.Diagnostic{{Severity: "ERROR", Code: "RELEASE_ACTIVATION_FAILED", Message: err.Error(), Retryable: true}}) - return explorerV2Error(c, http.StatusConflict, "RELEASE_ACTIVATION_FAILED", err.Error()) + return publishFailure(http.StatusInternalServerError, "REVISION_INSERT_FAILED", err.Error(), "INSERT_REVISION", fiber.Map{"cause": err.Error()}) } + publishInfo("Explorer revision inserted", "revision_id", revision.ID, "reused_output_count", len(result.Bundle.Outputs)-len(changedOutputs)) var activationErr error if id == "default" { activationErr = explorers.ActivateRepository(c.Context(), project, revision.ID) @@ -386,13 +472,14 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author activationErr = explorers.ActivateInteractive(c.Context(), project, id, revision.ID) } if activationErr != nil { - return explorerV2Error(c, http.StatusConflict, "ACTIVATION_FAILED", activationErr.Error()) + return publishFailure(http.StatusServiceUnavailable, "ACTIVATION_FAILED", "the Explorer revision could not be activated", "ACTIVATE_EXPLORER", fiber.Map{"cause": activationErr.Error()}) } state, err := getExplorerV2State(c.Context(), explorers, project, id) if err != nil { - return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error()) + return publishFailure(http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error(), "READ_PUBLISHED_STATE", fiber.Map{"cause": err.Error()}) } - return c.JSON(fiber.Map{"project": project, "explorerId": id, "publicationId": revision.ID, "activeUrl": state.ActiveURL, "state": state, "materializations": materializations, "diagnostics": result.Diagnostics}) + publishInfo("Explorer publish complete", "revision_id", revision.ID, "reused_output_count", len(result.Bundle.Outputs)-len(changedOutputs)) + return c.JSON(fiber.Map{"project": project, "explorerId": id, "publicationId": revision.ID, "draftVersion": owner.DraftVersion, "draftDigest": owner.DraftDigest, "activeUrl": state.ActiveURL, "state": state, "materializations": materializations, "diagnostics": result.Diagnostics}) }) } @@ -404,6 +491,379 @@ func selectorsForBundle(bundle recipe.Bundle) []dataset.DataframeSelector { return selectors } +func selectorsForOutputs(outputs []recipe.Output, bundle recipe.Bundle) []dataset.DataframeSelector { + selectors := make([]dataset.DataframeSelector, 0, len(outputs)) + for _, output := range outputs { + selectors = append(selectors, dataset.DataframeSelector{Recipe: bundle.Name, TranslationVersion: bundle.TranslationVersion, Output: output.Name}) + } + return selectors +} + +func recipeOutputNames(outputs []recipe.Output) []string { + names := make([]string, 0, len(outputs)) + for _, output := range outputs { + names = append(names, output.Name) + } + return names +} + +func outputsNeedingMaterialization(bundle recipe.Bundle, active activeExplorerDataset, generation string, fingerprints map[string]string) []recipe.Output { + if strings.TrimSpace(active.Generation) == "" || active.Generation != generation { + return append([]recipe.Output(nil), bundle.Outputs...) + } + result := make([]recipe.Output, 0) + for _, output := range bundle.Outputs { + var datasetOutput *explorer.DatasetOutput + for index := range active.Dataset.Outputs { + if active.Dataset.Outputs[index].Name == output.Name { + candidate := active.Dataset.Outputs[index] + datasetOutput = &candidate + break + } + } + var materialization *explorer.Materialization + for index := range active.Materializations { + if active.Materializations[index].Output == output.Name { + candidate := active.Materializations[index] + materialization = &candidate + break + } + } + fingerprint := strings.TrimSpace(fingerprints[output.Name]) + fingerprintRequired := len(fingerprints) > 0 + if datasetOutput == nil || materialization == nil || !datasetOutput.Queryable || + !selectorForOutputIsCanonical(datasetOutput.Selector, output.Name) || + !selectorForOutputIsCanonical(materialization.Selector, output.Name) || + *datasetOutput.Selector != *materialization.Selector || + (fingerprintRequired && (fingerprint == "" || (datasetOutput.Fingerprint != fingerprint && materialization.Fingerprint != fingerprint))) { + result = append(result, output) + } + } + return result +} + +func verifyQueryableOutput(output, generation string, execution graphresolver.RecipeExecution) error { + if strings.TrimSpace(execution.SourceGeneration) != strings.TrimSpace(generation) { + return fmt.Errorf("output %q was materialized for generation %q instead of %q", output, execution.SourceGeneration, generation) + } + executionState := strings.ToUpper(strings.TrimSpace(execution.State)) + if executionState != "PUBLISHED" && executionState != "READY" && executionState != "ACTIVE" { + return fmt.Errorf("output %q execution is not queryable (state %q)", output, execution.State) + } + for _, item := range execution.Outputs { + if item.Name == output { + state := strings.ToUpper(item.State) + if state == "PUBLISHED" || state == "READY" || state == "ACTIVE" { + return nil + } + return fmt.Errorf("output %q is not queryable (state %q)", output, item.State) + } + } + return fmt.Errorf("output %q was not returned by the materializer", output) +} + +func mergeMaterializedExplorerOutputs(bundle recipe.Bundle, active activeExplorerDataset, generation, schemaDigest string, fingerprints map[string]string, executions []graphresolver.RecipeExecution) activeExplorerDataset { + materializations := make(map[string]explorer.Materialization, len(active.Materializations)+len(executions)) + for _, item := range active.Materializations { + materializations[item.Output] = item + } + datasetOutputs := make(map[string]explorer.DatasetOutput, len(active.Dataset.Outputs)+len(executions)) + for _, item := range active.Dataset.Outputs { + datasetOutputs[item.Name] = item + } + lastExecutionID := active.Publication.ExecutionID + for _, execution := range executions { + lastExecutionID = execution.ID + for _, output := range execution.Outputs { + selector := explorerOutputSelector(bundle, output.Name) + fingerprint := fingerprints[output.Name] + materializations[output.Name] = explorer.Materialization{OutputID: output.Name, Output: output.Name, MaterializationID: execution.ID, Fingerprint: fingerprint, Selector: selector, Columns: append([]publication.PhysicalColumn(nil), output.Columns...)} + state := strings.ToUpper(output.State) + datasetOutputs[output.Name] = explorer.DatasetOutput{Name: output.Name, State: state, Queryable: state == "PUBLISHED" || state == "READY" || state == "ACTIVE", Fingerprint: fingerprint, Selector: selector, Columns: append([]publication.PhysicalColumn(nil), output.Columns...)} + } + } + mergedMaterials := make([]explorer.Materialization, 0, len(materializations)) + for _, item := range materializations { + mergedMaterials = append(mergedMaterials, item) + } + sort.Slice(mergedMaterials, func(i, j int) bool { return mergedMaterials[i].Output < mergedMaterials[j].Output }) + mergedOutputs := make([]explorer.DatasetOutput, 0, len(datasetOutputs)) + for _, item := range datasetOutputs { + mergedOutputs = append(mergedOutputs, item) + } + sort.Slice(mergedOutputs, func(i, j int) bool { return mergedOutputs[i].Name < mergedOutputs[j].Name }) + return activeExplorerDataset{ + Generation: generation, SchemaDigest: schemaDigest, + Materializations: mergedMaterials, + Dataset: explorer.DatasetMetadata{Generation: generation, SchemaDigest: schemaDigest, Outputs: mergedOutputs}, + Publication: explorer.PublicationMetadata{State: string(explorer.RevisionReady), Generation: generation, ExecutionID: lastExecutionID, UpdatedAt: time.Now().UTC()}, + } +} + +func activateExplorerReleaseWithRetry(ctx context.Context, activate ExplorerV2ReleaseActivator, project, generation string, selectors []dataset.DataframeSelector) error { + err := activate(ctx, project, generation, selectors) + if err != nil && errors.Is(err, dataset.ErrReleaseActivationConflict) { + return activate(ctx, project, generation, selectors) + } + return err +} + +func explorerReleaseFailure(err error, preflight bool) (int, string, string) { + switch { + case errors.Is(err, dataset.ErrSnapshotNotFound): + return http.StatusServiceUnavailable, "DATASET_GENERATION_UNAVAILABLE", "the active dataset generation is not ready for publishing" + case errors.Is(err, dataset.ErrReleaseRequirementsUnmet): + return http.StatusServiceUnavailable, "DATASET_GENERATION_NOT_READY", "the active dataset generation is still being prepared" + case errors.Is(err, dataset.ErrReleaseActivationConflict): + return http.StatusConflict, "DATASET_RELEASE_CONFLICT", "the active dataset changed while publishing; retry publish" + default: + if preflight { + return http.StatusServiceUnavailable, "DATASET_GENERATION_UNAVAILABLE", "the active dataset generation could not be validated" + } + return http.StatusServiceUnavailable, "DATASET_RELEASE_ACTIVATION_FAILED", "the dataset was built but could not be activated" + } +} + +type activeExplorerDataset struct { + Generation string + SchemaDigest string + Materializations []explorer.Materialization + Dataset explorer.DatasetMetadata + Publication explorer.PublicationMetadata +} + +type activeDatasetOutputDiagnostic struct { + Output string `json:"output"` + Path string `json:"path"` + Reason string `json:"reason"` +} + +type activeDatasetCompatibility struct { + Ready bool `json:"ready"` + ActiveGeneration string `json:"activeGeneration,omitempty"` + MissingOutputs []activeDatasetOutputDiagnostic `json:"missingOutputs,omitempty"` + AvailableOutputs []string `json:"availableOutputs,omitempty"` +} + +type activeExplorerDatasetError struct { + message string + details activeDatasetCompatibility +} + +func (e *activeExplorerDatasetError) Error() string { return e.message } + +func activeDatasetErrorDetails(err error, bundle recipe.Bundle) activeDatasetCompatibility { + var datasetErr *activeExplorerDatasetError + if errors.As(err, &datasetErr) { + return datasetErr.details + } + return activeDatasetCompatibility{MissingOutputs: missingDatasetOutputs(bundle, "ACTIVE_RELEASE_UNAVAILABLE")} +} + +func missingDatasetOutputs(bundle recipe.Bundle, reason string) []activeDatasetOutputDiagnostic { + missing := make([]activeDatasetOutputDiagnostic, 0, len(bundle.Outputs)) + for index, output := range bundle.Outputs { + missing = append(missing, activeDatasetOutputDiagnostic{Output: output.Name, Path: fmt.Sprintf("recipe.outputs[%d]", index), Reason: reason}) + } + return missing +} + +// resolveActiveExplorerDataset reads the canonical repository release record. +// Explorer revisions are configuration pointers, not dataset-release records; +// they are never used as a compatibility fallback here. +func resolveActiveExplorerDataset(ctx context.Context, service *explorer.Service, project string, bundle recipe.Bundle) (activeExplorerDataset, error) { + repository, err := service.RepositoryConfig(ctx, project) + if err != nil || repository == nil { + return activeExplorerDataset{}, &activeExplorerDatasetError{ + message: fmt.Sprintf("active repository dataset release is unavailable for project %q", project), + details: activeDatasetCompatibility{MissingOutputs: missingDatasetOutputs(bundle, "ACTIVE_RELEASE_UNAVAILABLE")}, + } + } + candidate := activeExplorerDatasetFromRepository(*repository) + if candidate.Generation == "" { + return activeExplorerDataset{}, &activeExplorerDatasetError{ + message: fmt.Sprintf("active repository dataset release for project %q has no generation", project), + details: activeDatasetCompatibility{MissingOutputs: missingDatasetOutputs(bundle, "ACTIVE_RELEASE_UNAVAILABLE")}, + } + } + compatibility := inspectActiveExplorerDataset(candidate, bundle) + if !compatibility.Ready { + return activeExplorerDataset{}, &activeExplorerDatasetError{ + message: fmt.Sprintf("active repository dataset release for project %q does not contain complete metadata for the requested Explorer outputs", project), + details: compatibility, + } + } + return candidate, nil +} + +func activeExplorerDatasetFromRepository(value explorer.RepositoryConfig) activeExplorerDataset { + return activeExplorerDataset{Generation: strings.TrimSpace(value.SourceGeneration), SchemaDigest: value.Dataset.SchemaDigest, Materializations: append([]explorer.Materialization(nil), value.Materializations...), Dataset: value.Dataset, Publication: value.Publication} +} + +func activeExplorerDatasetSupports(value activeExplorerDataset, bundle recipe.Bundle) bool { + return inspectActiveExplorerDataset(value, bundle).Ready +} + +func inspectActiveExplorerDataset(value activeExplorerDataset, bundle recipe.Bundle) activeDatasetCompatibility { + compatibility := activeDatasetCompatibility{Ready: true, ActiveGeneration: value.Generation} + for _, item := range value.Dataset.Outputs { + if item.Name != "" { + compatibility.AvailableOutputs = append(compatibility.AvailableOutputs, item.Name) + } + } + sort.Strings(compatibility.AvailableOutputs) + for index, output := range bundle.Outputs { + diagnostic := activeDatasetOutputDiagnostic{Output: output.Name, Path: fmt.Sprintf("recipe.outputs[%d]", index)} + var datasetOutput *explorer.DatasetOutput + for itemIndex := range value.Dataset.Outputs { + if value.Dataset.Outputs[itemIndex].Name == output.Name { + candidate := value.Dataset.Outputs[itemIndex] + datasetOutput = &candidate + break + } + } + if datasetOutput == nil { + diagnostic.Reason = "MISSING_DATASET_OUTPUT" + } else if !datasetOutput.Queryable && !isQueryableDatasetState(datasetOutput.State) { + diagnostic.Reason = "OUTPUT_NOT_QUERYABLE" + } else if !selectorForOutputIsCanonical(datasetOutput.Selector, output.Name) { + diagnostic.Reason = "MISSING_DATASET_SELECTOR" + } else { + var materialization *explorer.Materialization + for itemIndex := range value.Materializations { + if value.Materializations[itemIndex].Output == output.Name { + candidate := value.Materializations[itemIndex] + materialization = &candidate + break + } + } + if materialization == nil || materialization.MaterializationID == "" { + diagnostic.Reason = "MISSING_MATERIALIZATION" + } else if !selectorForOutputIsCanonical(materialization.Selector, output.Name) { + diagnostic.Reason = "MISSING_MATERIALIZATION_SELECTOR" + } else if *datasetOutput.Selector != *materialization.Selector { + diagnostic.Reason = "SELECTOR_MISMATCH" + } + } + if diagnostic.Reason != "" { + compatibility.Ready = false + compatibility.MissingOutputs = append(compatibility.MissingOutputs, diagnostic) + } + } + return compatibility +} + +func persistActiveExplorerDataset(ctx context.Context, service *explorer.Service, repository explorer.RepositoryConfig, active activeExplorerDataset) error { + materializations := mergeExplorerMaterializations(repository.Materializations, active.Materializations) + dataset := mergeExplorerDataset(repository.Dataset, active.Dataset, active.Generation, active.SchemaDigest) + repository.SourceGeneration = active.Generation + repository.Materializations = materializations + repository.Dataset = dataset + repository.Publication = active.Publication + if repository.ExecutionID == "" { + repository.ExecutionID = active.Publication.ExecutionID + } + _, err := service.SaveRepositoryConfig(ctx, repository) + return err +} + +func mergeExplorerMaterializations(existing, updates []explorer.Materialization) []explorer.Materialization { + byOutput := make(map[string]explorer.Materialization, len(existing)+len(updates)) + for _, value := range existing { + byOutput[value.Output] = value + } + for _, value := range updates { + byOutput[value.Output] = value + } + result := make([]explorer.Materialization, 0, len(byOutput)) + for _, value := range byOutput { + result = append(result, value) + } + sort.Slice(result, func(i, j int) bool { return result[i].Output < result[j].Output }) + return result +} + +func mergeExplorerDataset(existing, updates explorer.DatasetMetadata, generation, schemaDigest string) explorer.DatasetMetadata { + byOutput := make(map[string]explorer.DatasetOutput, len(existing.Outputs)+len(updates.Outputs)) + for _, value := range existing.Outputs { + byOutput[value.Name] = value + } + for _, value := range updates.Outputs { + byOutput[value.Name] = value + } + outputs := make([]explorer.DatasetOutput, 0, len(byOutput)) + for _, value := range byOutput { + outputs = append(outputs, value) + } + sort.Slice(outputs, func(i, j int) bool { return outputs[i].Name < outputs[j].Name }) + if generation == "" { + generation = existing.Generation + } + if schemaDigest == "" { + schemaDigest = existing.SchemaDigest + } + return explorer.DatasetMetadata{Generation: generation, SchemaDigest: schemaDigest, Outputs: outputs} +} + +func reuseActiveExplorerDataset(bundle recipe.Bundle, value activeExplorerDataset) ([]explorer.Materialization, explorer.DatasetMetadata, error) { + materializations := make([]explorer.Materialization, 0, len(bundle.Outputs)) + outputs := make([]explorer.DatasetOutput, 0, len(bundle.Outputs)) + for _, output := range bundle.Outputs { + var materialization *explorer.Materialization + for index := range value.Materializations { + if value.Materializations[index].Output == output.Name { + candidate := value.Materializations[index] + materialization = &candidate + break + } + } + var datasetOutput *explorer.DatasetOutput + for index := range value.Dataset.Outputs { + if value.Dataset.Outputs[index].Name == output.Name { + candidate := value.Dataset.Outputs[index] + datasetOutput = &candidate + break + } + } + if datasetOutput == nil || (!datasetOutput.Queryable && !isQueryableDatasetState(datasetOutput.State)) { + return nil, explorer.DatasetMetadata{}, fmt.Errorf("output %q is not queryable in the active dataset release", output.Name) + } + if materialization == nil || materialization.MaterializationID == "" || !selectorForOutputIsCanonical(materialization.Selector, output.Name) { + return nil, explorer.DatasetMetadata{}, fmt.Errorf("output %q has incomplete active dataframe materialization", output.Name) + } + if !selectorForOutputIsCanonical(datasetOutput.Selector, output.Name) { + return nil, explorer.DatasetMetadata{}, fmt.Errorf("output %q has no active dataframe selector", output.Name) + } + if *datasetOutput.Selector != *materialization.Selector { + return nil, explorer.DatasetMetadata{}, fmt.Errorf("output %q has mismatched active dataframe selectors", output.Name) + } + materialization.OutputID = output.Name + materialization.Output = output.Name + if len(materialization.Columns) == 0 { + materialization.Columns = append([]publication.PhysicalColumn(nil), datasetOutput.Columns...) + } + materializations = append(materializations, *materialization) + datasetOutput.Name = output.Name + datasetOutput.Columns = append([]publication.PhysicalColumn(nil), materialization.Columns...) + outputs = append(outputs, *datasetOutput) + } + dataset := explorer.DatasetMetadata{Generation: value.Generation, SchemaDigest: value.SchemaDigest, Outputs: outputs} + return materializations, dataset, nil +} + +func selectorForOutputIsCanonical(selector *dataset.DataframeSelector, output string) bool { + return selector != nil && selector.Valid() && selector.Output == output +} + +func isQueryableDatasetState(state string) bool { + switch strings.ToUpper(strings.TrimSpace(state)) { + case "PUBLISHED", "READY", "ACTIVE": + return true + default: + return false + } +} + func decodeStrict(raw []byte, value any) error { decoder := json.NewDecoder(strings.NewReader(string(raw))) decoder.DisallowUnknownFields() @@ -439,6 +899,35 @@ func explorerV2Error(c fiber.Ctx, status int, code, message string) error { return c.Status(status).JSON(fiber.Map{"error": fiber.Map{"code": code, "message": message}}) } +func explorerV2ErrorWithDetails(c fiber.Ctx, status int, code, message string, details any) error { + body := fiber.Map{"code": code, "message": message, "details": details} + if status == http.StatusServiceUnavailable || status == http.StatusConflict { + body["retryable"] = true + } + if requestID, _ := c.Locals("request_id").(string); requestID != "" { + body["requestId"] = requestID + } + return c.Status(status).JSON(fiber.Map{"error": body}) +} + +// publicExplorerPublishDetails keeps operational causes in structured logs +// while returning only stable, actionable fields to the Builder. In +// particular, raw AQL, SQL, and storage errors must not become UI copy. +func publicExplorerPublishDetails(details any) any { + values, ok := details.(fiber.Map) + if !ok { + return details + } + public := make(fiber.Map, len(values)) + for key, value := range values { + if key == "cause" || key == "retryable" { + continue + } + public[key] = value + } + return public +} + func draftConflictResponse(c fiber.Ctx, explorers *explorer.Service, project, id string) error { current, err := explorers.Get(c.Context(), project, id) if err != nil { diff --git a/internal/server/explorer_v2_lifecycle_test.go b/internal/server/explorer_v2_lifecycle_test.go index d273228a..b42b14d1 100644 --- a/internal/server/explorer_v2_lifecycle_test.go +++ b/internal/server/explorer_v2_lifecycle_test.go @@ -13,6 +13,7 @@ import ( graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/dataframe/publication" "github.com/calypr/loom/internal/dataframe/recipe" "github.com/calypr/loom/internal/dataset" "github.com/calypr/loom/internal/explorer" @@ -36,7 +37,9 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { if err != nil { t.Fatal(err) } - if _, err := service.SaveRepositoryConfig(context.Background(), explorer.RepositoryConfig{Project: "project-a", Config: repository, SourceGeneration: "generation-a"}); err != nil { + repositorySelector := dataset.DataframeSelector{Recipe: "repository", TranslationVersion: "interactive", Output: "DocumentReference"} + repositoryMaterialization := explorer.Materialization{OutputID: "DocumentReference", Output: "DocumentReference", MaterializationID: "execution-a", Selector: &repositorySelector, Columns: []publication.PhysicalColumn{{Name: "id", LogicalType: "String"}}} + if _, err := service.SaveRepositoryConfig(context.Background(), explorer.RepositoryConfig{Project: "project-a", Config: repository, SourceGeneration: "generation-a", ExecutionID: "execution-a", Materializations: []explorer.Materialization{repositoryMaterialization}, Dataset: explorer.DatasetMetadata{Generation: "generation-a", Outputs: []explorer.DatasetOutput{{Name: "DocumentReference", State: "PUBLISHED", Queryable: true, Selector: &repositorySelector, Columns: repositoryMaterialization.Columns}}}, Publication: explorer.PublicationMetadata{State: "ACTIVE", Generation: "generation-a", ExecutionID: "execution-a"}}); err != nil { t.Fatal(err) } repositoryBundle := testV2Bundle("repository") @@ -146,8 +149,8 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { if defaultPublished.StatusCode != http.StatusOK || !strings.Contains(defaultPublished.Body, `"publicationId"`) { t.Fatalf("default publish status=%d body=%s", defaultPublished.StatusCode, defaultPublished.Body) } - if len(releaseActivations) != 1 || len(releaseActivations[0]) != 1 || releaseActivations[0][0].Output != "DocumentReference" { - t.Fatalf("default release activations = %#v", releaseActivations) + if len(releaseActivations) != 0 { + t.Fatalf("configuration publish unexpectedly activated a dataset release: %#v", releaseActivations) } defaultAfterPublish := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/default", "") var activeDefaultState explorerV2State @@ -155,7 +158,6 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { if defaultAfterPublish.StatusCode != http.StatusOK || activeDefaultState.ActiveRevisionID == "" || string(activeDefaultState.ActiveConfig) != string(activeDefaultState.DraftConfig) { t.Fatalf("default active state=%#v", activeDefaultState) } - var draft map[string]any if err := json.Unmarshal(created.DraftConfig, &draft); err != nil { t.Fatal(err) @@ -177,13 +179,13 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { t.Fatalf("saved state=%#v", updated) } stale := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/custom-explorer/draft", string(draftRequest)) - if stale.StatusCode != http.StatusConflict || !strings.Contains(stale.Body, `"code":"DRAFT_CONFLICT"`) || !strings.Contains(stale.Body, `"currentVersion":2`) { - t.Fatalf("stale status=%d body=%s", stale.StatusCode, stale.Body) + if stale.StatusCode != http.StatusOK || !strings.Contains(stale.Body, `"draftVersion":3`) { + t.Fatalf("last-write-wins status=%d body=%s", stale.StatusCode, stale.Body) } compileRequest, _ := json.Marshal(map[string]any{"output": "DocumentReference", "config": json.RawMessage(updated.DraftConfig), "expectedDraftVersion": updated.DraftVersion}) compiled := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom-explorer/authoring/compile", string(compileRequest)) - if compiled.StatusCode != http.StatusOK || !strings.Contains(compiled.Body, `"recipeDigest"`) { + if compiled.StatusCode != http.StatusOK || !strings.Contains(compiled.Body, `"recipeDigest"`) || !strings.Contains(compiled.Body, `"diagnostics":[]`) { t.Fatalf("compile status=%d body=%s", compiled.StatusCode, compiled.Body) } @@ -202,8 +204,8 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { if published.StatusCode != http.StatusOK || !strings.Contains(published.Body, `"publicationId"`) || !strings.Contains(published.Body, `"activeUrl"`) { t.Fatalf("publish status=%d body=%s", published.StatusCode, published.Body) } - if len(releaseActivations) != 2 || len(releaseActivations[1]) != 1 || releaseActivations[1][0].Recipe != bundle.Name { - t.Fatalf("custom release activations = %#v", releaseActivations) + if len(releaseActivations) != 0 { + t.Fatalf("custom configuration publish unexpectedly activated a dataset release: %#v", releaseActivations) } stateResponse := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom-explorer", "") var active explorerV2State @@ -211,6 +213,9 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { if stateResponse.StatusCode != http.StatusOK || active.ActiveRevisionID == "" || string(active.ActiveConfig) != string(active.DraftConfig) { t.Fatalf("active state=%#v", active) } + if len(active.Materializations) != 1 || active.Materializations[0].Selector == nil || active.Materializations[0].Selector.Recipe != "repository" { + t.Fatalf("configuration publish did not reuse the active dataset selector: %#v", active.Materializations) + } priorActiveRevision := active.ActiveRevisionID releaseFails = true draftExplorer["title"] = "Failed release draft" @@ -223,14 +228,14 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { var failedReleaseState explorerV2State decodeBody(t, failedReleaseDraft.Body, &failedReleaseState) failedReleasePublish := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom-explorer/publish", `{"expectedDraftVersion":`+fmt.Sprint(failedReleaseState.DraftVersion)+`,"expectedDraftDigest":"`+failedReleaseState.DraftDigest+`"}`) - if failedReleasePublish.StatusCode != http.StatusConflict || !strings.Contains(failedReleasePublish.Body, `"code":"RELEASE_ACTIVATION_FAILED"`) { - t.Fatalf("failed release publish status=%d body=%s", failedReleasePublish.StatusCode, failedReleasePublish.Body) + if failedReleasePublish.StatusCode != http.StatusOK { + t.Fatalf("configuration publish should not depend on release activation status=%d body=%s", failedReleasePublish.StatusCode, failedReleasePublish.Body) } unchangedAfterReleaseFailure := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom-explorer", "") var releaseUnchanged explorerV2State decodeBody(t, unchangedAfterReleaseFailure.Body, &releaseUnchanged) - if releaseUnchanged.ActiveRevisionID != priorActiveRevision || string(releaseUnchanged.ActiveConfig) == string(releaseUnchanged.DraftConfig) { - t.Fatalf("failed release activation changed active state: %#v", releaseUnchanged) + if releaseUnchanged.ActiveRevisionID == priorActiveRevision || string(releaseUnchanged.ActiveConfig) != string(releaseUnchanged.DraftConfig) { + t.Fatalf("configuration publish did not activate independently of release state: %#v", releaseUnchanged) } releaseFails = false @@ -245,14 +250,244 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { var failedDraftState explorerV2State decodeBody(t, failedDraft.Body, &failedDraftState) failedPublish := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom-explorer/publish", `{"expectedDraftVersion":`+fmt.Sprint(failedDraftState.DraftVersion)+`,"expectedDraftDigest":"`+failedDraftState.DraftDigest+`"}`) - if failedPublish.StatusCode != http.StatusUnprocessableEntity { - t.Fatalf("failed publish status=%d body=%s", failedPublish.StatusCode, failedPublish.Body) + if failedPublish.StatusCode != http.StatusOK { + t.Fatalf("configuration publish should not call materialization status=%d body=%s", failedPublish.StatusCode, failedPublish.Body) } unchangedResponse := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom-explorer", "") var unchanged explorerV2State decodeBody(t, unchangedResponse.Body, &unchanged) - if unchanged.ActiveRevisionID != priorActiveRevision || string(unchanged.ActiveConfig) == string(unchanged.DraftConfig) { - t.Fatalf("failed publication changed active state: %#v", unchanged) + if unchanged.ActiveRevisionID == releaseUnchanged.ActiveRevisionID || string(unchanged.ActiveConfig) != string(unchanged.DraftConfig) { + t.Fatalf("materializer availability affected configuration activation: %#v", unchanged) + } +} + +func TestActiveExplorerDatasetRequiresCanonicalReleaseMetadata(t *testing.T) { + bundle := testV2Bundle("explorer-custom") + candidate := activeExplorerDataset{ + Generation: "generation-a", + Dataset: explorer.DatasetMetadata{Outputs: []explorer.DatasetOutput{{Name: "DocumentReference", State: "PUBLISHED", Queryable: true}}}, + Materializations: []explorer.Materialization{{Output: "DocumentReference", MaterializationID: "execution-a"}}, + } + if activeExplorerDatasetSupports(candidate, bundle) { + t.Fatal("incomplete release metadata was accepted without canonical selectors") + } +} + +func TestOutputsNeedingMaterializationReusesUnchangedOutputs(t *testing.T) { + bundle := recipe.Bundle{Outputs: []recipe.Output{{Name: "Patient"}, {Name: "Specimen"}}} + patientSelector := dataset.DataframeSelector{Recipe: "explorer", TranslationVersion: "v1", Output: "Patient"} + specimenSelector := dataset.DataframeSelector{Recipe: "explorer", TranslationVersion: "v1", Output: "Specimen"} + active := activeExplorerDataset{ + Generation: "generation-a", + Dataset: explorer.DatasetMetadata{Generation: "generation-a", Outputs: []explorer.DatasetOutput{ + {Name: "Patient", State: "PUBLISHED", Queryable: true, Fingerprint: "patient-v1", Selector: &patientSelector}, + {Name: "Specimen", State: "PUBLISHED", Queryable: true, Fingerprint: "specimen-v1", Selector: &specimenSelector}, + }}, + Materializations: []explorer.Materialization{ + {Output: "Patient", MaterializationID: "execution-patient", Fingerprint: "patient-v1", Selector: &patientSelector}, + {Output: "Specimen", MaterializationID: "execution-specimen", Fingerprint: "specimen-v1", Selector: &specimenSelector}, + }, + } + changed := outputsNeedingMaterialization(bundle, active, "generation-a", map[string]string{"Patient": "patient-v1", "Specimen": "specimen-v2"}) + if len(changed) != 1 || changed[0].Name != "Specimen" { + t.Fatalf("changed outputs = %#v, want only Specimen", changed) + } +} + +func TestPublishBuildsMissingDatasetOutput(t *testing.T) { + store := explorer.NewMemoryStore() + service, err := explorer.NewService(store) + if err != nil { + t.Fatal(err) + } + repository := baselineExplorerConfigV2("project-a", "Default") + repositorySelector := dataset.DataframeSelector{Recipe: "repository", TranslationVersion: "interactive", Output: "DocumentReference"} + repositoryMaterialization := explorer.Materialization{OutputID: "DocumentReference", Output: "DocumentReference", MaterializationID: "execution-a", Selector: &repositorySelector, Columns: []publication.PhysicalColumn{{Name: "id", LogicalType: "String"}}} + if _, err := service.SaveRepositoryConfig(context.Background(), explorer.RepositoryConfig{ + Project: "project-a", Config: repository, SourceGeneration: "generation-a", ExecutionID: "execution-a", + Materializations: []explorer.Materialization{repositoryMaterialization}, + Dataset: explorer.DatasetMetadata{Generation: "generation-a", Outputs: []explorer.DatasetOutput{{Name: "DocumentReference", State: "PUBLISHED", Queryable: true, Selector: &repositorySelector, Columns: repositoryMaterialization.Columns}}}, + Publication: explorer.PublicationMetadata{State: "ACTIVE", Generation: "generation-a", ExecutionID: "execution-a"}, + }); err != nil { + t.Fatal(err) + } + missingBundle := testV2Bundle("explorer-custom") + missingBundle.Outputs[0].Name = "SubstanceDefinition" + missingBundle.Outputs[0].RootResourceType = "SubstanceDefinition" + missingBundle.Outputs[0].RowGrain = "substance_definition" + compile := func(_ context.Context, request ExplorerV2CompileRequest) (ExplorerV2CompileResult, error) { + digest, _ := missingBundle.Digest() + return ExplorerV2CompileResult{Config: request.Config, Bundle: missingBundle, RecipeDigest: digest, SourceGeneration: "generation-a", ResolvedSchemaDigest: "schema-a"}, nil + } + materializeCalls := 0 + var materializedOutputNames [][]string + materialize := func(_ context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { + materializeCalls++ + materializedOutputNames = append(materializedOutputNames, append([]string(nil), bindings.OutputNames...)) + outputs := make([]graphresolver.RecipeExecutionOutput, 0, len(bundle.Outputs)) + for _, output := range bundle.Outputs { + outputs = append(outputs, graphresolver.RecipeExecutionOutput{Name: output.Name, State: "PUBLISHED", Columns: []publication.PhysicalColumn{{Name: "id", LogicalType: "String"}}}) + } + return graphresolver.RecipeExecution{ID: "execution-substance", SourceGeneration: "generation-a", ResolvedSchemaDigest: "schema-substance", State: "PUBLISHED", Outputs: outputs}, nil + } + var releaseActivations [][]dataset.DataframeSelector + activateRelease := func(_ context.Context, project, generation string, selectors []dataset.DataframeSelector) error { + if project != "project-a" || generation != "generation-a" { + t.Fatalf("release identity = %s/%s", project, generation) + } + releaseActivations = append(releaseActivations, append([]dataset.DataframeSelector(nil), selectors...)) + return nil + } + app := fiber.New() + RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{Compile: compile, Materialize: materialize, ActivateRelease: activateRelease}) + created := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers", `{"name":"Needs Load","blank":true}`) + if created.StatusCode != http.StatusCreated { + t.Fatalf("create status=%d body=%s", created.StatusCode, created.Body) + } + published := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/needs-load/publish", `{}`) + if published.StatusCode != http.StatusOK || !strings.Contains(published.Body, `"publicationId"`) { + t.Fatalf("publish status=%d body=%s", published.StatusCode, published.Body) + } + if materializeCalls != 1 || len(releaseActivations) != 1 || len(releaseActivations[0]) != 1 || releaseActivations[0][0].Output != "SubstanceDefinition" { + t.Fatalf("build lifecycle calls=%d releases=%#v", materializeCalls, releaseActivations) + } + if len(materializedOutputNames) != 1 || len(materializedOutputNames[0]) != 1 || materializedOutputNames[0][0] != "SubstanceDefinition" { + t.Fatalf("materialized output selection = %#v", materializedOutputNames) + } + active, err := service.ActiveRevision(context.Background(), "project-a", "needs-load") + if err != nil { + t.Fatal(err) + } + if len(active.Materializations) != 1 || active.Materializations[0].Output != "SubstanceDefinition" || active.Materializations[0].Selector == nil { + t.Fatalf("active materializations=%#v", active.Materializations) + } + updatedRepository, err := service.RepositoryConfig(context.Background(), "project-a") + if err != nil { + t.Fatal(err) + } + if len(updatedRepository.Dataset.Outputs) != 2 || len(updatedRepository.Materializations) != 2 { + t.Fatalf("merged repository dataset=%#v materializations=%#v", updatedRepository.Dataset, updatedRepository.Materializations) + } +} + +func TestPublishUsesCompiledGenerationInsteadOfStaleRepositoryGeneration(t *testing.T) { + store := explorer.NewMemoryStore() + service, err := explorer.NewService(store) + if err != nil { + t.Fatal(err) + } + repository := baselineExplorerConfigV2("project-a", "Default") + oldSelector := dataset.DataframeSelector{Recipe: "repository", TranslationVersion: "interactive", Output: "DocumentReference"} + oldMaterialization := explorer.Materialization{OutputID: "DocumentReference", Output: "DocumentReference", MaterializationID: "execution-old", Selector: &oldSelector} + if _, err := service.SaveRepositoryConfig(context.Background(), explorer.RepositoryConfig{ + Project: "project-a", Config: repository, SourceGeneration: "generation-old", ExecutionID: "execution-old", + Materializations: []explorer.Materialization{oldMaterialization}, + Dataset: explorer.DatasetMetadata{Generation: "generation-old", Outputs: []explorer.DatasetOutput{{Name: "DocumentReference", State: "PUBLISHED", Queryable: true, Selector: &oldSelector}}}, + Publication: explorer.PublicationMetadata{State: "ACTIVE", Generation: "generation-old", ExecutionID: "execution-old"}, + }); err != nil { + t.Fatal(err) + } + bundle := testV2Bundle("explorer-custom") + compile := func(_ context.Context, request ExplorerV2CompileRequest) (ExplorerV2CompileResult, error) { + digest, _ := bundle.Digest() + return ExplorerV2CompileResult{Config: request.Config, Bundle: bundle, RecipeDigest: digest, SourceGeneration: "generation-new", ResolvedSchemaDigest: "schema-new", OutputFingerprints: map[string]string{"DocumentReference": "fingerprint-new"}}, nil + } + validatedGeneration := "" + validateGeneration := func(_ context.Context, project, generation string) error { + if project != "project-a" { + t.Fatalf("validated project = %q", project) + } + validatedGeneration = generation + return nil + } + materializedGeneration := "" + materialize := func(_ context.Context, _ recipe.Bundle, bindings recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { + materializedGeneration = bindings.DatasetGeneration + return graphresolver.RecipeExecution{ID: "execution-new", SourceGeneration: bindings.DatasetGeneration, ResolvedSchemaDigest: "schema-new", State: "PUBLISHED", Outputs: []graphresolver.RecipeExecutionOutput{{Name: "DocumentReference", State: "PUBLISHED"}}}, nil + } + activatedGeneration := "" + activateRelease := func(_ context.Context, project, generation string, _ []dataset.DataframeSelector) error { + if project != "project-a" { + t.Fatalf("activated project = %q", project) + } + activatedGeneration = generation + return nil + } + app := fiber.New() + RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{ + Compile: compile, Materialize: materialize, ValidateReleaseGeneration: validateGeneration, ActivateRelease: activateRelease, + }) + created := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers", `{"name":"Current Generation","blank":true}`) + if created.StatusCode != http.StatusCreated { + t.Fatalf("create status=%d body=%s", created.StatusCode, created.Body) + } + published := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/current-generation/publish", `{}`) + if published.StatusCode != http.StatusOK { + t.Fatalf("publish status=%d body=%s", published.StatusCode, published.Body) + } + if validatedGeneration != "generation-new" || materializedGeneration != "generation-new" || activatedGeneration != "generation-new" { + t.Fatalf("publish generations validate=%q materialize=%q activate=%q", validatedGeneration, materializedGeneration, activatedGeneration) + } + updated, err := service.RepositoryConfig(context.Background(), "project-a") + if err != nil { + t.Fatal(err) + } + if updated.SourceGeneration != "generation-new" || updated.Dataset.Generation != "generation-new" || updated.Publication.Generation != "generation-new" { + t.Fatalf("updated repository generation = %#v", updated) + } +} + +func TestPublishPreflightsGenerationBeforeMaterialization(t *testing.T) { + store := explorer.NewMemoryStore() + service, err := explorer.NewService(store) + if err != nil { + t.Fatal(err) + } + bundle := testV2Bundle("explorer-custom") + compile := func(_ context.Context, request ExplorerV2CompileRequest) (ExplorerV2CompileResult, error) { + digest, _ := bundle.Digest() + return ExplorerV2CompileResult{Config: request.Config, Bundle: bundle, RecipeDigest: digest, SourceGeneration: "generation-missing"}, nil + } + materializeCalls := 0 + materialize := func(context.Context, recipe.Bundle, recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { + materializeCalls++ + return graphresolver.RecipeExecution{}, nil + } + app := fiber.New() + RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{ + Compile: compile, Materialize: materialize, + ValidateReleaseGeneration: func(context.Context, string, string) error { return dataset.ErrSnapshotNotFound }, + ActivateRelease: func(context.Context, string, string, []dataset.DataframeSelector) error { return nil }, + }) + created := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers", `{"name":"Missing Generation","blank":true}`) + if created.StatusCode != http.StatusCreated { + t.Fatalf("create status=%d body=%s", created.StatusCode, created.Body) + } + published := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/missing-generation/publish", `{}`) + if published.StatusCode != http.StatusServiceUnavailable || !strings.Contains(published.Body, `"code":"DATASET_GENERATION_UNAVAILABLE"`) || !strings.Contains(published.Body, `"retryable":true`) { + t.Fatalf("publish status=%d body=%s", published.StatusCode, published.Body) + } + if materializeCalls != 0 { + t.Fatalf("materializer called %d times after failed generation preflight", materializeCalls) + } +} + +func TestExplorerPublishErrorHidesBackendCause(t *testing.T) { + app := fiber.New() + app.Get("/", func(c fiber.Ctx) error { + c.Locals("request_id", "request-a") + return explorerV2ErrorWithDetails(c, http.StatusServiceUnavailable, "DATASET_BUILD_FAILED", "the dataset could not be built", publicExplorerPublishDetails(fiber.Map{ + "generation": "generation-a", + "output": "Patient", + "cause": "secret backend query and credentials", + })) + }) + response := requestJSON(t, app, http.MethodGet, "/", "") + if response.StatusCode != http.StatusServiceUnavailable || !strings.Contains(response.Body, `"retryable":true`) || !strings.Contains(response.Body, `"requestId":"request-a"`) { + t.Fatalf("publish error status=%d body=%s", response.StatusCode, response.Body) + } + if strings.Contains(response.Body, "secret backend") || !strings.Contains(response.Body, `"output":"Patient"`) { + t.Fatalf("publish error leaked backend cause or lost public context: %s", response.Body) } } diff --git a/internal/server/recipe_publication.go b/internal/server/recipe_publication.go index 9076314b..ed567f8b 100644 --- a/internal/server/recipe_publication.go +++ b/internal/server/recipe_publication.go @@ -90,7 +90,8 @@ func publishResolvedRecipe(ctx context.Context, recipeEngine *engine.Engine, tar } identity := publication.BundleIdentity{ Name: name, TranslationVersion: full.Semantic.SemanticPlan.TranslationVersion, - Project: bindings.Project, DatasetGeneration: bindings.DatasetGeneration, + OutputName: incrementalPublicationOutput(bindings, streams), + Project: bindings.Project, DatasetGeneration: bindings.DatasetGeneration, RecipeDigest: full.StoredRecipeDigest, SchemaDigest: full.ResolvedSchemaDigest, ScopeDigest: full.Semantic.ScopeDigest, EngineVersion: "loom-recipe-v1", AuthScopeMode: string(bindings.AuthScopeMode), @@ -117,7 +118,8 @@ func publishResolvedRecipe(ctx context.Context, recipeEngine *engine.Engine, tar } publicationIdentity := publication.PublicationIdentity{ Name: identity.Name, TranslationVersion: identity.TranslationVersion, - Project: identity.Project, DatasetGeneration: identity.DatasetGeneration, + OutputName: identity.OutputName, + Project: identity.Project, DatasetGeneration: identity.DatasetGeneration, RecipeDigest: identity.RecipeDigest, SchemaDigest: identity.SchemaDigest, ScopeDigest: identity.ScopeDigest, EngineVersion: identity.EngineVersion, AuthScopeMode: identity.AuthScopeMode, @@ -127,6 +129,13 @@ func publishResolvedRecipe(ctx context.Context, recipeEngine *engine.Engine, tar return identity, err } +func incrementalPublicationOutput(bindings recipe.RuntimeBindings, streams []engine.OutputStream) string { + if len(bindings.OutputNames) != 1 || len(streams) != 1 { + return "" + } + return streams[0].Name +} + func recipeResolvedDynamicColumnCounts(plan engine.Resolved) map[string]int { counts := make(map[string]int, len(plan.Semantic.ResolvedColumns)) for dynamicMap, columns := range plan.Semantic.ResolvedColumns { diff --git a/internal/server/server.go b/internal/server/server.go index 0bff5ea5..d9a1994d 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -218,7 +218,7 @@ func run(ctx context.Context, serverConfig Config) error { } } verificationStore := publicationVerificationStore{executions: publishedRegistry, query: lifecycleClient} - releaseService := &publicationcontract.ReleaseService{Snapshots: lifecycleStore, Releases: lifecycleStore, Verifier: verificationStore, Required: serverConfig.Server.RequiredDataframeSelectors} + releaseService := &publicationcontract.ReleaseService{Snapshots: lifecycleStore, Manifests: lifecycleStore, Releases: lifecycleStore, Verifier: verificationStore, Required: serverConfig.Server.RequiredDataframeSelectors} activateExplorerRelease := func(ctx context.Context, project, generation string, selectors []publicationcontract.DataframeSelector) error { expectedRevision := int64(0) active, err := releaseService.Active(ctx, project) @@ -233,6 +233,9 @@ func run(ctx context.Context, serverConfig Config) error { }) return err } + validateExplorerReleaseGeneration := func(ctx context.Context, project, generation string) error { + return releaseService.ValidateGeneration(ctx, project, generation) + } noAuthEnabled := serverConfig.Server.AllowUnauthenticated || serverConfig.Auth.AllowUnauthenticated var candidateProjects func(context.Context) ([]string, error) if noAuthEnabled { @@ -380,11 +383,13 @@ func run(ctx context.Context, serverConfig Config) error { }, explorerService, explorerMaterializer, ExplorerV2LifecycleConfig{ Compile: explorerV2Compiler(recipeEngine, explorerCatalog), Catalog: explorerCatalog, + Logger: logger, Preview: func(ctx context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (map[string][]map[string]any, error) { return recipeEngine.PreviewBundle(ctx, bundle, bindings) }, - Materialize: explorerMaterializer, - ActivateRelease: activateExplorerRelease, + Materialize: explorerMaterializer, + ValidateReleaseGeneration: validateExplorerReleaseGeneration, + ActivateRelease: activateExplorerRelease, }) if publicationWorker != nil { go func() { diff --git a/internal/store/clickhouse/client.go b/internal/store/clickhouse/client.go index 08568432..22d7ffdf 100644 --- a/internal/store/clickhouse/client.go +++ b/internal/store/clickhouse/client.go @@ -265,6 +265,24 @@ func normalizeInsertValue(column Column, value any) (any, error) { if items.Kind() != reflect.Array && items.Kind() != reflect.Slice { return nil, fmt.Errorf("ClickHouse column %q expects %s, got %T", column.Name, columnType, value) } + if unwrapClickHouseType(itemType, "Nullable") == "JSON" { + normalized := make([]*ch.JSON, items.Len()) + for index := 0; index < items.Len(); index++ { + item, err := normalizeInsertValue(Column{Name: column.Name, Type: itemType}, items.Index(index).Interface()) + if err != nil { + return nil, err + } + if item == nil { + continue + } + jsonValue, ok := item.(*ch.JSON) + if !ok { + return nil, fmt.Errorf("ClickHouse column %q JSON array item normalized to %T", column.Name, item) + } + normalized[index] = jsonValue + } + return normalized, nil + } normalized := make([]any, items.Len()) for index := 0; index < items.Len(); index++ { item, err := normalizeInsertValue(Column{Name: column.Name, Type: itemType}, items.Index(index).Interface()) @@ -275,6 +293,9 @@ func normalizeInsertValue(column Column, value any) (any, error) { } return normalized, nil } + if baseType == "JSON" { + return normalizeJSONInsertValue(column.Name, value) + } text, isString := value.(string) if !isString { return value, nil @@ -297,6 +318,139 @@ func normalizeInsertValue(column Column, value any) (any, error) { return value, nil } +func normalizeJSONInsertValue(column string, value any) (any, error) { + if value == nil { + return nil, nil + } + if _, ok := value.(*ch.JSON); ok { + return value, nil + } + if _, ok := value.(ch.JSON); ok { + return value, nil + } + object, ok, err := jsonObjectMap(value) + if err != nil { + return nil, fmt.Errorf("ClickHouse column %q JSON object: %w", column, err) + } + if !ok { + return nil, fmt.Errorf("ClickHouse column %q expects a JSON object, got %T", column, value) + } + return buildNativeJSONObject(object) +} + +func buildNativeJSONObject(object map[string]any) (*ch.JSON, error) { + result := ch.NewJSON() + if err := addNativeJSONFields(result, "", object); err != nil { + return nil, err + } + return result, nil +} + +func addNativeJSONFields(result *ch.JSON, prefix string, object map[string]any) error { + for key, value := range object { + path := key + if prefix != "" { + path = prefix + "." + key + } + if nested, ok, err := jsonObjectMap(value); err != nil { + return err + } else if ok { + if err := addNativeJSONFields(result, path, nested); err != nil { + return err + } + continue + } + normalized, err := normalizeNativeJSONField(value) + if err != nil { + return err + } + result.SetValueAtPath(path, normalized) + } + return nil +} + +func normalizeNativeJSONField(value any) (any, error) { + if value == nil { + return nil, nil + } + rv := reflect.ValueOf(value) + for rv.IsValid() && (rv.Kind() == reflect.Interface || rv.Kind() == reflect.Pointer) { + if rv.IsNil() { + return nil, nil + } + rv = rv.Elem() + } + if !rv.IsValid() || (rv.Kind() != reflect.Slice && rv.Kind() != reflect.Array) || rv.Type().Elem().Kind() == reflect.Uint8 { + return value, nil + } + items := make([]*ch.JSON, rv.Len()) + for index := 0; index < rv.Len(); index++ { + item := rv.Index(index).Interface() + if item == nil || (reflect.ValueOf(item).Kind() == reflect.Pointer && reflect.ValueOf(item).IsNil()) { + continue + } + object, ok, err := jsonObjectMap(item) + if err != nil { + return nil, err + } + if !ok { + return value, nil + } + converted, err := buildNativeJSONObject(object) + if err != nil { + return nil, err + } + items[index] = converted + } + return ch.NewDynamicWithType(items, "Array(JSON)"), nil +} + +func jsonObjectMap(value any) (map[string]any, bool, error) { + if value == nil { + return nil, false, nil + } + switch typed := value.(type) { + case map[string]any: + return typed, true, nil + case ch.JSON: + return typed.NestedMap(), true, nil + case *ch.JSON: + if typed == nil { + return nil, false, nil + } + return typed.NestedMap(), true, nil + } + rv := reflect.ValueOf(value) + for rv.IsValid() && (rv.Kind() == reflect.Interface || rv.Kind() == reflect.Pointer) { + if rv.IsNil() { + return nil, false, nil + } + rv = rv.Elem() + } + if !rv.IsValid() { + return nil, false, nil + } + if rv.Kind() == reflect.Map && rv.Type().Key().Kind() == reflect.String { + result := make(map[string]any, rv.Len()) + for _, key := range rv.MapKeys() { + result[key.String()] = rv.MapIndex(key).Interface() + } + return result, true, nil + } + if rv.Kind() != reflect.Struct { + return nil, false, nil + } + encoded, err := json.Marshal(value) + if err != nil { + return nil, false, err + } + var result map[string]any + if err := json.Unmarshal(encoded, &result); err != nil { + return nil, false, nil + } + return result, true, nil +} + func unwrapClickHouseType(value, wrapper string) string { if inner, ok := wrappedClickHouseType(value, wrapper); ok { return inner @@ -385,6 +539,13 @@ func parseOptions(opts Options) (*ch.Options, error) { parsed.Auth.Password = opts.Password parsed.DialTimeout = opts.Timeout parsed.ReadTimeout = opts.Timeout + // Native JSON columns are used for logical object-valued dataframe fields. + // Keep the setting on every connection so DDL and native batch inserts work + // consistently against ClickHouse 25.3 deployments. + if parsed.Settings == nil { + parsed.Settings = ch.Settings{} + } + parsed.Settings["allow_experimental_json_type"] = true return parsed, nil } diff --git a/internal/store/clickhouse/client_test.go b/internal/store/clickhouse/client_test.go index 50895a4b..cb4c3584 100644 --- a/internal/store/clickhouse/client_test.go +++ b/internal/store/clickhouse/client_test.go @@ -3,6 +3,8 @@ package clickhouse import ( "testing" "time" + + ch "github.com/ClickHouse/clickhouse-go/v2" ) func TestNewUsesOfficialDriverDSN(t *testing.T) { @@ -61,3 +63,38 @@ func TestNormalizeInsertValueUsesEmptyArrayForMissingRepeatedValue(t *testing.T) t.Fatalf("empty array length = %d", got) } } + +func TestNormalizeInsertValuePassesNativeJSONValuesThrough(t *testing.T) { + value, err := normalizeInsertValue(Column{Name: "method", Type: "Nullable(JSON)"}, map[string]any{"code": "M1"}) + if err != nil { + t.Fatal(err) + } + jsonValue, ok := value.(*ch.JSON) + if !ok || jsonValue.NestedMap()["code"] != "M1" { + t.Fatalf("native JSON value = %#v", value) + } + + value, err = normalizeInsertValue(Column{Name: "method", Type: "JSON"}, map[string]any{ + "coding": []map[string]any{{"code": "M1", "display": "Fixation"}}, + }) + if err != nil { + t.Fatal(err) + } + jsonValue, ok = value.(*ch.JSON) + if !ok { + t.Fatalf("nested native JSON value = %#v", value) + } + coding, ok := jsonValue.NestedMap()["coding"].(ch.Dynamic) + if !ok || coding.Type() != "Array(JSON)" { + t.Fatalf("nested coding value = %#v", jsonValue.NestedMap()["coding"]) + } + + value, err = normalizeInsertValue(Column{Name: "methods", Type: "Array(JSON)"}, []map[string]any{{"code": "M1"}, {"code": "M2"}}) + if err != nil { + t.Fatal(err) + } + items, ok := value.([]*ch.JSON) + if !ok || len(items) != 2 { + t.Fatalf("native JSON array = %#v", value) + } +} diff --git a/internal/store/clickhouse/integration_test.go b/internal/store/clickhouse/integration_test.go index 6fbd0555..0d1ececd 100644 --- a/internal/store/clickhouse/integration_test.go +++ b/internal/store/clickhouse/integration_test.go @@ -84,3 +84,73 @@ func TestClickHouseNativeRoundTrip(t *testing.T) { t.Fatalf("verify after pruning: %v", err) } } + +func TestClickHouseNativeJSONRoundTrip(t *testing.T) { + url := os.Getenv("LOOM_CLICKHOUSE_URL") + if url == "" { + t.Skip("LOOM_CLICKHOUSE_URL is not set") + } + database := os.Getenv("LOOM_CLICKHOUSE_DATABASE") + if database == "" { + database = "loom_test" + } + client, err := New(Options{ + URL: url, Database: database, + Username: os.Getenv("LOOM_CLICKHOUSE_USERNAME"), + Password: os.Getenv("LOOM_CLICKHOUSE_PASSWORD"), + Timeout: 10 * time.Second, + }) + if err != nil { + t.Fatal(err) + } + defer client.Close() + ctx := context.Background() + if err := client.EnsureDatabase(ctx); err != nil { + t.Fatal(err) + } + if err := client.Ping(ctx); err != nil { + t.Fatalf("ping ClickHouse: %v", err) + } + table := "loom_json_it_" + uuid.NewString()[:8] + defer client.DropTable(ctx, table) + columns := []Column{ + {Name: "__loom_row_id", Type: "String"}, + {Name: "method", Type: "Nullable(JSON)"}, + {Name: "methods", Type: "Array(JSON)"}, + } + if err := client.CreateTable(ctx, table, columns); err != nil { + t.Fatal(err) + } + rows := []map[string]any{{ + "__loom_row_id": "1", + "method": map[string]any{ + "coding": []map[string]any{{"code": "M1", "display": "method one"}}, + "text": "method one", + }, + "methods": []map[string]any{ + {"coding": map[string]any{"code": "M1"}}, + {"coding": map[string]any{"code": "M2"}}, + }, + }} + if err := client.InsertRows(ctx, table, columns, rows); err != nil { + t.Fatal(err) + } + result, err := client.QueryRowsArgs(ctx, "SELECT `method`, `methods` FROM `"+table+"`", []string{"method", "methods"}) + if err != nil { + t.Fatal(err) + } + if len(result) != 1 { + t.Fatalf("JSON rows = %#v", result) + } + method, ok := result[0]["method"].(map[string]any) + if !ok || method["text"] != "method one" { + t.Fatalf("JSON object = %#v", result[0]["method"]) + } + methods, ok := result[0]["methods"].([]any) + if !ok || len(methods) != 2 { + t.Fatalf("JSON array = %#v", result[0]["methods"]) + } + if err := client.VerifyOutput(ctx, table, columns, 1); err != nil { + t.Fatalf("verify JSON output: %v", err) + } +} From 3c58ae3d41b10c783b7b0c1c14ae9bfd56e0c3e8 Mon Sep 17 00:00:00 2001 From: matthewpeterkort Date: Tue, 25 Aug 2026 14:11:55 -0700 Subject: [PATCH 07/15] refactor --- Dockerfile | 10 +- README.md | 20 +- cmd/arango-fhir-proto/main.go | 288 +- cmd/arango-fhir-proto/main_test.go | 72 + cmd/explorer-authoring-bootstrap/main.go | 100 + cmd/explorer-authoring-live-migrate/main.go | 409 + cmd/generate/extraction.go | 104 +- cmd/generate/extraction_test.go | 37 +- cmd/generate/metadata.go | 36 +- cmd/generate/metadata_test.go | 24 + cmd/generate/names.go | 11 - generated/fhir/extract.go | 109277 ++++++--------- generated/fhirschema/generated.go | 41081 ++---- internal/api/http/errors.go | 12 +- internal/api/http/errors_test.go | 23 + internal/api/http/http_test.go | 58 + internal/api/http/middleware.go | 73 +- internal/authscope/principal.go | 5 +- internal/authscope/scope_resolver.go | 25 + internal/authscope/scope_test.go | 25 + internal/catalog/arango/store.go | 402 +- internal/catalog/arango/store_test.go | 136 +- internal/catalog/capability_evidence.go | 143 + internal/catalog/capability_evidence_test.go | 53 + internal/catalog/limits.go | 65 + internal/catalog/rebuild.go | 26 + internal/catalog/relationships.go | 13 +- internal/catalog/relationships_test.go | 9 + internal/catalog/types.go | 163 +- internal/catalog/write_profiler.go | 91 +- internal/catalog/write_profiler_test.go | 35 + .../dataframe/compiler/capability/probe.go | 758 + .../compiler/capability/probe_test.go | 138 + internal/dataframe/compiler/grain_test.go | 6 + .../compiler/semantic_validation_test.go | 14 +- internal/dataframe/errors/errors.go | 11 +- internal/dataframe/errors/errors_test.go | 28 +- internal/dataframe/recipe/engine/engine.go | 318 +- .../dataframe/recipe/engine/engine_test.go | 328 + .../dataframe/recipe/engine/identity_test.go | 1 + .../dataframe/semantic/semantic_validation.go | 38 +- internal/dataframe/spec/grain.go | 18 +- .../arango/capability_snapshot_store.go | 202 + .../arango/capability_snapshot_store_test.go | 91 + internal/explorer/arango/collections.go | 13 +- internal/explorer/arango/collections_test.go | 2 +- .../explorer/arango/receipt_store_test.go | 100 + internal/explorer/arango/store.go | 195 + internal/explorer/authoring_v1.go | 470 + internal/explorer/authoring_v1_test.go | 214 + internal/explorer/authoringv2/migration.go | 80 + .../explorer/authoringv2/migration_test.go | 45 + internal/explorer/authoringv2/types.go | 678 + internal/explorer/authoringv2/types_test.go | 132 + internal/explorer/bootstrap/bootstrap.go | 353 + internal/explorer/bootstrap/bootstrap_test.go | 61 + internal/explorer/canonical_json.go | 35 + internal/explorer/capability/builder.go | 444 + internal/explorer/capability/builder_test.go | 165 + internal/explorer/capability/domain.go | 390 + .../explorer/capabilitystore/repository.go | 234 + .../capabilitystore/repository_test.go | 92 + internal/explorer/catalog.go | 44 +- internal/explorer/catalog_test.go | 18 + internal/explorer/compilation.go | 13 +- internal/explorer/compilation/translate.go | 503 + .../explorer/compilation/translate_test.go | 110 + internal/explorer/compilation_receipt.go | 323 + internal/explorer/compilation_receipt_test.go | 148 + internal/explorer/config_v2.go | 169 +- internal/explorer/config_v2_test.go | 38 + internal/explorer/memory_store.go | 262 +- internal/explorer/output_contract.go | 136 + internal/explorer/output_contract_test.go | 82 + internal/explorer/receipt_store_test.go | 82 + internal/explorer/service.go | 133 +- internal/explorer/state_v1.go | 249 + internal/explorer/store.go | 66 + internal/explorer/types.go | 62 +- internal/fhir/schema/compiler_semantics.go | 33 +- .../fhir/schema/compiler_semantics_test.go | 21 + internal/ingest/documents.go | 23 +- internal/ingest/documents_test.go | 35 + internal/ingest/generated_load_test.go | 37 + internal/ingest/generation_orchestration.go | 5 +- internal/ingest/generation_workers.go | 12 +- internal/ingest/load_options.go | 15 + internal/ingest/load_options_test.go | 43 + internal/projectid/projectid.go | 76 + internal/projectid/projectid_test.go | 35 + .../server/explorer_authoring_migration.go | 687 + .../explorer_authoring_migration_test.go | 197 + .../explorer_authoring_normalization_test.go | 223 + internal/server/explorer_authoring_v1.go | 878 + .../server/explorer_authoring_v1_routes.go | 503 + internal/server/explorer_authoring_v1_test.go | 440 + .../server/explorer_authoring_v2_routes.go | 524 + internal/server/explorer_builder_lifecycle.go | 167 + .../server/explorer_builder_routes_test.go | 429 + internal/server/explorer_capability.go | 555 + internal/server/explorer_capability_test.go | 343 + internal/server/explorer_config_route.go | 15 +- internal/server/explorer_preview_response.go | 249 + .../server/explorer_preview_response_test.go | 87 + internal/server/explorer_preview_security.go | 152 + .../server/explorer_preview_security_test.go | 141 + internal/server/explorer_publication.go | 41 + internal/server/explorer_receipt_contract.go | 104 + .../server/explorer_receipt_contract_test.go | 203 + internal/server/explorer_v2_engine.go | 38 +- internal/server/explorer_v2_engine_test.go | 12 +- internal/server/explorer_v2_lifecycle.go | 800 +- internal/server/explorer_v2_lifecycle_test.go | 346 +- internal/server/explorer_wiring.go | 48 +- internal/server/options.go | 30 + internal/server/project_id.go | 20 + internal/server/project_id_test.go | 35 + internal/server/server.go | 223 +- internal/server/wiring_test.go | 11 + internal/store/arango/client.go | 42 +- .../store/arango/client_queryrows_test.go | 144 + .../store/arango/profile_integration_test.go | 100 + 122 files changed, 70446 insertions(+), 98594 deletions(-) create mode 100644 cmd/explorer-authoring-bootstrap/main.go create mode 100644 cmd/explorer-authoring-live-migrate/main.go create mode 100644 internal/catalog/capability_evidence.go create mode 100644 internal/catalog/capability_evidence_test.go create mode 100644 internal/catalog/limits.go create mode 100644 internal/dataframe/compiler/capability/probe.go create mode 100644 internal/dataframe/compiler/capability/probe_test.go create mode 100644 internal/explorer/arango/capability_snapshot_store.go create mode 100644 internal/explorer/arango/capability_snapshot_store_test.go create mode 100644 internal/explorer/arango/receipt_store_test.go create mode 100644 internal/explorer/authoring_v1.go create mode 100644 internal/explorer/authoring_v1_test.go create mode 100644 internal/explorer/authoringv2/migration.go create mode 100644 internal/explorer/authoringv2/migration_test.go create mode 100644 internal/explorer/authoringv2/types.go create mode 100644 internal/explorer/authoringv2/types_test.go create mode 100644 internal/explorer/bootstrap/bootstrap.go create mode 100644 internal/explorer/bootstrap/bootstrap_test.go create mode 100644 internal/explorer/canonical_json.go create mode 100644 internal/explorer/capability/builder.go create mode 100644 internal/explorer/capability/builder_test.go create mode 100644 internal/explorer/capability/domain.go create mode 100644 internal/explorer/capabilitystore/repository.go create mode 100644 internal/explorer/capabilitystore/repository_test.go create mode 100644 internal/explorer/compilation/translate.go create mode 100644 internal/explorer/compilation/translate_test.go create mode 100644 internal/explorer/compilation_receipt.go create mode 100644 internal/explorer/compilation_receipt_test.go create mode 100644 internal/explorer/output_contract.go create mode 100644 internal/explorer/output_contract_test.go create mode 100644 internal/explorer/receipt_store_test.go create mode 100644 internal/explorer/state_v1.go create mode 100644 internal/ingest/documents_test.go create mode 100644 internal/ingest/load_options_test.go create mode 100644 internal/projectid/projectid.go create mode 100644 internal/projectid/projectid_test.go create mode 100644 internal/server/explorer_authoring_migration.go create mode 100644 internal/server/explorer_authoring_migration_test.go create mode 100644 internal/server/explorer_authoring_normalization_test.go create mode 100644 internal/server/explorer_authoring_v1.go create mode 100644 internal/server/explorer_authoring_v1_routes.go create mode 100644 internal/server/explorer_authoring_v1_test.go create mode 100644 internal/server/explorer_authoring_v2_routes.go create mode 100644 internal/server/explorer_builder_lifecycle.go create mode 100644 internal/server/explorer_builder_routes_test.go create mode 100644 internal/server/explorer_capability.go create mode 100644 internal/server/explorer_capability_test.go create mode 100644 internal/server/explorer_preview_response.go create mode 100644 internal/server/explorer_preview_response_test.go create mode 100644 internal/server/explorer_preview_security.go create mode 100644 internal/server/explorer_preview_security_test.go create mode 100644 internal/server/explorer_receipt_contract.go create mode 100644 internal/server/explorer_receipt_contract_test.go create mode 100644 internal/server/project_id.go create mode 100644 internal/server/project_id_test.go create mode 100644 internal/store/arango/client_queryrows_test.go diff --git a/Dockerfile b/Dockerfile index 85e42593..7822fdb0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,7 +21,7 @@ COPY internal ./internal COPY schemas ./schemas ARG TARGETOS=linux -ARG TARGETARCH=amd64 +ARG TARGETARCH RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ GOOS="$TARGETOS" GOARCH="$TARGETARCH" \ @@ -29,6 +29,13 @@ RUN --mount=type=cache,target=/go/pkg/mod \ -trimpath \ -ldflags="-s -w" \ -o /out/arango-fhir-server ./cmd/arango-fhir-server +RUN --mount=type=cache,target=/go/pkg/mod \ + --mount=type=cache,target=/root/.cache/go-build \ + GOOS="$TARGETOS" GOARCH="$TARGETARCH" \ + go build -mod=mod \ + -trimpath \ + -ldflags="-s -w" \ + -o /out/arango-fhir-proto ./cmd/arango-fhir-proto FROM alpine:3.22 RUN apk add --no-cache ca-certificates tzdata && \ @@ -38,6 +45,7 @@ RUN apk add --no-cache ca-certificates tzdata && \ WORKDIR /app COPY --from=builder /out/arango-fhir-server /app/arango-fhir-server +COPY --from=builder /out/arango-fhir-proto /app/arango-fhir-proto COPY --from=builder /src/schemas /app/schemas USER arango-fhir diff --git a/README.md b/README.md index 43e976d0..d4f2e1f3 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,11 @@ Loom is deliberately not an arbitrary AQL gateway, ClickHouse SQL proxy, or a replacement FHIR model. It is a recipe-driven graph-to-flat data service with explicit authorization and publication boundaries. +Explorer Builder authoring is intent-driven: the browser submits the versioned +V1 authoring document, Loom lowers it to a native recipe, and the existing +recipe compiler produces the scoped plan/AQL. The browser never constructs or +repairs the recipe AST. See [the Explorer authoring contract](docs/EXPLORER_AUTHORING.md). + ```mermaid flowchart LR NDJSON["FHIR NDJSON"] --> Ingest["Ingest and catalog"] @@ -55,7 +60,7 @@ recipe, translation-version, and output selector. | `arango-fhir-server` | HTTP server for graph compilation/control and flat dataframe reads. | | `POST /graphql/graph` | Arango graph and recipe control plane: explicit graph traversal, typed FHIR reads, recipe validation, preview, execution, publication reads, and recipe control. | | `POST /graphql/dataframe` | Arango-backed FHIR dataframe compiler and executor (`runFhirDataframe`). | -| `POST /api/v1/projects/:project/explorers/...` | REST V2 Explorer lifecycle used by the Builder. | +| `POST /api/v1/projects/:project/explorers/...` | REST Explorer lifecycle and V1 intent authoring used by the Builder. | | `PUT /api/v1/projects/:project/resources/:resourceType` | Primary multipart NDJSON resource loader. | `GET /graphql/graph` serves GraphQL Playground for the graph API. `GET /apollo` @@ -158,9 +163,10 @@ Run the checked-in graph dataframe example after the server is up: make dataframe-demo ``` -See [the Quickstart](docs/QUICKSTART.md) for the complete local setup flow and -[the GraphQL API guide](docs/GRAPHQL_API.md) for copy-paste examples of the -graph/compiler and published flat-reader APIs. +See [the documentation index](docs/README.md) for the complete guide map, +[the Quickstart](docs/QUICKSTART.md) for local setup, and +[the Explorer authoring guide](docs/EXPLORER_AUTHORING.md) for the current +Builder contract. ## Graph and flat GraphQL contracts @@ -299,7 +305,7 @@ without rebuilding the server image. | [`internal/ingest`](internal/ingest) | NDJSON loading, validation, graph extraction, and ingest lifecycle. | | [`internal/dataset`](internal/dataset) | Immutable generation and active-manifest contracts. | | [`internal/catalog`](internal/catalog) | Evidence of populated fields, references, and authorization paths. | -| [`internal/explorer`](internal/explorer) | Editable Explorer V2 configs, drafts, immutable revisions, and publication state. | +| [`internal/explorer`](internal/explorer) | V1 authoring intent, resolved Builder models, server compilation receipts, immutable revisions, publication state, and legacy ETL compatibility types. | | [`internal/dataframe/compiler`](internal/dataframe/compiler) | Typed plan IR, lowering, optimization, and AQL rendering. | | [`internal/dataframe/recipe`](internal/dataframe/recipe) | Recipe contract, validation, schema resolution, execution, and control services. | | [`internal/dataframe/publication`](internal/dataframe/publication) | Backend-neutral bounded streaming publication contract. | @@ -336,13 +342,13 @@ go test ./... ## Further reading +- [Documentation index](docs/README.md) - [Quickstart](docs/QUICKSTART.md) +- [Explorer authoring contract](docs/EXPLORER_AUTHORING.md) - [Default dataframer recipe authoring guide](docs/DATAFRAMER_RECIPES.md) - [Dataframer recipe reference and operating manual](docs/DATAFRAMER_RECIPE_REFERENCE.md) - [GraphQL API guide](docs/GRAPHQL_API.md) - [Developer architecture](docs/DEVELOPER_ARCHITECTURE.md) -- [ClickHouse reader contract and execution plan](docs/CLICKHOUSE_GRAPHQL_READER_EXECUTION_PLAN.md) -- [Explorer/Loom parity plan](docs/EXPLORER_LOOM_SLICE_PARITY_PLAN.md) - [Experimental local stack](experimental/README.md) The Helm chart lives in the separate `gen3-helm` repository under `helm/loom`. diff --git a/cmd/arango-fhir-proto/main.go b/cmd/arango-fhir-proto/main.go index d09749ca..b89a64a3 100644 --- a/cmd/arango-fhir-proto/main.go +++ b/cmd/arango-fhir-proto/main.go @@ -5,14 +5,19 @@ import ( "encoding/json" "flag" "fmt" + "math" "os" "runtime" + "runtime/debug" "runtime/pprof" "runtime/trace" + "strconv" + "strings" "github.com/calypr/loom/internal/catalog" catalogarango "github.com/calypr/loom/internal/catalog/arango" publication "github.com/calypr/loom/internal/dataset" + publicationarango "github.com/calypr/loom/internal/dataset/arango" "github.com/calypr/loom/internal/ingest" arangostore "github.com/calypr/loom/internal/store/arango" ) @@ -41,6 +46,12 @@ func main() { err = runDiscoverPopulatedFields(ctx, os.Args[2:]) case "rebuild-relationship-catalog": err = runRebuildRelationshipCatalog(ctx, os.Args[2:]) + case "audit-relationship-edges": + err = runAuditRelationshipEdges(ctx, os.Args[2:]) + case "repair-generation": + err = runRepairGeneration(ctx, os.Args[2:]) + case "activate-generation": + err = runActivateGeneration(ctx, os.Args[2:]) default: usage() os.Exit(2) @@ -58,6 +69,8 @@ type loadCommandConfig struct { MemProfile string TraceProfile string BlockProfile string + MemoryLimit string + MemoryBytes int64 Generation string } @@ -77,6 +90,9 @@ func parseLoadCommand(args []string, errorHandling flag.ErrorHandling) (loadComm if err := fs.Parse(args); err != nil { return loadCommandConfig{}, err } + if err := config.parseMemoryLimit(); err != nil { + return loadCommandConfig{}, err + } if config.Generation == "" { return loadCommandConfig{}, fmt.Errorf("--generation is required for load-generation") } @@ -96,6 +112,7 @@ func configureLoadFlags(fs *flag.FlagSet, config *loadCommandConfig) { fs.StringVar(&config.MemProfile, "mem-profile", "", "Write heap profile to file at end of run") fs.StringVar(&config.TraceProfile, "trace-profile", "", "Write runtime trace to file") fs.StringVar(&config.BlockProfile, "block-profile", "", "Write block profile to file at end of run") + fs.StringVar(&config.MemoryLimit, "memory-limit", "4GiB", "Go memory limit for this load, for example 4GiB; 0 disables the soft limit") fs.StringVar(&config.Options.URL, "url", defaultURL, "Backend base URL") fs.StringVar(&config.Options.Database, "database", defaultDatabase, "Backend database") fs.StringVar(&config.Options.Schema, "schema", defaultSchema, "graph-fhir JSON schema") @@ -104,32 +121,98 @@ func configureLoadFlags(fs *flag.FlagSet, config *loadCommandConfig) { fs.StringVar(&config.Options.AuthResourcePath, "auth-resource-path", "", "Optional auth resource path copied onto vertex data, for example EllrottLab-GDC_Data") fs.IntVar(&config.Options.BatchSize, "batch-size", 5000, "Bulk insert batch size") fs.IntVar(&config.Options.ProgressEvery, "progress-every", 50000, "Emit progress every N input rows") - fs.IntVar(&config.Options.WriterCount, "writers", 8, "Concurrent writer goroutines") + fs.IntVar(&config.Options.WriterCount, "writers", 2, "Concurrent writer goroutines") + fs.IntVar(&config.Options.WorkerCount, "workers", 2, "Concurrent parse/profile workers") + fs.IntVar(&config.Options.LineQueueSize, "line-queue-size", 1024, "Buffered input lines") + fs.IntVar(&config.Options.WriteQueueSize, "write-queue-size", 8, "Buffered write batches") + profileLimits := catalog.DefaultProfileLimits() + fs.IntVar(&config.Options.CatalogLimits.MaxFields, "max-catalog-fields", profileLimits.MaxFields, "Maximum retained catalog fields per resource") + fs.IntVar(&config.Options.CatalogLimits.MaxDistinctValuesPerField, "max-distinct-values", profileLimits.MaxDistinctValuesPerField, "Maximum retained distinct values per field") + fs.IntVar(&config.Options.CatalogLimits.MaxDistinctValueBytes, "max-distinct-value-bytes", profileLimits.MaxDistinctValueBytes, "Maximum retained bytes per catalog value") + fs.IntVar(&config.Options.CatalogLimits.MaxPivotColumnsPerField, "max-pivot-columns", profileLimits.MaxPivotColumnsPerField, "Maximum retained pivot columns per field") + fs.IntVar(&config.Options.CatalogLimits.MaxExtensionValuesPerField, "max-extension-values", profileLimits.MaxExtensionValuesPerField, "Maximum retained extension observations per field") + fs.IntVar(&config.Options.CatalogLimits.MaxShapePlans, "max-shape-plans", profileLimits.MaxShapePlans, "Maximum cached payload shape plans") fs.BoolVar(&config.Options.FailFast, "fail-fast", false, "Stop on the first decode, validation, or edge conversion error") fs.BoolVar(&config.Options.UseGeneric, "use-generic", false, "Use the generic jsonschema + jsonschemagraph validator and extractor") fs.StringVar(&config.Options.WriteAPI, "write-api", "import", "Bulk write API: import or document") fs.StringVar(&config.Generation, "generation", "", "Required opaque immutable dataset generation identifier") } +func (config *loadCommandConfig) parseMemoryLimit() error { + bytes, err := parseMemoryBytes(config.MemoryLimit) + if err != nil { + return fmt.Errorf("invalid --memory-limit: %w", err) + } + config.MemoryBytes = bytes + return nil +} + func runConfiguredLoad(ctx context.Context, config loadCommandConfig) error { + summary, err := runLoadWithProfiles(ctx, config) + if err != nil { + return err + } + return printJSON(summary) +} + +func runLoadWithProfiles(ctx context.Context, config loadCommandConfig) (summary ingest.LoadSummary, err error) { + previousMemoryLimit := int64(-1) + if config.MemoryBytes > 0 { + previousMemoryLimit = debug.SetMemoryLimit(config.MemoryBytes) + } + if previousMemoryLimit >= 0 { + defer debug.SetMemoryLimit(previousMemoryLimit) + } stopProfiles, profileErr := startProfiles(config.CPUProfile, config.MemProfile, config.TraceProfile, config.BlockProfile) if profileErr != nil { - return profileErr + return ingest.LoadSummary{}, profileErr } - var deferredErr error defer func() { - if stopErr := stopProfiles(); stopErr != nil && deferredErr == nil { - deferredErr = stopErr + if stopErr := stopProfiles(); stopErr != nil && err == nil { + err = stopErr } }() - summary, err := ingest.Load(ctx, config.Options) - if err != nil { - return err + return ingest.Load(ctx, config.Options) +} + +func parseMemoryBytes(raw string) (int64, error) { + raw = strings.TrimSpace(raw) + if raw == "" || raw == "0" { + return 0, nil } - if deferredErr != nil { - return deferredErr + lower := strings.ToLower(raw) + units := []struct { + suffix string + factor float64 + }{ + {suffix: "gib", factor: 1 << 30}, + {suffix: "gb", factor: 1e9}, + {suffix: "gi", factor: 1 << 30}, + {suffix: "g", factor: 1e9}, + {suffix: "mib", factor: 1 << 20}, + {suffix: "mb", factor: 1e6}, + {suffix: "mi", factor: 1 << 20}, + {suffix: "m", factor: 1e6}, + {suffix: "kib", factor: 1 << 10}, + {suffix: "kb", factor: 1e3}, + {suffix: "ki", factor: 1 << 10}, + {suffix: "k", factor: 1e3}, + {suffix: "b", factor: 1}, } - return printJSON(summary) + number := lower + factor := float64(1) + for _, unit := range units { + if strings.HasSuffix(lower, unit.suffix) { + number = strings.TrimSpace(strings.TrimSuffix(lower, unit.suffix)) + factor = unit.factor + break + } + } + value, err := strconv.ParseFloat(number, 64) + if err != nil || value <= 0 || value*factor > math.MaxInt64 { + return 0, fmt.Errorf("expected a positive byte value such as 4GiB") + } + return int64(value * factor), nil } func runDiscoverPopulatedReferences(ctx context.Context, args []string) error { @@ -204,6 +287,186 @@ func runRebuildRelationshipCatalog(ctx context.Context, args []string) error { return printJSON(summary) } +func runAuditRelationshipEdges(ctx context.Context, args []string) error { + fs := flag.NewFlagSet("audit-relationship-edges", flag.ExitOnError) + opts := catalog.RelationshipAuditOptions{} + connection := arangostore.ConnectionOptions{URL: defaultURL, Database: defaultDatabase} + fs.StringVar(&connection.URL, "url", defaultURL, "Backend base URL") + fs.StringVar(&connection.Database, "database", defaultDatabase, "Arango database") + fs.StringVar(&opts.Project, "project", defaultProject, "Project label") + fs.StringVar(&opts.DatasetGeneration, "dataset-generation", "", "Optional generation; empty selects the legacy namespace") + fs.IntVar(&opts.CursorBatch, "cursor-batch-size", 1000, "Query cursor batch size") + if err := fs.Parse(args); err != nil { + return err + } + result, err := auditRelationshipEdges(ctx, connection, opts) + if err != nil { + return err + } + return printJSON(result) +} + +func auditRelationshipEdges(ctx context.Context, connection arangostore.ConnectionOptions, opts catalog.RelationshipAuditOptions) (catalog.RelationshipAuditSummary, error) { + client, err := arangostore.Open(ctx, connection.URL, connection.Database) + if err != nil { + return catalog.RelationshipAuditSummary{}, err + } + defer client.Close(ctx) + adapter, err := catalogarango.New(client) + if err != nil { + return catalog.RelationshipAuditSummary{}, err + } + return adapter.AuditRelationshipEdges(ctx, opts) +} + +type repairCommandConfig struct { + Load loadCommandConfig + SourceGeneration string + Activate bool +} + +type repairGenerationReport struct { + Project string `json:"project"` + SourceGeneration string `json:"source_generation"` + TargetGeneration string `json:"target_generation"` + SourceAudit catalog.RelationshipAuditSummary `json:"source_audit"` + Load ingest.LoadSummary `json:"load"` + TargetAudit catalog.RelationshipAuditSummary `json:"target_audit"` + Activated bool `json:"activated"` +} + +type activateCommandConfig struct { + Connection arangostore.ConnectionOptions + Project string + Generation string +} + +type activateGenerationReport struct { + Project string `json:"project"` + Generation string `json:"generation"` + TargetAudit catalog.RelationshipAuditSummary `json:"target_audit"` + Activated bool `json:"activated"` +} + +func parseRepairCommand(args []string, errorHandling flag.ErrorHandling) (repairCommandConfig, error) { + fs := flag.NewFlagSet("repair-generation", errorHandling) + config := repairCommandConfig{} + configureLoadFlags(fs, &config.Load) + fs.StringVar(&config.SourceGeneration, "source-generation", "", "Existing generation to audit and replace") + fs.BoolVar(&config.Activate, "activate", false, "Activate the repaired generation after validation") + if err := fs.Parse(args); err != nil { + return repairCommandConfig{}, err + } + if err := config.Load.parseMemoryLimit(); err != nil { + return repairCommandConfig{}, err + } + if config.SourceGeneration == "" { + return repairCommandConfig{}, fmt.Errorf("--source-generation is required for repair-generation") + } + if config.Load.Generation == "" { + return repairCommandConfig{}, fmt.Errorf("--generation is required for repair-generation") + } + if config.SourceGeneration == config.Load.Generation { + return repairCommandConfig{}, fmt.Errorf("--generation must differ from --source-generation") + } + if _, err := publication.NewRef(config.Load.Options.Project, config.SourceGeneration); err != nil { + return repairCommandConfig{}, fmt.Errorf("invalid --source-generation: %w", err) + } + ref, err := publication.NewRef(config.Load.Options.Project, config.Load.Generation) + if err != nil { + return repairCommandConfig{}, fmt.Errorf("invalid --generation for repair-generation: %w", err) + } + config.Load.Options.Dataset = &ref + config.Load.Options.StageOnly = true + return config, nil +} + +func runRepairGeneration(ctx context.Context, args []string) error { + config, err := parseRepairCommand(args, flag.ExitOnError) + if err != nil { + return err + } + connection := arangostore.ConnectionOptions{URL: config.Load.Options.URL, Database: config.Load.Options.Database} + sourceAudit, err := auditRelationshipEdges(ctx, connection, catalog.RelationshipAuditOptions{Project: config.Load.Options.Project, DatasetGeneration: config.SourceGeneration}) + if err != nil { + return fmt.Errorf("audit source generation: %w", err) + } + loadSummary, err := runLoadWithProfiles(ctx, config.Load) + if err != nil { + return err + } + targetAudit, err := auditRelationshipEdges(ctx, connection, catalog.RelationshipAuditOptions{Project: config.Load.Options.Project, DatasetGeneration: config.Load.Generation}) + if err != nil { + return fmt.Errorf("audit repaired generation: %w", err) + } + if targetAudit.InvalidEdgeCount != 0 { + return fmt.Errorf("repaired generation %s still contains %d invalid edge(s); it remains staged", config.Load.Generation, targetAudit.InvalidEdgeCount) + } + activated := false + if config.Activate { + if err := activateStagedGeneration(ctx, connection, *config.Load.Options.Dataset); err != nil { + return fmt.Errorf("activate repaired generation: %w", err) + } + activated = true + } + return printJSON(repairGenerationReport{Project: config.Load.Options.Project, SourceGeneration: config.SourceGeneration, TargetGeneration: config.Load.Generation, SourceAudit: sourceAudit, Load: loadSummary, TargetAudit: targetAudit, Activated: activated}) +} + +func parseActivateCommand(args []string, errorHandling flag.ErrorHandling) (activateCommandConfig, error) { + fs := flag.NewFlagSet("activate-generation", errorHandling) + config := activateCommandConfig{Connection: arangostore.ConnectionOptions{URL: defaultURL, Database: defaultDatabase}} + fs.StringVar(&config.Connection.URL, "url", defaultURL, "Backend base URL") + fs.StringVar(&config.Connection.Database, "database", defaultDatabase, "Arango database") + fs.StringVar(&config.Project, "project", defaultProject, "Project label") + fs.StringVar(&config.Generation, "generation", "", "Staged immutable generation to activate") + if err := fs.Parse(args); err != nil { + return activateCommandConfig{}, err + } + if config.Generation == "" { + return activateCommandConfig{}, fmt.Errorf("--generation is required for activate-generation") + } + if _, err := publication.NewRef(config.Project, config.Generation); err != nil { + return activateCommandConfig{}, fmt.Errorf("invalid --generation for activate-generation: %w", err) + } + return config, nil +} + +func runActivateGeneration(ctx context.Context, args []string) error { + config, err := parseActivateCommand(args, flag.ExitOnError) + if err != nil { + return err + } + audit, err := auditRelationshipEdges(ctx, config.Connection, catalog.RelationshipAuditOptions{Project: config.Project, DatasetGeneration: config.Generation}) + if err != nil { + return fmt.Errorf("audit generation before activation: %w", err) + } + if audit.InvalidEdgeCount != 0 { + return fmt.Errorf("generation %s contains %d invalid edge(s); activation refused", config.Generation, audit.InvalidEdgeCount) + } + ref, _ := publication.NewRef(config.Project, config.Generation) + if err := activateStagedGeneration(ctx, config.Connection, ref); err != nil { + return err + } + return printJSON(activateGenerationReport{Project: config.Project, Generation: config.Generation, TargetAudit: audit, Activated: true}) +} + +func activateStagedGeneration(ctx context.Context, connection arangostore.ConnectionOptions, ref publication.Ref) error { + client, err := arangostore.Open(ctx, connection.URL, connection.Database) + if err != nil { + return err + } + defer client.Close(ctx) + lifecycle, err := publicationarango.New(client) + if err != nil { + return err + } + manifest, err := lifecycle.ReadManifest(ctx, ref) + if err != nil { + return err + } + return lifecycle.Activate(ctx, manifest) +} + func parseDiscoverPopulatedReferenceOptions(args []string, errorHandling flag.ErrorHandling) (catalog.PopulatedReferenceOptions, arangostore.ConnectionOptions, error) { fs := flag.NewFlagSet("discover-populated-references", errorHandling) opts := catalog.PopulatedReferenceOptions{} @@ -253,7 +516,10 @@ func usage() { arango-fhir-proto load-generation --generation OPAQUE_ID [flags] # immutable complete META directory arango-fhir-proto discover-populated-references [flags] arango-fhir-proto discover-populated-fields [flags] + arango-fhir-proto audit-relationship-edges [flags] # read-only invalid endpoint audit arango-fhir-proto rebuild-relationship-catalog [flags] # explicit fhir_edge repair/backfill + arango-fhir-proto repair-generation [flags] # stage a corrected immutable generation; --activate is explicit + arango-fhir-proto activate-generation [flags] # validate and activate a staged immutable generation `) } diff --git a/cmd/arango-fhir-proto/main_test.go b/cmd/arango-fhir-proto/main_test.go index 7920e864..3da1bae0 100644 --- a/cmd/arango-fhir-proto/main_test.go +++ b/cmd/arango-fhir-proto/main_test.go @@ -27,6 +27,30 @@ func TestParseGenerationLoadWiresImmutableDataset(t *testing.T) { if got, want := config.Options.Dataset.Generation, "load:2026-07-11/v1"; got != want { t.Fatalf("generation dataset generation = %q, want %q", got, want) } + if config.MemoryBytes <= 0 || config.Options.WorkerCount != 2 { + t.Fatalf("resource defaults = memory %d workers %d, want finite memory and two workers", config.MemoryBytes, config.Options.WorkerCount) + } +} + +func TestParseMemoryBytes(t *testing.T) { + tests := []struct { + input string + want int64 + }{ + {input: "4GiB", want: 4 << 30}, + {input: "512Mi", want: 512 << 20}, + {input: "1000", want: 1000}, + {input: "0", want: 0}, + } + for _, test := range tests { + got, err := parseMemoryBytes(test.input) + if err != nil || got != test.want { + t.Fatalf("parseMemoryBytes(%q) = %d, %v; want %d", test.input, got, err, test.want) + } + } + if _, err := parseMemoryBytes("not-memory"); err == nil { + t.Fatal("parseMemoryBytes accepted invalid input") + } } func TestParseGenerationLoadRejectsUnsafeOrInvalidInput(t *testing.T) { @@ -61,6 +85,54 @@ func TestParseGenerationLoadRejectsUnsafeOrInvalidInput(t *testing.T) { } } +func TestParseRepairCommandStagesDistinctImmutableGeneration(t *testing.T) { + config, err := parseRepairCommand([]string{ + "--project", "project-a", + "--source-generation", "generation-old", + "--generation", "generation-new", + "--meta-dir", "META_SMALL", + }, flag.ContinueOnError) + if err != nil { + t.Fatalf("parseRepairCommand() error = %v", err) + } + if config.Load.Options.Dataset == nil || config.Load.Options.Dataset.Generation != "generation-new" { + t.Fatalf("repair dataset = %#v, want generation-new", config.Load.Options.Dataset) + } + if !config.Load.Options.StageOnly { + t.Fatal("repair command must stage before optional activation") + } + if config.Activate { + t.Fatal("repair command activated without --activate") + } +} + +func TestParseRepairCommandRejectsSameGeneration(t *testing.T) { + _, err := parseRepairCommand([]string{ + "--project", "project-a", + "--source-generation", "generation-a", + "--generation", "generation-a", + }, flag.ContinueOnError) + if err == nil || !strings.Contains(err.Error(), "must differ") { + t.Fatalf("parseRepairCommand() error = %v, want distinct-generation error", err) + } +} + +func TestParseActivateCommandRequiresValidGeneration(t *testing.T) { + config, err := parseActivateCommand([]string{ + "--project", "project-a", + "--generation", "generation-new", + }, flag.ContinueOnError) + if err != nil { + t.Fatalf("parseActivateCommand() error = %v", err) + } + if config.Project != "project-a" || config.Generation != "generation-new" { + t.Fatalf("activation config = %#v", config) + } + if _, err := parseActivateCommand([]string{"--project", "project-a"}, flag.ContinueOnError); err == nil || !strings.Contains(err.Error(), "--generation is required") { + t.Fatalf("missing generation error = %v", err) + } +} + func TestParseDiscoveryCommandsPassExplicitDatasetGeneration(t *testing.T) { fields, _, err := parseDiscoverPopulatedFieldOptions([]string{ "--project", "project-a", diff --git a/cmd/explorer-authoring-bootstrap/main.go b/cmd/explorer-authoring-bootstrap/main.go new file mode 100644 index 00000000..e5058ae9 --- /dev/null +++ b/cmd/explorer-authoring-bootstrap/main.go @@ -0,0 +1,100 @@ +package main + +import ( + "bytes" + "encoding/json" + "flag" + "fmt" + "io" + "os" + + "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/explorer/bootstrap" +) + +type pinnedCatalog struct { + Nodes []struct { + NodeID string `json:"nodeId"` + ResourceType string `json:"resourceType"` + } `json:"nodes"` + RouteEdges []struct { + EdgeID string `json:"edgeId"` + FromNodeID string `json:"fromNodeId"` + ToNodeID string `json:"toNodeId"` + Label string `json:"label"` + } `json:"routeEdges"` + Candidates []struct { + CandidateID string `json:"candidateId"` + NodeID string `json:"nodeId"` + FieldRef string `json:"fieldRef"` + Select string `json:"select"` + LogicalType string `json:"logicalType"` + Filterable bool `json:"filterable"` + Chartable bool `json:"chartable"` + } `json:"candidates"` +} + +func main() { + configPath := flag.String("config", "", "legacy default ExplorerConfigV2 JSON") + catalogPath := flag.String("catalog", "", "pinned V1 authoring catalog JSON") + project := flag.String("project", "", "project identity") + bundlePath := flag.String("bundle", "", "output canonical authoring bundle JSON") + reportPath := flag.String("report", "", "output conversion report JSON") + flag.Parse() + if *configPath == "" || *catalogPath == "" || *project == "" || *bundlePath == "" || *reportPath == "" { + flag.Usage() + os.Exit(2) + } + config, err := os.ReadFile(*configPath) + if err != nil { + fail(err) + } + catalogRaw, err := os.ReadFile(*catalogPath) + if err != nil { + fail(err) + } + var wire pinnedCatalog + dec := json.NewDecoder(bytes.NewReader(catalogRaw)) + dec.DisallowUnknownFields() + if err := dec.Decode(&wire); err != nil { + fail(fmt.Errorf("decode pinned catalog: %w", err)) + } + var trailing any + if err := dec.Decode(&trailing); err != io.EOF { + fail(fmt.Errorf("pinned catalog has trailing JSON")) + } + catalog := explorer.Catalog{Selections: map[string]explorer.CatalogSelection{}} + for _, node := range wire.Nodes { + catalog.Nodes = append(catalog.Nodes, explorer.CatalogNode{ID: node.NodeID, ResourceType: node.ResourceType}) + } + for _, edge := range wire.RouteEdges { + catalog.Edges = append(catalog.Edges, explorer.CatalogEdge{ID: edge.EdgeID, FromNodeID: edge.FromNodeID, ToNodeID: edge.ToNodeID, Label: edge.Label}) + } + for _, candidate := range wire.Candidates { + catalog.Selections[candidate.CandidateID] = explorer.CatalogSelection{ID: candidate.CandidateID, NodeID: candidate.NodeID, FieldRef: candidate.FieldRef, Select: candidate.Select, LogicalType: candidate.LogicalType, Filterable: candidate.Filterable, Chartable: candidate.Chartable} + } + bundle, report, err := bootstrap.ConvertDefault(config, catalog, *project) + if err != nil { + writeReport(*reportPath, report) + fail(err) + } + canonical, err := bundle.CanonicalJSON() + if err != nil { + fail(err) + } + if err := os.WriteFile(*bundlePath, canonical, 0o644); err != nil { + fail(err) + } + writeReport(*reportPath, report) +} + +func writeReport(path string, report bootstrap.Report) { + raw, err := json.MarshalIndent(report, "", " ") + if err != nil { + fail(err) + } + if err := os.WriteFile(path, append(raw, '\n'), 0o644); err != nil { + fail(err) + } +} +func fail(err error) { _, _ = fmt.Fprintln(os.Stderr, err); os.Exit(1) } diff --git a/cmd/explorer-authoring-live-migrate/main.go b/cmd/explorer-authoring-live-migrate/main.go new file mode 100644 index 00000000..0cd60756 --- /dev/null +++ b/cmd/explorer-authoring-live-migrate/main.go @@ -0,0 +1,409 @@ +// Command explorer-authoring-live-migrate performs an explicit admin-only +// conversion of the active legacy Explorer packet into a V1 multi-output, +// multi-tab draft. It never activates or materializes the result. +// +// This is intentionally a best-effort bridge for the cutover. Legacy recipe +// transforms are lowered to their underlying catalog selection when possible; +// the report names every skipped or deduplicated field so the conversion is +// not mistaken for an exact legacy equivalence proof. +package main + +import ( + "bytes" + "encoding/json" + "errors" + "flag" + "fmt" + "io" + "net/http" + "os" + "sort" + "strings" + "time" + + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/explorer" +) + +type liveField struct { + Project string `json:"project"` + ResourceType string `json:"resource_type"` + Path string `json:"path"` + Kind string `json:"kind"` +} + +type liveSource struct { + Key string `json:"key"` + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + Title string `json:"title"` + SourceGeneration string `json:"sourceGeneration"` + DraftVersion int64 `json:"draftVersion"` + Config json.RawMessage `json:"config"` + Emitted []explorer.EmittedColumn `json:"emitted"` + Fields []liveField `json:"fields"` +} + +type migrationReport struct { + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + SourceGeneration string `json:"sourceGeneration"` + LegacyRevisionID string `json:"legacyRevisionId"` + LegacyOutputCount int `json:"legacyOutputCount"` + V1DocumentCount int `json:"v1DocumentCount"` + LegacyTabCount int `json:"legacyTabCount"` + V1TabCount int `json:"v1TabCount"` + ConvertedFields int `json:"convertedFields"` + ConvertedBindings int `json:"convertedBindings"` + DeduplicatedFields []string `json:"deduplicatedFields,omitempty"` + SkippedFields []string `json:"skippedFields,omitempty"` + SkippedBindings []string `json:"skippedBindings,omitempty"` + Exact bool `json:"exact"` + IntentDigest string `json:"intentDigest"` + Applied bool `json:"applied"` +} + +type cursorResponse struct { + Result []json.RawMessage `json:"result"` + Error bool `json:"error"` + ErrorMessage string `json:"errorMessage"` +} + +func main() { + url := flag.String("url", "http://127.0.0.1:18529", "ArangoDB base URL") + database := flag.String("database", "fhir_proto", "ArangoDB database") + project := flag.String("project", "HTAN_INT-BForePC", "Loom project") + explorerID := flag.String("explorer", "default", "Explorer identity") + apply := flag.Bool("apply", false, "write the V1 draft to loom_explorers") + flag.Parse() + + client := &http.Client{Timeout: 30 * time.Second} + source, err := loadSource(client, strings.TrimRight(*url, "/"), *database, *project, *explorerID) + if err != nil { + fail(err) + } + + bundle, report, err := convert(source) + if err != nil { + writeReport(report) + fail(err) + } + report.IntentDigest = bundle.IntentDigest + if *apply { + if err := applyDraft(client, strings.TrimRight(*url, "/"), *database, source, bundle); err != nil { + writeReport(report) + fail(err) + } + report.Applied = true + } + writeReport(report) + canonical, err := bundle.CanonicalJSON() + if err != nil { + fail(err) + } + _, _ = os.Stdout.Write(canonical) + _, _ = os.Stdout.Write([]byte("\n")) +} + +func loadSource(client *http.Client, baseURL, database, project, explorerID string) (liveSource, error) { + query := `LET owner = FIRST(FOR d IN loom_explorers FILTER d.project == @project AND d.explorerId == @explorerId RETURN d) +LET revision = owner == null OR owner.activeRevisionId == null ? null : DOCUMENT("loom_explorer_revisions", owner.activeRevisionId) +LET fields = (FOR d IN fhir_field_catalog FILTER d.project == @project RETURN KEEP(d, "project", "resource_type", "path", "kind")) +FILTER owner != null +RETURN {key: owner._key, project: owner.project, explorerId: owner.explorerId, title: owner.activeConfig.explorer.title, sourceGeneration: owner.sourceGeneration, draftVersion: owner.draftVersion, config: owner.activeConfig, emitted: revision == null ? [] : revision.emittedColumns, fields: fields}` + rows, err := runAQL(client, baseURL, database, query, map[string]any{"project": project, "explorerId": explorerID}) + if err != nil { + return liveSource{}, err + } + if len(rows) != 1 { + return liveSource{}, fmt.Errorf("expected one active Explorer source, got %d", len(rows)) + } + var source liveSource + if err := json.Unmarshal(rows[0], &source); err != nil { + return liveSource{}, fmt.Errorf("decode live Explorer source: %w", err) + } + return source, nil +} + +func convert(source liveSource) (explorer.ExplorerAuthoringBundleV1, migrationReport, error) { + var config explorer.ConfigV2 + if err := json.Unmarshal(source.Config, &config); err != nil { + return explorer.ExplorerAuthoringBundleV1{}, migrationReport{}, fmt.Errorf("decode active ExplorerConfigV2: %w", err) + } + var legacy recipe.Bundle + if err := json.Unmarshal(config.Recipe, &legacy); err != nil { + return explorer.ExplorerAuthoringBundleV1{}, migrationReport{}, fmt.Errorf("decode active recipe: %w", err) + } + report := migrationReport{Project: source.Project, ExplorerID: source.ExplorerID, SourceGeneration: source.SourceGeneration, LegacyRevisionID: "active", LegacyOutputCount: len(legacy.Outputs), LegacyTabCount: len(config.Views), Exact: false} + + catalog := make(map[string]liveField, len(source.Fields)) + for _, field := range source.Fields { + if field.ResourceType == "" || field.Path == "" { + continue + } + key := field.ResourceType + "\x00" + field.Path + if _, exists := catalog[key]; !exists { + catalog[key] = field + } + } + emittedByOutputPublic := map[string]map[string]explorer.EmittedColumn{} + for _, emitted := range source.Emitted { + if emittedByOutputPublic[emitted.OutputID] == nil { + emittedByOutputPublic[emitted.OutputID] = map[string]explorer.EmittedColumn{} + } + emittedByOutputPublic[emitted.OutputID][emitted.PublicColumn] = emitted + } + + documents := make([]explorer.ExplorerBuilderDocumentV1, 0, len(legacy.Outputs)) + documentsByLegacyOutput := map[string]int{} + pathsByOutput := map[string]map[string]string{} + for _, output := range legacy.Outputs { + outputID := explorer.StableExplorerID(output.Name) + nodeID := explorer.OpaqueID("n_", output.RootResourceType) + document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: outputID, Title: output.Name}, BaseNodeID: nodeID, RowNodeID: nodeID, Presentation: map[string]explorer.ExplorerPresentationBindingV1{}} + pathsByOutput[output.Name] = map[string]string{} + for _, field := range output.Fields { + path, ok := firstSelectionPath(field.Expr) + if !ok || strings.HasPrefix(path, "route_") { + report.SkippedFields = append(report.SkippedFields, output.Name+"."+field.Name) + continue + } + path = strings.TrimPrefix(path, "root.") + key := output.RootResourceType + "\x00" + path + catalogField, ok := catalog[key] + if !ok { + report.SkippedFields = append(report.SkippedFields, output.Name+"."+field.Name) + continue + } + candidateID := explorer.OpaqueID("s_", catalogField.ResourceType+"\x00"+catalogField.Path) + if addCandidate(&document, candidateID) { + report.ConvertedFields++ + } else { + report.DeduplicatedFields = append(report.DeduplicatedFields, output.Name+"."+field.Name) + } + pathsByOutput[output.Name][field.Name] = path + } + documentsByLegacyOutput[output.Name] = len(documents) + documents = append(documents, document) + } + + tabs := make([]explorer.ExplorerTabV1, 0, len(config.Views)) + for index, view := range config.Views { + documentIndex, ok := documentsByLegacyOutput[view.Output] + if !ok { + report.SkippedBindings = append(report.SkippedBindings, view.ID+":unknown-output") + continue + } + document := &documents[documentIndex] + output := legacy.Outputs[documentIndex] + outputPaths := pathsByOutput[view.Output] + for columnIndex, column := range view.Table.Columns { + path, ok := outputPaths[column.Column] + if !ok { + if emitted, exists := emittedByOutputPublic[view.Output][column.Column]; exists { + path, ok = selectionPath(output.RootResourceType, emitted.SelectionID) + } + } + candidateID, ok := candidateForPath(catalog, output.RootResourceType, path) + if !ok { + report.SkippedBindings = append(report.SkippedBindings, view.ID+"."+column.Column) + continue + } + if !addCandidate(document, candidateID) { + report.DeduplicatedFields = append(report.DeduplicatedFields, view.ID+"."+column.Column) + } + emissionID := explorer.OpaqueID("em_", document.Output.ID+"\x00base\x00"+candidateID) + binding := document.Presentation[emissionID] + binding.Label = firstNonEmpty(column.Label, column.Column) + visible := column.Visible + binding.Visible = &visible + order := columnIndex + binding.Order = &order + document.Presentation[emissionID] = binding + report.ConvertedBindings++ + } + for _, filter := range view.Filters { + path := outputPaths[filter.Column] + if path == "" { + if emitted, exists := emittedByOutputPublic[view.Output][filter.Column]; exists { + path, _ = selectionPath(output.RootResourceType, emitted.SelectionID) + } + } + candidateID, ok := candidateForPath(catalog, output.RootResourceType, path) + if !ok || !presentationCandidate(catalog, output.RootResourceType, path) { + report.SkippedBindings = append(report.SkippedBindings, view.ID+".filter."+filter.Column) + continue + } + addCandidate(document, candidateID) + emissionID := explorer.OpaqueID("em_", document.Output.ID+"\x00base\x00"+candidateID) + binding := document.Presentation[emissionID] + binding.Filter = &explorer.ExplorerFilterBindingV1{Label: filter.Label} + document.Presentation[emissionID] = binding + } + for _, chart := range view.Charts { + path := outputPaths[chart.Column] + if path == "" { + if emitted, exists := emittedByOutputPublic[view.Output][chart.Column]; exists { + path, _ = selectionPath(output.RootResourceType, emitted.SelectionID) + } + } + candidateID, ok := candidateForPath(catalog, output.RootResourceType, path) + if !ok || !presentationCandidate(catalog, output.RootResourceType, path) { + report.SkippedBindings = append(report.SkippedBindings, view.ID+".chart."+chart.Column) + continue + } + addCandidate(document, candidateID) + emissionID := explorer.OpaqueID("em_", document.Output.ID+"\x00base\x00"+candidateID) + binding := document.Presentation[emissionID] + binding.Chart = &explorer.ExplorerChartBindingV1{Type: chart.Type, Title: chart.Title} + document.Presentation[emissionID] = binding + } + tabs = append(tabs, explorer.ExplorerTabV1{ID: explorer.StableExplorerID(view.ID), Title: view.Title, OutputID: document.Output.ID, Order: index}) + } + for i := range documents { + sort.Strings(documents[i].CandidateIDs) + } + bundle := explorer.ExplorerAuthoringBundleV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, Project: source.Project, ExplorerID: source.ExplorerID, Title: source.Title, Documents: documents, Tabs: tabs} + canonical, err := bundle.CanonicalJSON() + if err != nil { + return explorer.ExplorerAuthoringBundleV1{}, report, fmt.Errorf("canonicalize manual V1 bundle: %w", err) + } + if err := json.Unmarshal(canonical, &bundle); err != nil { + return explorer.ExplorerAuthoringBundleV1{}, report, fmt.Errorf("normalize manual V1 bundle: %w", err) + } + bundle.IntentDigest, err = bundle.DocumentDigest() + if err != nil { + return explorer.ExplorerAuthoringBundleV1{}, report, err + } + report.V1DocumentCount = len(bundle.AuthoringDocuments()) + report.V1TabCount = len(bundle.Tabs) + return bundle, report, nil +} + +func firstSelectionPath(expression recipe.Expression) (string, bool) { + if expression.Select != "" { + return expression.Select, true + } + for _, argument := range expression.Args { + if argument.Select != "" { + return argument.Select, true + } + } + return "", false +} + +func selectionPath(rootResourceType, selectionID string) (string, bool) { + selectionID = strings.TrimSpace(strings.SplitN(selectionID, "#", 2)[0]) + prefix, path, ok := strings.Cut(selectionID, ".") + if !ok || prefix != rootResourceType || path == "" { + return "", false + } + return path, true +} + +func candidateForPath(catalog map[string]liveField, resourceType, path string) (string, bool) { + path = strings.TrimPrefix(strings.TrimSpace(path), "root.") + if path == "" { + return "", false + } + field, ok := catalog[resourceType+"\x00"+path] + if !ok { + return "", false + } + return explorer.OpaqueID("s_", field.ResourceType+"\x00"+field.Path), true +} + +func presentationCandidate(catalog map[string]liveField, resourceType, path string) bool { + path = strings.TrimPrefix(strings.TrimSpace(path), "root.") + field, ok := catalog[resourceType+"\x00"+path] + return ok && field.Kind != "object" && field.Kind != "array" +} + +func addCandidate(document *explorer.ExplorerBuilderDocumentV1, candidateID string) bool { + for _, existing := range document.CandidateIDs { + if existing == candidateID { + return false + } + } + document.CandidateIDs = append(document.CandidateIDs, candidateID) + return true +} + +func applyDraft(client *http.Client, baseURL, database string, source liveSource, bundle explorer.ExplorerAuthoringBundleV1) error { + canonical, err := bundle.CanonicalJSON() + if err != nil { + return err + } + var bundleObject map[string]any + if err := json.Unmarshal(canonical, &bundleObject); err != nil { + return err + } + query := `FOR d IN loom_explorers +FILTER d._key == @key AND d.project == @project AND d.explorerId == @explorerId AND d.draftVersion == @expectedVersion +UPDATE d WITH {draftVersion: d.draftVersion + 1, draftAuthoringBundle: @bundle, draftIntentDigest: @digest, draftDigest: @digest, draftReceiptId: null, draftIdentityMappings: [], diagnostics: @diagnostics, updatedBy: @actor, updatedAt: @updatedAt} IN loom_explorers +RETURN NEW` + rows, err := runAQL(client, baseURL, database, query, map[string]any{ + "key": source.Key, "project": source.Project, "explorerId": source.ExplorerID, + "expectedVersion": source.DraftVersion, "bundle": bundleObject, "digest": bundle.IntentDigest, + "diagnostics": []map[string]any{{"severity": "WARN", "stage": "migration", "code": "MANUAL_AUTHORING_MIGRATION", "message": "draft created by the live best-effort legacy conversion; inspect the migration report before compiling or publishing"}}, + "actor": "manual-authoring-migration", "updatedAt": time.Now().UTC().Format(time.RFC3339Nano), + }) + if err != nil { + return err + } + if len(rows) != 1 { + return errors.New("draft changed during manual migration; no write was applied") + } + return nil +} + +func runAQL(client *http.Client, baseURL, database, query string, bindVars map[string]any) ([]json.RawMessage, error) { + body, err := json.Marshal(map[string]any{"query": query, "bindVars": bindVars}) + if err != nil { + return nil, err + } + request, err := http.NewRequest(http.MethodPost, baseURL+"/_db/"+database+"/_api/cursor", bytes.NewReader(body)) + if err != nil { + return nil, err + } + request.Header.Set("Content-Type", "application/json") + response, err := client.Do(request) + if err != nil { + return nil, err + } + defer response.Body.Close() + raw, err := io.ReadAll(response.Body) + if err != nil { + return nil, err + } + if response.StatusCode < 200 || response.StatusCode >= 300 { + return nil, fmt.Errorf("Arango query returned %s: %s", response.Status, strings.TrimSpace(string(raw))) + } + var result cursorResponse + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + if result.Error { + return nil, errors.New(result.ErrorMessage) + } + return result.Result, nil +} + +func firstNonEmpty(values ...string) string { + for _, value := range values { + if strings.TrimSpace(value) != "" { + return value + } + } + return "Explorer" +} + +func writeReport(report migrationReport) { + raw, _ := json.MarshalIndent(report, "", " ") + _, _ = os.Stderr.Write(append(raw, '\n')) +} + +func fail(err error) { + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) +} diff --git a/cmd/generate/extraction.go b/cmd/generate/extraction.go index 7c307cc6..e1388243 100644 --- a/cmd/generate/extraction.go +++ b/cmd/generate/extraction.go @@ -23,6 +23,7 @@ func generateExtract(schema *Schema, path string) error { sb.WriteString("\t\"sync\"\n") sb.WriteString("\t\"github.com/google/uuid\"\n") sb.WriteString("\t\"github.com/bytedance/sonic\"\n") + sb.WriteString("\tfhirschema \"github.com/calypr/loom/internal/fhir/schema\"\n") sb.WriteString(")\n\n") // 1. Write EdgeDocument struct definition @@ -158,14 +159,6 @@ func splitFHIRReference(ref string) (string, string, bool) { return targetType, targetID, true } -func targetTypeFromLabel(label string) string { - parts := strings.Split(label, "_") - if len(parts) == 0 { - return "" - } - return parts[len(parts)-1] -} - func buildEdgeRawJSON(key, from, to, label, projectJSON, fromType, toType string) json.RawMessage { var buf bytes.Buffer buf.Grow(256) @@ -201,13 +194,10 @@ func buildEdgeRawJSON(key, from, to, label, projectJSON, fromType, toType string for _, k := range keys { def := schema.Defs[k] - // Check if it's a top-level resource (typically has resourceType const) - var hasResourceType bool - if prop, ok := def.Properties["resourceType"]; ok && prop.Const != nil { - hasResourceType = true - } - - if !hasResourceType { + // Only concrete FHIR roots get graph loaders. Backbone definitions and + // abstract Resource remain available to field/selector generation but + // never become graph collections or row grains. + if !isFHIRRootResourceDefinition(k, def) { continue } @@ -288,6 +278,8 @@ func generateTraversalCode(schema *Schema, structName string, path []string, var sb.WriteString(fmt.Sprintf("%srefVal := %s\n", indent, varName)) sb.WriteString(fmt.Sprintf("%srefType, targetID, ok := splitFHIRReference(refVal)\n", indent)) sb.WriteString(fmt.Sprintf("%sif ok {\n", indent)) + sb.WriteString(fmt.Sprintf("%s\trefType, ok = fhirschema.ConcreteResourceType(refType)\n", indent)) + sb.WriteString(fmt.Sprintf("%s\tif ok {\n", indent)) // Match prefix check allowAnyMatch := false @@ -300,62 +292,56 @@ func generateTraversalCode(schema *Schema, structName string, path []string, var } } + bodyIndent := indent + "\t\t" if !allowAnyMatch && matchPrefix != "" { - sb.WriteString(fmt.Sprintf("%s\tif refType == %q {\n", indent, matchPrefix)) - indent += "\t" + sb.WriteString(fmt.Sprintf("%sif refType == %q {\n", bodyIndent, matchPrefix)) + bodyIndent += "\t" } - // Calculate UUIDs and append EdgeDocuments. Most generated forward edge - // targets retain the long-standing label-derived convention. The one - // compiler-owned exception is ResearchSubject.study: its bare label - // cannot encode a target type, while the checked-in schema proves its - // concrete ResearchStudy target. Keep this narrow until each other bare - // label has an equivalent storage-route proof. - forwardTargetType := generatedForwardTargetType(structName, link) - sb.WriteString(fmt.Sprintf("%s\tforwardKey := getEdgeUUID(targetID, id, %q)\n", indent, link.Rel)) - sb.WriteString(fmt.Sprintf("%s\tif seen == nil {\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t\tseen = make(map[string]struct{}, 4)\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t}\n", indent)) - sb.WriteString(fmt.Sprintf("%s\tif _, exists := seen[forwardKey]; !exists {\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t\tseen[forwardKey] = struct{}{}\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t\tedges = append(edges, buildEdgeRawJSON(\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t\t\tforwardKey,\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t\t\tcollectionID(sourceType, id),\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t\t\tcollectionID(%q, targetID),\n", indent, forwardTargetType)) - sb.WriteString(fmt.Sprintf("%s\t\t\t%q,\n", indent, link.Rel)) - sb.WriteString(fmt.Sprintf("%s\t\t\tprojectJSON,\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t\t\tsourceType,\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t\t\t%q,\n", indent, forwardTargetType)) - sb.WriteString(fmt.Sprintf("%s\t\t))\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t}\n", indent)) + sb.WriteString(fmt.Sprintf("%sforwardKey := getEdgeUUID(targetID, id, %q)\n", bodyIndent, link.Rel)) + sb.WriteString(fmt.Sprintf("%sif seen == nil {\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\tseen = make(map[string]struct{}, 4)\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s}\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%sif _, exists := seen[forwardKey]; !exists {\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\tseen[forwardKey] = struct{}{}\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\tedges = append(edges, buildEdgeRawJSON(\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\t\tforwardKey,\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\t\tcollectionID(sourceType, id),\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\t\tcollectionID(refType, targetID),\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\t\t%q,\n", bodyIndent, link.Rel)) + sb.WriteString(fmt.Sprintf("%s\t\tprojectJSON,\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\t\tsourceType,\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\t\trefType,\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\t))\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s}\n", bodyIndent)) // Check if backref exists if len(link.TargetHints.Backref) > 0 && link.TargetHints.Backref[0] != "" { backref := link.TargetHints.Backref[0] - backrefTargetType := targetTypeFromLabel(backref) - sb.WriteString(fmt.Sprintf("%s\tbackrefKey := getEdgeUUID(id, targetID, %q)\n", indent, backref)) - sb.WriteString(fmt.Sprintf("%s\tif seen == nil {\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t\tseen = make(map[string]struct{}, 4)\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t}\n", indent)) - sb.WriteString(fmt.Sprintf("%s\tif _, exists := seen[backrefKey]; !exists {\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t\tseen[backrefKey] = struct{}{}\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t\tedges = append(edges, buildEdgeRawJSON(\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t\t\tbackrefKey,\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t\t\tcollectionID(sourceType, targetID),\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t\t\tcollectionID(%q, id),\n", indent, backrefTargetType)) - sb.WriteString(fmt.Sprintf("%s\t\t\t%q,\n", indent, backref)) - sb.WriteString(fmt.Sprintf("%s\t\t\tprojectJSON,\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t\t\tsourceType,\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t\t\t%q,\n", indent, backrefTargetType)) - sb.WriteString(fmt.Sprintf("%s\t\t))\n", indent)) - sb.WriteString(fmt.Sprintf("%s\t}\n", indent)) + sb.WriteString(fmt.Sprintf("%sbackrefKey := getEdgeUUID(id, targetID, %q)\n", bodyIndent, backref)) + sb.WriteString(fmt.Sprintf("%sif seen == nil {\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\tseen = make(map[string]struct{}, 4)\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s}\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%sif _, exists := seen[backrefKey]; !exists {\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\tseen[backrefKey] = struct{}{}\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\tedges = append(edges, buildEdgeRawJSON(\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\t\tbackrefKey,\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\t\tcollectionID(refType, targetID),\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\t\tcollectionID(sourceType, id),\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\t\t%q,\n", bodyIndent, backref)) + sb.WriteString(fmt.Sprintf("%s\t\tprojectJSON,\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\t\trefType,\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\t\tsourceType,\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s\t))\n", bodyIndent)) + sb.WriteString(fmt.Sprintf("%s}\n", bodyIndent)) } if !allowAnyMatch && matchPrefix != "" { - indent = indent[:len(indent)-1] - sb.WriteString(fmt.Sprintf("%s\t}\n", indent)) + bodyIndent = bodyIndent[:len(bodyIndent)-1] + sb.WriteString(fmt.Sprintf("%s}\n", bodyIndent)) } + sb.WriteString(fmt.Sprintf("%s\t}\n", indent)) sb.WriteString(fmt.Sprintf("%s}\n", indent)) return sb.String(), nil } diff --git a/cmd/generate/extraction_test.go b/cmd/generate/extraction_test.go index c6c0718f..e51b06a1 100644 --- a/cmd/generate/extraction_test.go +++ b/cmd/generate/extraction_test.go @@ -7,7 +7,7 @@ import ( "testing" ) -func TestGenerateExtractUsesSchemaTargetTypeForResearchSubjectStudy(t *testing.T) { +func TestGenerateExtractUsesRuntimeConcreteReferenceType(t *testing.T) { schema := loadCheckedInGraphFHIRSchema(t) generatedPath := filepath.Join(t.TempDir(), "extract.go") if err := generateExtract(schema, generatedPath); err != nil { @@ -27,10 +27,37 @@ func TestGenerateExtractUsesSchemaTargetTypeForResearchSubjectStudy(t *testing.T if next := strings.Index(section[len(signature):], "// ExtractEdges extracts graph links from "); next >= 0 { section = section[:len(signature)+next] } - if !strings.Contains(section, `collectionID("ResearchStudy", targetID)`) || !strings.Contains(section, `"ResearchStudy",`) { - t.Fatalf("ResearchSubject.study forward edge did not use its schema target type:\n%s", section) + if !strings.Contains(section, `refType, ok = fhirschema.ConcreteResourceType(refType)`) { + t.Fatalf("generated extractor does not validate runtime reference types:\n%s", section) } - if strings.Contains(section, `collectionID("study", targetID)`) { - t.Fatalf("ResearchSubject.study forward edge derived target collection from bare label:\n%s", section) + if !strings.Contains(section, `collectionID(refType, targetID)`) { + t.Fatalf("generated extractor does not use the concrete runtime target type:\n%s", section) + } + if !strings.Contains(section, `seen[backrefKey] = struct{}{}`) { + t.Fatalf("generated extractor does not deduplicate repeated backreferences:\n%s", section) + } + if strings.Contains(section, `collectionID("study", targetID)`) || strings.Contains(section, `collectionID("ResearchStudy", targetID)`) { + t.Fatalf("ResearchSubject.study forward edge still hard-codes a label-derived target collection:\n%s", section) + } +} + +func TestGenerateExtractEmitsOnlyConcreteRootLoaders(t *testing.T) { + schema := loadCheckedInGraphFHIRSchema(t) + generatedPath := filepath.Join(t.TempDir(), "extract.go") + if err := generateExtract(schema, generatedPath); err != nil { + t.Fatalf("generate FHIR edge extractor: %v", err) + } + generated, err := os.ReadFile(generatedPath) + if err != nil { + t.Fatalf("read generated FHIR edge extractor: %v", err) + } + text := string(generated) + for _, resourceType := range []string{"Resource", "PatientContact", "PractitionerQualification", "OrganizationQualification"} { + if strings.Contains(text, "ExtractEdges extracts graph links from "+resourceType) { + t.Fatalf("generated extractor emitted non-resource definition %s", resourceType) + } + } + if !strings.Contains(text, "ExtractEdges extracts graph links from Practitioner") { + t.Fatal("generated extractor omitted concrete Practitioner root") } } diff --git a/cmd/generate/metadata.go b/cmd/generate/metadata.go index 56c81a92..0c836e06 100644 --- a/cmd/generate/metadata.go +++ b/cmd/generate/metadata.go @@ -37,15 +37,12 @@ func generateFHIRSchema(schema *Schema, path string) error { seenTraversalKeys := map[string]struct{}{} for _, k := range keys { def := schema.Defs[k] - if def == nil || len(def.Links) == 0 { + if !isFHIRRootResourceDefinition(k, def) || len(def.Links) == 0 { continue } for _, link := range def.Links { - toType := refName(link.TargetSchema.Ref) - if strings.TrimSpace(toType) == "" { - toType = targetTypeFromLabel(link.Rel) - } - if strings.TrimSpace(link.Rel) == "" || strings.TrimSpace(toType) == "" { + toType, ok := schemaConcreteLinkTargetType(schema, link) + if strings.TrimSpace(link.Rel) == "" || !ok { continue } forwardKey := traversalKey(k, link.Rel, toType) @@ -64,6 +61,33 @@ func generateFHIRSchema(schema *Schema, path string) error { return os.WriteFile(path, []byte(sb.String()), 0644) } +// schemaConcreteLinkTargetType resolves a graph link target from schema +// semantics. Relationship labels are only a compatibility fallback for older +// schema entries; the fallback is accepted only when it resolves to a +// concrete root, so labels can never introduce a graph node by themselves. +func schemaConcreteLinkTargetType(schema *Schema, link Link) (string, bool) { + candidates := []string{refName(link.TargetSchema.Ref)} + if candidates[0] == "" { + for _, regex := range link.TargetHints.RegexMatch { + candidate := strings.TrimSuffix(strings.TrimSpace(regex), "/*") + if candidate != "" { + candidates = append(candidates, candidate) + } + } + candidates = append(candidates, targetTypeFromLabel(link.Rel)) + } + for _, candidate := range candidates { + candidate = strings.TrimSpace(candidate) + if candidate == "" { + continue + } + if isFHIRRootResourceDefinition(candidate, schema.Defs[candidate]) { + return candidate, true + } + } + return "", false +} + // schemaFHIRRootResourceTypes discovers compiler-visible collections from the // checked-in graph schema. It deliberately does not carry a copied list of // FHIR resource names: a schema definition is a concrete root only when its diff --git a/cmd/generate/metadata_test.go b/cmd/generate/metadata_test.go index af15bd08..e242b9b9 100644 --- a/cmd/generate/metadata_test.go +++ b/cmd/generate/metadata_test.go @@ -56,3 +56,27 @@ func TestFHIRSchemaMetadataGenerationMatchesCheckedInArtifact(t *testing.T) { t.Fatal("checked-in generated/fhirschema/generated.go is stale; run make generate-fhir") } } + +func TestFHIRSchemaMetadataOmitsNonResourceTraversals(t *testing.T) { + schema := loadCheckedInGraphFHIRSchema(t) + generatedPath := filepath.Join(t.TempDir(), "generated.go") + if err := generateFHIRSchema(schema, generatedPath); err != nil { + t.Fatalf("generate FHIR schema metadata: %v", err) + } + got, err := os.ReadFile(generatedPath) + if err != nil { + t.Fatalf("read generated metadata: %v", err) + } + for _, key := range []string{ + `"PractitionerQualification|issuer|Organization"`, + `"Organization|issuer|PractitionerQualification"`, + `"OrganizationQualification|issuer|Organization"`, + } { + if bytes.Contains(got, []byte(key)) { + t.Fatalf("generated traversal metadata contains non-resource key %s", key) + } + } + if !bytes.Contains(got, []byte(`"Practitioner|qualification_issuer|Organization"`)) { + t.Fatalf("generated traversal metadata omitted valid Practitioner relationship") + } +} diff --git a/cmd/generate/names.go b/cmd/generate/names.go index f2d0979c..48af45ea 100644 --- a/cmd/generate/names.go +++ b/cmd/generate/names.go @@ -15,17 +15,6 @@ func targetTypeFromLabel(label string) string { return parts[len(parts)-1] } -func generatedForwardTargetType(structName string, link Link) string { - labelTargetType := targetTypeFromLabel(link.Rel) - if strings.TrimSpace(structName) != "ResearchSubject" || strings.TrimSpace(link.Rel) != "study" { - return labelTargetType - } - if targetType := refName(link.TargetSchema.Ref); targetType == "ResearchStudy" { - return targetType - } - return labelTargetType -} - func toGoName(s string) string { if s == "" { return "" diff --git a/generated/fhir/extract.go b/generated/fhir/extract.go index 78926bb0..7802655d 100644 --- a/generated/fhir/extract.go +++ b/generated/fhir/extract.go @@ -8,6 +8,7 @@ import ( "encoding/json" "fmt" "github.com/bytedance/sonic" + fhirschema "github.com/calypr/loom/internal/fhir/schema" "github.com/google/uuid" "hash" "strconv" @@ -147,14 +148,6 @@ func splitFHIRReference(ref string) (string, string, bool) { return targetType, targetID, true } -func targetTypeFromLabel(label string) string { - parts := strings.Split(label, "_") - if len(parts) == 0 { - return "" - } - return parts[len(parts)-1] -} - func buildEdgeRawJSON(key, from, to, label, projectJSON, fromType, toType string) json.RawMessage { var buf bytes.Buffer buf.Grow(256) @@ -176,293 +169,6 @@ func buildEdgeRawJSON(key, from, to, label, projectJSON, fromType, toType string return json.RawMessage(buf.Bytes()) } -// ExtractEdges extracts graph links from Address. -func (x *Address) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Address" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from Age. -func (x *Age) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Age" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from Annotation. -func (x *Annotation) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Annotation" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.AuthorReference != nil { - if x.AuthorReference.Reference != nil { - refVal := *x.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "authorReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "authorReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - if x.AuthorReference != nil { - if x.AuthorReference.Reference != nil { - refVal := *x.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "authorReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "authorReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - if x.AuthorReference != nil { - if x.AuthorReference.Reference != nil { - refVal := *x.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - if x.AuthorReference != nil { - if x.AuthorReference.Reference != nil { - refVal := *x.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from Attachment. -func (x *Attachment) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Attachment" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from Availability. -func (x *Availability) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Availability" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from AvailabilityAvailableTime. -func (x *AvailabilityAvailableTime) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "AvailabilityAvailableTime" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from AvailabilityNotAvailableTime. -func (x *AvailabilityNotAvailableTime) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "AvailabilityNotAvailableTime" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - // ExtractEdges extracts graph links from BodyStructure. func (x *BodyStructure) ExtractEdges(project string) ([]json.RawMessage, error) { var edges []json.RawMessage @@ -482,38 +188,41 @@ func (x *BodyStructure) ExtractEdges(project string) ([]json.RawMessage, error) refVal := *x.Patient.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("patient", targetID), - "patient", - projectJSON, - sourceType, - "patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "body_structure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("structure", id), - "body_structure", - projectJSON, - sourceType, - "structure", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "body_structure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "body_structure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -522,94 +231,153 @@ func (x *BodyStructure) ExtractEdges(project string) ([]json.RawMessage, error) return edges, nil } -// ExtractEdges extracts graph links from BodyStructureIncludedStructure. -func (x *BodyStructureIncludedStructure) ExtractEdges(project string) ([]json.RawMessage, error) { +// ExtractEdges extracts graph links from Condition. +func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { var edges []json.RawMessage if x == nil || x.ID == nil { return edges, nil } id := *x.ID - sourceType := "BodyStructureIncludedStructure" + sourceType := "Condition" projectJSON := strconv.Quote(project) _ = id _ = sourceType _ = projectJSON var seen map[string]struct{} _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from BodyStructureIncludedStructureBodyLandmarkOrientation. -func (x *BodyStructureIncludedStructureBodyLandmarkOrientation) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "subject_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "condition", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } } - id := *x.ID - sourceType := "BodyStructureIncludedStructureBodyLandmarkOrientation" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark. -func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "subject_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "condition", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } } - id := *x.ID - sourceType := "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "device_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -618,46 +386,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "device_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -666,46 +437,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "device_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -714,46 +488,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "device_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -762,46 +539,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "device_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -810,46 +590,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "device_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -858,46 +641,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "device_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -906,46 +692,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "device_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -954,46 +743,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "device_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -1002,46 +794,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "device_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -1050,46 +845,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "device_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -1098,46 +896,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "device_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -1146,46 +947,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "device_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -1194,46 +998,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "device_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -1242,46 +1049,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "device_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -1290,46 +1100,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "device_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -1338,46 +1151,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "device_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -1386,46 +1202,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "device_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -1434,46 +1253,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "device_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -1482,46 +1304,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "device_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -1530,46 +1355,49 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "device_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -1578,46 +1406,202 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "device_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) + } + } + } + } + } + } + } + if x.Evidence != nil { + for _, item_3_x_Evidence := range x.Evidence { + if item_3_x_Evidence != nil { + if item_3_x_Evidence.Reference != nil { + if item_3_x_Evidence.Reference.Reference != nil { + refVal := *item_3_x_Evidence.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "evidence_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "evidence_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) + } + } + } + } + } + } + } + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + } + } + } + } + } + } + } + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -1626,46 +1610,202 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "device_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) + } + } + } + } + } + } + } + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) + } + } + } + } + } + } + } + if x.Participant != nil { + for _, item_3_x_Participant := range x.Participant { + if item_3_x_Participant != nil { + if item_3_x_Participant.Actor != nil { + if item_3_x_Participant.Actor.Reference != nil { + refVal := *item_3_x_Participant.Actor.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "participant_actor_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "participant_actor_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "condition_participant") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "condition_participant", + projectJSON, + refType, + sourceType, + )) + } } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + } + } + } + } + } + } + } + if x.Participant != nil { + for _, item_3_x_Participant := range x.Participant { + if item_3_x_Participant != nil { + if item_3_x_Participant.Actor != nil { + if item_3_x_Participant.Actor.Reference != nil { + refVal := *item_3_x_Participant.Actor.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "participant_actor_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "participant_actor_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "condition_participant") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "condition_participant", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -1674,1134 +1814,246 @@ func (x *BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandma } } } - return edges, nil -} - -// ExtractEdges extracts graph links from CodeableConcept. -func (x *CodeableConcept) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil + if x.Participant != nil { + for _, item_3_x_Participant := range x.Participant { + if item_3_x_Participant != nil { + if item_3_x_Participant.Actor != nil { + if item_3_x_Participant.Actor.Reference != nil { + refVal := *item_3_x_Participant.Actor.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "participant_actor_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "participant_actor_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "condition_participant") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "condition_participant", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } } - id := *x.ID - sourceType := "CodeableConcept" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from CodeableReference. -func (x *CodeableReference) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil + if x.Participant != nil { + for _, item_3_x_Participant := range x.Participant { + if item_3_x_Participant != nil { + if item_3_x_Participant.Actor != nil { + if item_3_x_Participant.Actor.Reference != nil { + refVal := *item_3_x_Participant.Actor.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "participant_actor_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "participant_actor_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "condition_participant") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "condition_participant", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } } - id := *x.ID - sourceType := "CodeableReference" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Stage != nil { + for _, item_4_x_Stage := range x.Stage { + if item_4_x_Stage != nil { + if item_4_x_Stage.Assessment != nil { + for _, item_2_item_4_x_Stage_Assessment := range item_4_x_Stage.Assessment { + if item_2_item_4_x_Stage_Assessment != nil { + if item_2_item_4_x_Stage_Assessment.Reference != nil { + refVal := *item_2_item_4_x_Stage_Assessment.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "stage_assessment_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "stage_assessment_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "assessment_condition_stage") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "assessment_condition_stage", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } } } } } } - return edges, nil -} - -// ExtractEdges extracts graph links from Coding. -func (x *Coding) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil + if x.Stage != nil { + for _, item_4_x_Stage := range x.Stage { + if item_4_x_Stage != nil { + if item_4_x_Stage.Assessment != nil { + for _, item_2_item_4_x_Stage_Assessment := range item_4_x_Stage.Assessment { + if item_2_item_4_x_Stage_Assessment != nil { + if item_2_item_4_x_Stage_Assessment.Reference != nil { + refVal := *item_2_item_4_x_Stage_Assessment.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "stage_assessment_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "stage_assessment_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "assessment_condition_stage") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "assessment_condition_stage", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + } } - id := *x.ID - sourceType := "Coding" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen return edges, nil } -// ExtractEdges extracts graph links from Condition. -func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { +// ExtractEdges extracts graph links from DiagnosticReport. +func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, error) { var edges []json.RawMessage if x == nil || x.ID == nil { return edges, nil } id := *x.ID - sourceType := "Condition" + sourceType := "DiagnosticReport" projectJSON := strconv.Quote(project) _ = id _ = sourceType _ = projectJSON var seen map[string]struct{} _ = seen - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "subject_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "subject_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("condition", id), - "condition", - projectJSON, - sourceType, - "condition", - )) - } - } - } - } - } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "subject_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "subject_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("condition", id), - "condition", - projectJSON, - sourceType, - "condition", - )) - } - } - } - } - } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Organization") + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_MedicationRequest") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -2810,14 +2062,14 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Organization", targetID), - "evidence_reference_Organization", + collectionID(refType, targetID), + "basedOn_MedicationRequest", projectJSON, sourceType, - "Organization", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "basedOn_diagnostic_report") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -2825,12 +2077,12 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_diagnostic_report", projectJSON, + refType, sourceType, - "reference", )) } } @@ -2840,16 +2092,17 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Performer != nil { + for _, item_2_x_Performer := range x.Performer { + if item_2_x_Performer != nil { + if item_2_x_Performer.Reference != nil { + refVal := *item_2_x_Performer.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Group") + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "performer_Practitioner") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -2858,14 +2111,14 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Group", targetID), - "evidence_reference_Group", + collectionID(refType, targetID), + "performer_Practitioner", projectJSON, sourceType, - "Group", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "performer_diagnostic_report") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -2873,12 +2126,12 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "performer_diagnostic_report", projectJSON, + refType, sourceType, - "reference", )) } } @@ -2888,16 +2141,17 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Performer != nil { + for _, item_2_x_Performer := range x.Performer { + if item_2_x_Performer != nil { + if item_2_x_Performer.Reference != nil { + refVal := *item_2_x_Performer.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Practitioner") + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "performer_PractitionerRole") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -2906,14 +2160,14 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "evidence_reference_Practitioner", + collectionID(refType, targetID), + "performer_PractitionerRole", projectJSON, sourceType, - "Practitioner", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "performer_diagnostic_report") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -2921,12 +2175,12 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "performer_diagnostic_report", projectJSON, + refType, sourceType, - "reference", )) } } @@ -2936,16 +2190,17 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Performer != nil { + for _, item_2_x_Performer := range x.Performer { + if item_2_x_Performer != nil { + if item_2_x_Performer.Reference != nil { + refVal := *item_2_x_Performer.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_PractitionerRole") + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "performer_Organization") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -2954,14 +2209,14 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "evidence_reference_PractitionerRole", + collectionID(refType, targetID), + "performer_Organization", projectJSON, sourceType, - "PractitionerRole", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "performer_diagnostic_report") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -2969,12 +2224,12 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "performer_diagnostic_report", projectJSON, + refType, sourceType, - "reference", )) } } @@ -2984,16 +2239,17 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Result != nil { + for _, item_2_x_Result := range x.Result { + if item_2_x_Result != nil { + if item_2_x_Result.Reference != nil { + refVal := *item_2_x_Result.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_ResearchStudy") + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "result") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3002,14 +2258,14 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "evidence_reference_ResearchStudy", + collectionID(refType, targetID), + "result", projectJSON, sourceType, - "ResearchStudy", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "result_diagnostic_report") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3017,12 +2273,12 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "result_diagnostic_report", projectJSON, + refType, sourceType, - "reference", )) } } @@ -3032,16 +2288,17 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.ResultsInterpreter != nil { + for _, item_2_x_ResultsInterpreter := range x.ResultsInterpreter { + if item_2_x_ResultsInterpreter != nil { + if item_2_x_ResultsInterpreter.Reference != nil { + refVal := *item_2_x_ResultsInterpreter.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Patient") + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "resultsInterpreter_Practitioner") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3050,14 +2307,14 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Patient", targetID), - "evidence_reference_Patient", + collectionID(refType, targetID), + "resultsInterpreter_Practitioner", projectJSON, sourceType, - "Patient", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "resultsInterpreter_diagnostic_report") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3065,12 +2322,12 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "resultsInterpreter_diagnostic_report", projectJSON, + refType, sourceType, - "reference", )) } } @@ -3080,16 +2337,17 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.ResultsInterpreter != nil { + for _, item_2_x_ResultsInterpreter := range x.ResultsInterpreter { + if item_2_x_ResultsInterpreter != nil { + if item_2_x_ResultsInterpreter.Reference != nil { + refVal := *item_2_x_ResultsInterpreter.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_ResearchSubject") + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "resultsInterpreter_PractitionerRole") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3098,14 +2356,14 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "evidence_reference_ResearchSubject", + collectionID(refType, targetID), + "resultsInterpreter_PractitionerRole", projectJSON, sourceType, - "ResearchSubject", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "resultsInterpreter_diagnostic_report") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3113,12 +2371,12 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "resultsInterpreter_diagnostic_report", projectJSON, + refType, sourceType, - "reference", )) } } @@ -3128,16 +2386,17 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.ResultsInterpreter != nil { + for _, item_2_x_ResultsInterpreter := range x.ResultsInterpreter { + if item_2_x_ResultsInterpreter != nil { + if item_2_x_ResultsInterpreter.Reference != nil { + refVal := *item_2_x_ResultsInterpreter.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Substance") + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "resultsInterpreter_Organization") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3146,14 +2405,14 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Substance", targetID), - "evidence_reference_Substance", + collectionID(refType, targetID), + "resultsInterpreter_Organization", projectJSON, sourceType, - "Substance", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "resultsInterpreter_diagnostic_report") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3161,12 +2420,12 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "resultsInterpreter_diagnostic_report", projectJSON, + refType, sourceType, - "reference", )) } } @@ -3176,16 +2435,17 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Specimen != nil { + for _, item_2_x_Specimen := range x.Specimen { + if item_2_x_Specimen != nil { + if item_2_x_Specimen.Reference != nil { + refVal := *item_2_x_Specimen.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_SubstanceDefinition") + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "specimen") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3194,14 +2454,14 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "evidence_reference_SubstanceDefinition", + collectionID(refType, targetID), + "specimen", projectJSON, sourceType, - "SubstanceDefinition", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "specimen_diagnostic_report") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3209,12 +2469,12 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "specimen_diagnostic_report", projectJSON, + refType, sourceType, - "reference", )) } } @@ -3224,16 +2484,17 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Study != nil { + for _, item_2_x_Study := range x.Study { + if item_2_x_Study != nil { + if item_2_x_Study.Reference != nil { + refVal := *item_2_x_Study.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Specimen") + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "study_ImagingStudy") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3242,14 +2503,14 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Specimen", targetID), - "evidence_reference_Specimen", + collectionID(refType, targetID), + "study_ImagingStudy", projectJSON, sourceType, - "Specimen", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "study_diagnostic_report") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3257,12 +2518,12 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "study_diagnostic_report", projectJSON, + refType, sourceType, - "reference", )) } } @@ -3272,16 +2533,712 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "subject_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "subject_diagnostic_report") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_diagnostic_report", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "subject_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "subject_diagnostic_report") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_diagnostic_report", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "subject_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "subject_diagnostic_report") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_diagnostic_report", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "subject_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "subject_diagnostic_report") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_diagnostic_report", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "subject_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "subject_diagnostic_report") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_diagnostic_report", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "subject_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "subject_diagnostic_report") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_diagnostic_report", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Media != nil { + for _, item_3_x_Media := range x.Media { + if item_3_x_Media != nil { + if item_3_x_Media.Link != nil { + if item_3_x_Media.Link.Reference != nil { + refVal := *item_3_x_Media.Link.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Observation") + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "media_link") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "media_link", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "diagnostic_report_media") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "diagnostic_report_media", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + if x.SupportingInfo != nil { + for _, item_3_x_SupportingInfo := range x.SupportingInfo { + if item_3_x_SupportingInfo != nil { + if item_3_x_SupportingInfo.Reference != nil { + if item_3_x_SupportingInfo.Reference.Reference != nil { + refVal := *item_3_x_SupportingInfo.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInfo_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "diagnostic_report_supporting_info") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "diagnostic_report_supporting_info", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + if x.SupportingInfo != nil { + for _, item_3_x_SupportingInfo := range x.SupportingInfo { + if item_3_x_SupportingInfo != nil { + if item_3_x_SupportingInfo.Reference != nil { + if item_3_x_SupportingInfo.Reference.Reference != nil { + refVal := *item_3_x_SupportingInfo.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInfo_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "diagnostic_report_supporting_info") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "diagnostic_report_supporting_info", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + if x.SupportingInfo != nil { + for _, item_3_x_SupportingInfo := range x.SupportingInfo { + if item_3_x_SupportingInfo != nil { + if item_3_x_SupportingInfo.Reference != nil { + if item_3_x_SupportingInfo.Reference.Reference != nil { + refVal := *item_3_x_SupportingInfo.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInfo_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "diagnostic_report_supporting_info") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "diagnostic_report_supporting_info", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + return edges, nil +} + +// ExtractEdges extracts graph links from DocumentReference. +func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "DocumentReference" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.Author != nil { + for _, item_2_x_Author := range x.Author { + if item_2_x_Author != nil { + if item_2_x_Author.Reference != nil { + refVal := *item_2_x_Author.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "author_Practitioner") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3290,14 +3247,14 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Observation", targetID), - "evidence_reference_Observation", + collectionID(refType, targetID), + "author_Practitioner", projectJSON, sourceType, - "Observation", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "author_document_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3305,12 +3262,12 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "author_document_reference", projectJSON, + refType, sourceType, - "reference", )) } } @@ -3320,16 +3277,17 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Author != nil { + for _, item_2_x_Author := range x.Author { + if item_2_x_Author != nil { + if item_2_x_Author.Reference != nil { + refVal := *item_2_x_Author.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_DiagnosticReport") + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "author_PractitionerRole") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3338,14 +3296,14 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "evidence_reference_DiagnosticReport", + collectionID(refType, targetID), + "author_PractitionerRole", projectJSON, sourceType, - "DiagnosticReport", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "author_document_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3353,12 +3311,12 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "author_document_reference", projectJSON, + refType, sourceType, - "reference", )) } } @@ -3368,16 +3326,17 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Author != nil { + for _, item_2_x_Author := range x.Author { + if item_2_x_Author != nil { + if item_2_x_Author.Reference != nil { + refVal := *item_2_x_Author.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Condition") + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "author_Organization") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3386,14 +3345,14 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Condition", targetID), - "evidence_reference_Condition", + collectionID(refType, targetID), + "author_Organization", projectJSON, sourceType, - "Condition", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "author_document_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3401,12 +3360,12 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "author_document_reference", projectJSON, + refType, sourceType, - "reference", )) } } @@ -3416,64 +3375,17 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "evidence_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Author != nil { + for _, item_2_x_Author := range x.Author { + if item_2_x_Author != nil { + if item_2_x_Author.Reference != nil { + refVal := *item_2_x_Author.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_MedicationAdministration") + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "author_Patient") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3482,14 +3394,14 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "evidence_reference_MedicationAdministration", + collectionID(refType, targetID), + "author_Patient", projectJSON, sourceType, - "MedicationAdministration", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "author_document_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3497,12 +3409,12 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "author_document_reference", projectJSON, + refType, sourceType, - "reference", )) } } @@ -3512,16 +3424,17 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_MedicationStatement") + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_MedicationRequest") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3530,14 +3443,14 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "evidence_reference_MedicationStatement", + collectionID(refType, targetID), + "basedOn_MedicationRequest", projectJSON, sourceType, - "MedicationStatement", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "basedOn_document_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -3545,12 +3458,12 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_document_reference", projectJSON, + refType, sourceType, - "reference", )) } } @@ -3560,1071 +3473,1130 @@ func (x *Condition) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "evidence_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Custodian != nil { + if x.Custodian.Reference != nil { + refVal := *x.Custodian.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "custodian") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "custodian", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "custodian_document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "custodian_document_reference", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "evidence_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "subject_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "evidence_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "subject_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "evidence_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "subject_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "evidence_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "subject_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "evidence_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "subject_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Evidence != nil { - for _, item_3_x_Evidence := range x.Evidence { - if item_3_x_Evidence != nil { - if item_3_x_Evidence.Reference != nil { - if item_3_x_Evidence.Reference.Reference != nil { - refVal := *item_3_x_Evidence.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "evidence_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "evidence_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "subject_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "note_authorReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "subject_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "note_authorReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "subject_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "note_authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "subject_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "note_authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "subject_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Participant != nil { - for _, item_3_x_Participant := range x.Participant { - if item_3_x_Participant != nil { - if item_3_x_Participant.Actor != nil { - if item_3_x_Participant.Actor.Reference != nil { - refVal := *item_3_x_Participant.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "participant_actor_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "participant_actor_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "condition_participant") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("participant", id), - "condition_participant", - projectJSON, - sourceType, - "participant", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "subject_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Participant != nil { - for _, item_3_x_Participant := range x.Participant { - if item_3_x_Participant != nil { - if item_3_x_Participant.Actor != nil { - if item_3_x_Participant.Actor.Reference != nil { - refVal := *item_3_x_Participant.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "participant_actor_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "participant_actor_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "condition_participant") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("participant", id), - "condition_participant", - projectJSON, - sourceType, - "participant", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "subject_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Participant != nil { - for _, item_3_x_Participant := range x.Participant { - if item_3_x_Participant != nil { - if item_3_x_Participant.Actor != nil { - if item_3_x_Participant.Actor.Reference != nil { - refVal := *item_3_x_Participant.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "participant_actor_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "participant_actor_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "condition_participant") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("participant", id), - "condition_participant", - projectJSON, - sourceType, - "participant", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "subject_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Participant != nil { - for _, item_3_x_Participant := range x.Participant { - if item_3_x_Participant != nil { - if item_3_x_Participant.Actor != nil { - if item_3_x_Participant.Actor.Reference != nil { - refVal := *item_3_x_Participant.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "participant_actor_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "participant_actor_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "condition_participant") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("participant", id), - "condition_participant", - projectJSON, - sourceType, - "participant", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "subject_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Stage != nil { - for _, item_4_x_Stage := range x.Stage { - if item_4_x_Stage != nil { - if item_4_x_Stage.Assessment != nil { - for _, item_2_item_4_x_Stage_Assessment := range item_4_x_Stage.Assessment { - if item_2_item_4_x_Stage_Assessment != nil { - if item_2_item_4_x_Stage_Assessment.Reference != nil { - refVal := *item_2_item_4_x_Stage_Assessment.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "stage_assessment_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "stage_assessment_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "assessment_condition_stage") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("stage", id), - "assessment_condition_stage", - projectJSON, - sourceType, - "stage", - )) - } - } - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "subject_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Stage != nil { - for _, item_4_x_Stage := range x.Stage { - if item_4_x_Stage != nil { - if item_4_x_Stage.Assessment != nil { - for _, item_2_item_4_x_Stage_Assessment := range item_4_x_Stage.Assessment { - if item_2_item_4_x_Stage_Assessment != nil { - if item_2_item_4_x_Stage_Assessment.Reference != nil { - refVal := *item_2_item_4_x_Stage_Assessment.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "stage_assessment_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "stage_assessment_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "assessment_condition_stage") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("stage", id), - "assessment_condition_stage", - projectJSON, - sourceType, - "stage", - )) - } - } - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "subject_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) } } } } } } - return edges, nil -} - -// ExtractEdges extracts graph links from ConditionParticipant. -func (x *ConditionParticipant) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "subject_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } } - id := *x.ID - sourceType := "ConditionParticipant" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "subject_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "actor_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "actor_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "condition_participant") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("participant", id), - "condition_participant", - projectJSON, - sourceType, - "participant", - )) - } - } - } - } - } - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "subject_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "actor_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "actor_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "condition_participant") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("participant", id), - "condition_participant", - projectJSON, - sourceType, - "participant", - )) - } - } - } - } - } - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "subject_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "actor_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "actor_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "condition_participant") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("participant", id), - "condition_participant", - projectJSON, - sourceType, - "participant", - )) - } - } - } - } - } - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "subject_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "actor_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "actor_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "condition_participant") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("participant", id), - "condition_participant", - projectJSON, - sourceType, - "participant", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "subject_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } - return edges, nil -} - -// ExtractEdges extracts graph links from ConditionStage. -func (x *ConditionStage) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "subject_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } } - id := *x.ID - sourceType := "ConditionStage" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Assessment != nil { - for _, item_2_x_Assessment := range x.Assessment { - if item_2_x_Assessment != nil { - if item_2_x_Assessment.Reference != nil { - refVal := *item_2_x_Assessment.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "assessment_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "assessment_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "assessment_condition_stage") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("stage", id), - "assessment_condition_stage", - projectJSON, - sourceType, - "stage", - )) + if x.Attester != nil { + for _, item_3_x_Attester := range x.Attester { + if item_3_x_Attester != nil { + if item_3_x_Attester.Party != nil { + if item_3_x_Attester.Party.Reference != nil { + refVal := *item_3_x_Attester.Party.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "attester_party_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "attester_party_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference_attester") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference_attester", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -4632,45 +4604,50 @@ func (x *ConditionStage) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Assessment != nil { - for _, item_2_x_Assessment := range x.Assessment { - if item_2_x_Assessment != nil { - if item_2_x_Assessment.Reference != nil { - refVal := *item_2_x_Assessment.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "assessment_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "assessment_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "assessment_condition_stage") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("stage", id), - "assessment_condition_stage", - projectJSON, - sourceType, - "stage", - )) + if x.Attester != nil { + for _, item_3_x_Attester := range x.Attester { + if item_3_x_Attester != nil { + if item_3_x_Attester.Party != nil { + if item_3_x_Attester.Party.Reference != nil { + refVal := *item_3_x_Attester.Party.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "attester_party_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "attester_party_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference_attester") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference_attester", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -4678,240 +4655,152 @@ func (x *ConditionStage) ExtractEdges(project string) ([]json.RawMessage, error) } } } - return edges, nil -} - -// ExtractEdges extracts graph links from ContactDetail. -func (x *ContactDetail) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ContactDetail" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from ContactPoint. -func (x *ContactPoint) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ContactPoint" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from Count. -func (x *Count) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Count" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from DataRequirement. -func (x *DataRequirement) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil + if x.Attester != nil { + for _, item_3_x_Attester := range x.Attester { + if item_3_x_Attester != nil { + if item_3_x_Attester.Party != nil { + if item_3_x_Attester.Party.Reference != nil { + refVal := *item_3_x_Attester.Party.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "attester_party_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "attester_party_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference_attester") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference_attester", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } } - id := *x.ID - sourceType := "DataRequirement" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.SubjectReference != nil { - if x.SubjectReference.Reference != nil { - refVal := *x.SubjectReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "subjectReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("subjectReference", targetID), - "subjectReference", - projectJSON, - sourceType, - "subjectReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "data_requirement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("requirement", id), - "data_requirement", - projectJSON, - sourceType, - "requirement", - )) + if x.Attester != nil { + for _, item_3_x_Attester := range x.Attester { + if item_3_x_Attester != nil { + if item_3_x_Attester.Party != nil { + if item_3_x_Attester.Party.Reference != nil { + refVal := *item_3_x_Attester.Party.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "attester_party_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "attester_party_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference_attester") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference_attester", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - return edges, nil -} - -// ExtractEdges extracts graph links from DataRequirementCodeFilter. -func (x *DataRequirementCodeFilter) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "DataRequirementCodeFilter" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from DataRequirementDateFilter. -func (x *DataRequirementDateFilter) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "DataRequirementDateFilter" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from DataRequirementSort. -func (x *DataRequirementSort) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "DataRequirementSort" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from DataRequirementValueFilter. -func (x *DataRequirementValueFilter) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "DataRequirementValueFilter" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from DiagnosticReport. -func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "DiagnosticReport" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "basedOn_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_diagnostic_report") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("report", id), - "basedOn_diagnostic_report", - projectJSON, - sourceType, - "report", - )) + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -4919,45 +4808,50 @@ func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, erro } } } - if x.Performer != nil { - for _, item_2_x_Performer := range x.Performer { - if item_2_x_Performer != nil { - if item_2_x_Performer.Reference != nil { - refVal := *item_2_x_Performer.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "performer_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "performer_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "performer_diagnostic_report") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("report", id), - "performer_diagnostic_report", - projectJSON, - sourceType, - "report", - )) + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -4965,45 +4859,50 @@ func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, erro } } } - if x.Performer != nil { - for _, item_2_x_Performer := range x.Performer { - if item_2_x_Performer != nil { - if item_2_x_Performer.Reference != nil { - refVal := *item_2_x_Performer.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "performer_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "performer_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "performer_diagnostic_report") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("report", id), - "performer_diagnostic_report", - projectJSON, - sourceType, - "report", - )) + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -5011,45 +4910,50 @@ func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, erro } } } - if x.Performer != nil { - for _, item_2_x_Performer := range x.Performer { - if item_2_x_Performer != nil { - if item_2_x_Performer.Reference != nil { - refVal := *item_2_x_Performer.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "performer_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "performer_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "performer_diagnostic_report") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("report", id), - "performer_diagnostic_report", - projectJSON, - sourceType, - "report", - )) + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -5057,45 +4961,50 @@ func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, erro } } } - if x.Result != nil { - for _, item_2_x_Result := range x.Result { - if item_2_x_Result != nil { - if item_2_x_Result.Reference != nil { - refVal := *item_2_x_Result.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "result") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("result", targetID), - "result", - projectJSON, - sourceType, - "result", - )) - } - backrefKey := getEdgeUUID(id, targetID, "result_diagnostic_report") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("report", id), - "result_diagnostic_report", - projectJSON, - sourceType, - "report", - )) + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -5103,45 +5012,50 @@ func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, erro } } } - if x.ResultsInterpreter != nil { - for _, item_2_x_ResultsInterpreter := range x.ResultsInterpreter { - if item_2_x_ResultsInterpreter != nil { - if item_2_x_ResultsInterpreter.Reference != nil { - refVal := *item_2_x_ResultsInterpreter.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "resultsInterpreter_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "resultsInterpreter_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "resultsInterpreter_diagnostic_report") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("report", id), - "resultsInterpreter_diagnostic_report", - projectJSON, - sourceType, - "report", - )) + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -5149,45 +5063,50 @@ func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, erro } } } - if x.ResultsInterpreter != nil { - for _, item_2_x_ResultsInterpreter := range x.ResultsInterpreter { - if item_2_x_ResultsInterpreter != nil { - if item_2_x_ResultsInterpreter.Reference != nil { - refVal := *item_2_x_ResultsInterpreter.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "resultsInterpreter_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "resultsInterpreter_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "resultsInterpreter_diagnostic_report") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("report", id), - "resultsInterpreter_diagnostic_report", - projectJSON, - sourceType, - "report", - )) + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -5195,45 +5114,50 @@ func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, erro } } } - if x.ResultsInterpreter != nil { - for _, item_2_x_ResultsInterpreter := range x.ResultsInterpreter { - if item_2_x_ResultsInterpreter != nil { - if item_2_x_ResultsInterpreter.Reference != nil { - refVal := *item_2_x_ResultsInterpreter.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "resultsInterpreter_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "resultsInterpreter_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "resultsInterpreter_diagnostic_report") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("report", id), - "resultsInterpreter_diagnostic_report", - projectJSON, - sourceType, - "report", - )) + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -5241,45 +5165,50 @@ func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, erro } } } - if x.Specimen != nil { - for _, item_2_x_Specimen := range x.Specimen { - if item_2_x_Specimen != nil { - if item_2_x_Specimen.Reference != nil { - refVal := *item_2_x_Specimen.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("specimen", targetID), - "specimen", - projectJSON, - sourceType, - "specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "specimen_diagnostic_report") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("report", id), - "specimen_diagnostic_report", - projectJSON, - sourceType, - "report", - )) + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -5287,45 +5216,50 @@ func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, erro } } } - if x.Study != nil { - for _, item_2_x_Study := range x.Study { - if item_2_x_Study != nil { - if item_2_x_Study.Reference != nil { - refVal := *item_2_x_Study.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "study_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "study_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "study_diagnostic_report") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("report", id), - "study_diagnostic_report", - projectJSON, - sourceType, - "report", - )) + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -5333,298 +5267,253 @@ func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, erro } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "subject_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "subject_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_diagnostic_report") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("report", id), - "subject_diagnostic_report", - projectJSON, - sourceType, - "report", - )) - } - } - } - } - } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "subject_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "subject_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_diagnostic_report") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("report", id), - "subject_diagnostic_report", - projectJSON, - sourceType, - "report", - )) - } - } - } - } - } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "subject_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "subject_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_diagnostic_report") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("report", id), - "subject_diagnostic_report", - projectJSON, - sourceType, - "report", - )) + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "subject_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "subject_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_diagnostic_report") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("report", id), - "subject_diagnostic_report", - projectJSON, - sourceType, - "report", - )) + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "subject_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "subject_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_diagnostic_report") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("report", id), - "subject_diagnostic_report", - projectJSON, - sourceType, - "report", - )) + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "subject_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "subject_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_diagnostic_report") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("report", id), - "subject_diagnostic_report", - projectJSON, - sourceType, - "report", - )) + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Media != nil { - for _, item_3_x_Media := range x.Media { - if item_3_x_Media != nil { - if item_3_x_Media.Link != nil { - if item_3_x_Media.Link.Reference != nil { - refVal := *item_3_x_Media.Link.Reference + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "media_link") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("link", targetID), - "media_link", - projectJSON, - sourceType, - "link", - )) - } - backrefKey := getEdgeUUID(id, targetID, "diagnostic_report_media") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("media", id), - "diagnostic_report_media", - projectJSON, - sourceType, - "media", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -5633,46 +5522,49 @@ func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, erro } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "note_authorReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -5681,46 +5573,49 @@ func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, erro } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "note_authorReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -5729,46 +5624,49 @@ func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, erro } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "note_authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -5777,46 +5675,49 @@ func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, erro } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "note_authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -5825,46 +5726,49 @@ func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, erro } } } - if x.SupportingInfo != nil { - for _, item_3_x_SupportingInfo := range x.SupportingInfo { - if item_3_x_SupportingInfo != nil { - if item_3_x_SupportingInfo.Reference != nil { - if item_3_x_SupportingInfo.Reference.Reference != nil { - refVal := *item_3_x_SupportingInfo.Reference.Reference + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "supportingInfo_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "diagnostic_report_supporting_info") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("info", id), - "diagnostic_report_supporting_info", - projectJSON, - sourceType, - "info", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -5873,46 +5777,49 @@ func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, erro } } } - if x.SupportingInfo != nil { - for _, item_3_x_SupportingInfo := range x.SupportingInfo { - if item_3_x_SupportingInfo != nil { - if item_3_x_SupportingInfo.Reference != nil { - if item_3_x_SupportingInfo.Reference.Reference != nil { - refVal := *item_3_x_SupportingInfo.Reference.Reference + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "supportingInfo_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "diagnostic_report_supporting_info") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("info", id), - "diagnostic_report_supporting_info", - projectJSON, - sourceType, - "info", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -5921,46 +5828,49 @@ func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, erro } } } - if x.SupportingInfo != nil { - for _, item_3_x_SupportingInfo := range x.SupportingInfo { - if item_3_x_SupportingInfo != nil { - if item_3_x_SupportingInfo.Reference != nil { - if item_3_x_SupportingInfo.Reference.Reference != nil { - refVal := *item_3_x_SupportingInfo.Reference.Reference + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "supportingInfo_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "diagnostic_report_supporting_info") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("info", id), - "diagnostic_report_supporting_info", - projectJSON, - sourceType, - "info", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -5969,248 +5879,152 @@ func (x *DiagnosticReport) ExtractEdges(project string) ([]json.RawMessage, erro } } } - return edges, nil -} - -// ExtractEdges extracts graph links from DiagnosticReportMedia. -func (x *DiagnosticReportMedia) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "DiagnosticReportMedia" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Link != nil { - if x.Link.Reference != nil { - refVal := *x.Link.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "link") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("link", targetID), - "link", - projectJSON, - sourceType, - "link", - )) - } - backrefKey := getEdgeUUID(id, targetID, "diagnostic_report_media") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("media", id), - "diagnostic_report_media", - projectJSON, - sourceType, - "media", - )) + if x.BodySite != nil { + for _, item_3_x_BodySite := range x.BodySite { + if item_3_x_BodySite != nil { + if item_3_x_BodySite.Reference != nil { + if item_3_x_BodySite.Reference.Reference != nil { + refVal := *item_3_x_BodySite.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "bodySite_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - return edges, nil -} - -// ExtractEdges extracts graph links from DiagnosticReportSupportingInfo. -func (x *DiagnosticReportSupportingInfo) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "DiagnosticReportSupportingInfo" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "diagnostic_report_supporting_info") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("info", id), - "diagnostic_report_supporting_info", - projectJSON, - sourceType, - "info", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "diagnostic_report_supporting_info") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("info", id), - "diagnostic_report_supporting_info", - projectJSON, - sourceType, - "info", - )) - } - } - } - } - } - if x.Reference != nil { - if x.Reference.Reference != nil { - refVal := *x.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "diagnostic_report_supporting_info") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("info", id), - "diagnostic_report_supporting_info", - projectJSON, - sourceType, - "info", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - return edges, nil -} - -// ExtractEdges extracts graph links from Directory. -func (x *Directory) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Directory" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Child != nil { - for _, item_2_x_Child := range x.Child { - if item_2_x_Child != nil { - if item_2_x_Child.Reference != nil { - refVal := *item_2_x_Child.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Directory" { - forwardKey := getEdgeUUID(targetID, id, "child_Directory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Directory", targetID), - "child_Directory", - projectJSON, - sourceType, - "Directory", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -6218,29 +6032,50 @@ func (x *Directory) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Child != nil { - for _, item_2_x_Child := range x.Child { - if item_2_x_Child != nil { - if item_2_x_Child.Reference != nil { - refVal := *item_2_x_Child.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "child_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "child_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -6248,79 +6083,50 @@ func (x *Directory) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - return edges, nil -} - -// ExtractEdges extracts graph links from Distance. -func (x *Distance) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Distance" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from DocumentReference. -func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "DocumentReference" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Author != nil { - for _, item_2_x_Author := range x.Author { - if item_2_x_Author != nil { - if item_2_x_Author.Reference != nil { - refVal := *item_2_x_Author.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "author_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "author_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "author_document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "author_document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -6328,45 +6134,50 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Author != nil { - for _, item_2_x_Author := range x.Author { - if item_2_x_Author != nil { - if item_2_x_Author.Reference != nil { - refVal := *item_2_x_Author.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "author_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "author_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "author_document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "author_document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -6374,45 +6185,50 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Author != nil { - for _, item_2_x_Author := range x.Author { - if item_2_x_Author != nil { - if item_2_x_Author.Reference != nil { - refVal := *item_2_x_Author.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "author_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "author_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "author_document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "author_document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -6420,45 +6236,50 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Author != nil { - for _, item_2_x_Author := range x.Author { - if item_2_x_Author != nil { - if item_2_x_Author.Reference != nil { - refVal := *item_2_x_Author.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "author_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "author_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "author_document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "author_document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -6466,45 +6287,50 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "basedOn_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "basedOn_document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -6512,1054 +6338,1284 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Custodian != nil { - if x.Custodian.Reference != nil { - refVal := *x.Custodian.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "custodian") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("custodian", targetID), - "custodian", - projectJSON, - sourceType, - "custodian", - )) - } - backrefKey := getEdgeUUID(id, targetID, "custodian_document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "custodian_document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "subject_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "subject_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "subject_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "subject_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "subject_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "subject_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "subject_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "subject_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "subject_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "subject_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "subject_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "subject_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "subject_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "subject_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "subject_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "subject_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "subject_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "subject_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "subject_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "subject_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "subject_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "subject_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "subject_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "subject_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "subject_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "subject_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "subject_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "subject_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Event != nil { + for _, item_3_x_Event := range x.Event { + if item_3_x_Event != nil { + if item_3_x_Event.Reference != nil { + if item_3_x_Event.Reference.Reference != nil { + refVal := *item_3_x_Event.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "event_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "event_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "subject_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "subject_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.RelatesTo != nil { + for _, item_3_x_RelatesTo := range x.RelatesTo { + if item_3_x_RelatesTo != nil { + if item_3_x_RelatesTo.Target != nil { + if item_3_x_RelatesTo.Target.Reference != nil { + refVal := *item_3_x_RelatesTo.Target.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "relatesTo_target") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatesTo_target", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "document_reference_relates_to") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "document_reference_relates_to", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference + return edges, nil +} + +// ExtractEdges extracts graph links from FamilyMemberHistory. +func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "FamilyMemberHistory" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.Patient != nil { + if x.Patient.Reference != nil { + refVal := *x.Patient.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "subject_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "subject_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "family_member_history") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "family_member_history", + projectJSON, + refType, + sourceType, + )) + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "subject_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "subject_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "subject_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "subject_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "subject_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "subject_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "subject_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "subject_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "subject_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "subject_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Participant != nil { + for _, item_3_x_Participant := range x.Participant { + if item_3_x_Participant != nil { + if item_3_x_Participant.Actor != nil { + if item_3_x_Participant.Actor.Reference != nil { + refVal := *item_3_x_Participant.Actor.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "participant_actor_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "participant_actor_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "family_member_history_participant") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "family_member_history_participant", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "subject_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "subject_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Participant != nil { + for _, item_3_x_Participant := range x.Participant { + if item_3_x_Participant != nil { + if item_3_x_Participant.Actor != nil { + if item_3_x_Participant.Actor.Reference != nil { + refVal := *item_3_x_Participant.Actor.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "participant_actor_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "participant_actor_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "family_member_history_participant") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "family_member_history_participant", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "subject_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "subject_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "document_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Participant != nil { + for _, item_3_x_Participant := range x.Participant { + if item_3_x_Participant != nil { + if item_3_x_Participant.Actor != nil { + if item_3_x_Participant.Actor.Reference != nil { + refVal := *item_3_x_Participant.Actor.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "participant_actor_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "participant_actor_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "family_member_history_participant") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "family_member_history_participant", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Attester != nil { - for _, item_3_x_Attester := range x.Attester { - if item_3_x_Attester != nil { - if item_3_x_Attester.Party != nil { - if item_3_x_Attester.Party.Reference != nil { - refVal := *item_3_x_Attester.Party.Reference + if x.Participant != nil { + for _, item_3_x_Participant := range x.Participant { + if item_3_x_Participant != nil { + if item_3_x_Participant.Actor != nil { + if item_3_x_Participant.Actor.Reference != nil { + refVal := *item_3_x_Participant.Actor.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "attester_party_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "attester_party_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference_attester") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("attester", id), - "document_reference_attester", - projectJSON, - sourceType, - "attester", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "participant_actor_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "participant_actor_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "family_member_history_participant") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "family_member_history_participant", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -7568,46 +7624,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Attester != nil { - for _, item_3_x_Attester := range x.Attester { - if item_3_x_Attester != nil { - if item_3_x_Attester.Party != nil { - if item_3_x_Attester.Party.Reference != nil { - refVal := *item_3_x_Attester.Party.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "attester_party_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "attester_party_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference_attester") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("attester", id), - "document_reference_attester", - projectJSON, - sourceType, - "attester", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -7616,46 +7675,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Attester != nil { - for _, item_3_x_Attester := range x.Attester { - if item_3_x_Attester != nil { - if item_3_x_Attester.Party != nil { - if item_3_x_Attester.Party.Reference != nil { - refVal := *item_3_x_Attester.Party.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "attester_party_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "attester_party_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference_attester") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("attester", id), - "document_reference_attester", - projectJSON, - sourceType, - "attester", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -7664,46 +7726,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Attester != nil { - for _, item_3_x_Attester := range x.Attester { - if item_3_x_Attester != nil { - if item_3_x_Attester.Party != nil { - if item_3_x_Attester.Party.Reference != nil { - refVal := *item_3_x_Attester.Party.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "attester_party_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "attester_party_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference_attester") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("attester", id), - "document_reference_attester", - projectJSON, - sourceType, - "attester", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -7712,46 +7777,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "bodySite_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -7760,46 +7828,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "bodySite_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -7808,46 +7879,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "bodySite_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -7856,46 +7930,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "bodySite_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -7904,46 +7981,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "bodySite_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -7952,46 +8032,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "bodySite_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8000,46 +8083,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "bodySite_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8048,46 +8134,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "bodySite_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8096,46 +8185,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "bodySite_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8144,46 +8236,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "bodySite_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8192,46 +8287,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "bodySite_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8240,46 +8338,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "bodySite_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8288,46 +8389,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "bodySite_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8336,46 +8440,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "bodySite_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8384,46 +8491,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "bodySite_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8432,46 +8542,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "bodySite_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8480,46 +8593,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "bodySite_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8528,46 +8644,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "bodySite_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8576,46 +8695,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "bodySite_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8624,46 +8746,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "bodySite_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8672,142 +8797,201 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "bodySite_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + return edges, nil +} + +// ExtractEdges extracts graph links from Group. +func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "Group" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.ManagingEntity != nil { + if x.ManagingEntity.Reference != nil { + refVal := *x.ManagingEntity.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "managingEntity_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "managingEntity_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "bodySite_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.ManagingEntity != nil { + if x.ManagingEntity.Reference != nil { + refVal := *x.ManagingEntity.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "managingEntity_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "managingEntity_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.BodySite != nil { - for _, item_3_x_BodySite := range x.BodySite { - if item_3_x_BodySite != nil { - if item_3_x_BodySite.Reference != nil { - if item_3_x_BodySite.Reference.Reference != nil { - refVal := *item_3_x_BodySite.Reference.Reference + if x.ManagingEntity != nil { + if x.ManagingEntity.Reference != nil { + refVal := *x.ManagingEntity.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "managingEntity_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "managingEntity_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "bodySite_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8816,46 +9000,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "event_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8864,46 +9051,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "event_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8912,46 +9102,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "event_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -8960,46 +9153,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "event_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9008,46 +9204,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "event_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9056,46 +9255,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "event_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9104,46 +9306,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "event_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9152,46 +9357,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "event_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9200,46 +9408,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "event_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9248,46 +9459,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "event_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9296,46 +9510,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "event_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9344,46 +9561,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "event_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9392,46 +9612,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "event_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9440,46 +9663,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "event_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9488,46 +9714,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "event_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9536,46 +9765,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "event_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9584,46 +9816,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "event_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9632,46 +9867,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "event_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9680,46 +9918,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "event_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9728,46 +9969,49 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "event_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9776,46 +10020,151 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "event_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) + } + } + } + } + } + } + } + if x.Characteristic != nil { + for _, item_3_x_Characteristic := range x.Characteristic { + if item_3_x_Characteristic != nil { + if item_3_x_Characteristic.ValueReference != nil { + if item_3_x_Characteristic.ValueReference.Reference != nil { + refVal := *item_3_x_Characteristic.ValueReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "characteristic_valueReference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_characteristic") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_characteristic", + projectJSON, + refType, + sourceType, + )) + } } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + } + } + } + } + } + } + } + if x.Member != nil { + for _, item_3_x_Member := range x.Member { + if item_3_x_Member != nil { + if item_3_x_Member.Entity != nil { + if item_3_x_Member.Entity.Reference != nil { + refVal := *item_3_x_Member.Entity.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "member_entity_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "member_entity_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_member") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_member", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9824,46 +10173,202 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Member != nil { + for _, item_3_x_Member := range x.Member { + if item_3_x_Member != nil { + if item_3_x_Member.Entity != nil { + if item_3_x_Member.Entity.Reference != nil { + refVal := *item_3_x_Member.Entity.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "member_entity_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "member_entity_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_member") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_member", + projectJSON, + refType, + sourceType, + )) + } } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "event_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) + } + } + } + } + } + } + } + if x.Member != nil { + for _, item_3_x_Member := range x.Member { + if item_3_x_Member != nil { + if item_3_x_Member.Entity != nil { + if item_3_x_Member.Entity.Reference != nil { + refVal := *item_3_x_Member.Entity.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "member_entity_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "member_entity_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_member") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_member", + projectJSON, + refType, + sourceType, + )) + } } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) + } + } + } + } + } + } + } + if x.Member != nil { + for _, item_3_x_Member := range x.Member { + if item_3_x_Member != nil { + if item_3_x_Member.Entity != nil { + if item_3_x_Member.Entity.Reference != nil { + refVal := *item_3_x_Member.Entity.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "member_entity_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "member_entity_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_member") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_member", + projectJSON, + refType, + sourceType, + )) + } } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + } + } + } + } + } + } + } + if x.Member != nil { + for _, item_3_x_Member := range x.Member { + if item_3_x_Member != nil { + if item_3_x_Member.Entity != nil { + if item_3_x_Member.Entity.Reference != nil { + refVal := *item_3_x_Member.Entity.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "member_entity_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "member_entity_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_member") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_member", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -9872,16 +10377,85 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Event != nil { - for _, item_3_x_Event := range x.Event { - if item_3_x_Event != nil { - if item_3_x_Event.Reference != nil { - if item_3_x_Event.Reference.Reference != nil { - refVal := *item_3_x_Event.Reference.Reference + if x.Member != nil { + for _, item_3_x_Member := range x.Member { + if item_3_x_Member != nil { + if item_3_x_Member.Entity != nil { + if item_3_x_Member.Entity.Reference != nil { + refVal := *item_3_x_Member.Entity.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "event_reference_BodyStructure") + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "member_entity_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "member_entity_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "group_member") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "group_member", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + return edges, nil +} + +// ExtractEdges extracts graph links from ImagingStudy. +func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "ImagingStudy" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_Task") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -9890,14 +10464,14 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "event_reference_BodyStructure", + collectionID(refType, targetID), + "basedOn_Task", projectJSON, sourceType, - "BodyStructure", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "basedOn_imaging_study") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -9905,12 +10479,12 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_imaging_study", projectJSON, + refType, sourceType, - "reference", )) } } @@ -9920,16 +10494,17 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.RelatesTo != nil { - for _, item_3_x_RelatesTo := range x.RelatesTo { - if item_3_x_RelatesTo != nil { - if item_3_x_RelatesTo.Target != nil { - if item_3_x_RelatesTo.Target.Reference != nil { - refVal := *item_3_x_RelatesTo.Target.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.PartOf != nil { + for _, item_2_x_PartOf := range x.PartOf { + if item_2_x_PartOf != nil { + if item_2_x_PartOf.Reference != nil { + refVal := *item_2_x_PartOf.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "relatesTo_target") + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "partOf") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -9938,14 +10513,14 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("target", targetID), - "relatesTo_target", + collectionID(refType, targetID), + "partOf", projectJSON, sourceType, - "target", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "document_reference_relates_to") + backrefKey := getEdgeUUID(id, targetID, "partOf_imaging_study") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -9953,12 +10528,12 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("to", id), - "document_reference_relates_to", + collectionID(refType, targetID), + collectionID(sourceType, id), + "partOf_imaging_study", projectJSON, + refType, sourceType, - "to", )) } } @@ -9968,1402 +10543,105 @@ func (x *DocumentReference) ExtractEdges(project string) ([]json.RawMessage, err } } } - return edges, nil -} - -// ExtractEdges extracts graph links from DocumentReferenceAttester. -func (x *DocumentReferenceAttester) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "DocumentReferenceAttester" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Party != nil { - if x.Party.Reference != nil { - refVal := *x.Party.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "party_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "party_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference_attester") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("attester", id), - "document_reference_attester", - projectJSON, - sourceType, - "attester", - )) - } - } - } - } - } - if x.Party != nil { - if x.Party.Reference != nil { - refVal := *x.Party.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "party_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "party_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference_attester") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("attester", id), - "document_reference_attester", - projectJSON, - sourceType, - "attester", - )) - } - } - } - } - } - if x.Party != nil { - if x.Party.Reference != nil { - refVal := *x.Party.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "party_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "party_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference_attester") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("attester", id), - "document_reference_attester", - projectJSON, - sourceType, - "attester", - )) - } - } - } - } - } - if x.Party != nil { - if x.Party.Reference != nil { - refVal := *x.Party.Reference + if x.Referrer != nil { + if x.Referrer.Reference != nil { + refVal := *x.Referrer.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "party_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "party_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference_attester") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("attester", id), - "document_reference_attester", - projectJSON, - sourceType, - "attester", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "referrer_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "referrer_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "imaging_study") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "imaging_study", + projectJSON, + refType, + sourceType, + )) + } } } } } } - return edges, nil -} - -// ExtractEdges extracts graph links from DocumentReferenceContent. -func (x *DocumentReferenceContent) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "DocumentReferenceContent" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from DocumentReferenceContentProfile. -func (x *DocumentReferenceContentProfile) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "DocumentReferenceContentProfile" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from DocumentReferenceRelatesTo. -func (x *DocumentReferenceRelatesTo) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "DocumentReferenceRelatesTo" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Target != nil { - if x.Target.Reference != nil { - refVal := *x.Target.Reference + if x.Referrer != nil { + if x.Referrer.Reference != nil { + refVal := *x.Referrer.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "target") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("target", targetID), - "target", - projectJSON, - sourceType, - "target", - )) - } - backrefKey := getEdgeUUID(id, targetID, "document_reference_relates_to") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("to", id), - "document_reference_relates_to", - projectJSON, - sourceType, - "to", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "referrer_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "referrer_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "imaging_study") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "imaging_study", + projectJSON, + refType, + sourceType, + )) + } } } } } } - return edges, nil -} - -// ExtractEdges extracts graph links from Dosage. -func (x *Dosage) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Dosage" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from DosageDoseAndRate. -func (x *DosageDoseAndRate) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "DosageDoseAndRate" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from Duration. -func (x *Duration) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Duration" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from Expression. -func (x *Expression) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Expression" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from ExtendedContactDetail. -func (x *ExtendedContactDetail) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ExtendedContactDetail" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Organization != nil { - if x.Organization.Reference != nil { - refVal := *x.Organization.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("organization", targetID), - "organization", - projectJSON, - sourceType, - "organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extended_contact_detail") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("detail", id), - "extended_contact_detail", - projectJSON, - sourceType, - "detail", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from Extension. -func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Extension" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "valueReference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "valueReference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "valueReference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "valueReference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "valueReference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "valueReference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "valueReference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "valueReference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "valueReference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "valueReference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "valueReference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "valueReference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "valueReference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "valueReference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "valueReference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "valueReference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "valueReference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "valueReference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "valueReference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extension") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("extension", id), - "extension", - projectJSON, - sourceType, - "extension", - )) - } - } - } - } - } - if x.ValueAnnotation != nil { - if x.ValueAnnotation.AuthorReference != nil { - if x.ValueAnnotation.AuthorReference.Reference != nil { - refVal := *x.ValueAnnotation.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueAnnotation_authorReference_Practitioner") + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "subject_Patient") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -11372,14 +10650,14 @@ func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueAnnotation_authorReference_Practitioner", + collectionID(refType, targetID), + "subject_Patient", projectJSON, sourceType, - "Practitioner", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "annotation") + backrefKey := getEdgeUUID(id, targetID, "imaging_study") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -11387,12 +10665,12 @@ func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "imaging_study", projectJSON, + refType, sourceType, - "annotation", )) } } @@ -11400,14 +10678,15 @@ func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.ValueAnnotation != nil { - if x.ValueAnnotation.AuthorReference != nil { - if x.ValueAnnotation.AuthorReference.Reference != nil { - refVal := *x.ValueAnnotation.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueAnnotation_authorReference_PractitionerRole") + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "subject_Group") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -11416,14 +10695,14 @@ func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueAnnotation_authorReference_PractitionerRole", + collectionID(refType, targetID), + "subject_Group", projectJSON, sourceType, - "PractitionerRole", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "annotation") + backrefKey := getEdgeUUID(id, targetID, "imaging_study") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -11431,12 +10710,12 @@ func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "imaging_study", projectJSON, + refType, sourceType, - "annotation", )) } } @@ -11444,1730 +10723,2637 @@ func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.ValueAnnotation != nil { - if x.ValueAnnotation.AuthorReference != nil { - if x.ValueAnnotation.AuthorReference.Reference != nil { - refVal := *x.ValueAnnotation.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueAnnotation_authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueAnnotation_authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueAnnotation != nil { - if x.ValueAnnotation.AuthorReference != nil { - if x.ValueAnnotation.AuthorReference.Reference != nil { - refVal := *x.ValueAnnotation.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueAnnotation_authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueAnnotation_authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueCodeableReference_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "valueCodeableReference_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueCodeableReference_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueCodeableReference_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "valueCodeableReference_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueCodeableReference_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "valueCodeableReference_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "valueCodeableReference_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "valueCodeableReference_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "valueCodeableReference_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "valueCodeableReference_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "valueCodeableReference_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "valueCodeableReference_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "valueCodeableReference_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "valueCodeableReference_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "valueCodeableReference_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "valueCodeableReference_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "valueCodeableReference_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "valueCodeableReference_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "valueCodeableReference_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "valueCodeableReference_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "valueCodeableReference_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "valueCodeableReference_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueDataRequirement != nil { - if x.ValueDataRequirement.SubjectReference != nil { - if x.ValueDataRequirement.SubjectReference.Reference != nil { - refVal := *x.ValueDataRequirement.SubjectReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "valueDataRequirement_subjectReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("subjectReference", targetID), - "valueDataRequirement_subjectReference", - projectJSON, - sourceType, - "subjectReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "data_requirement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("requirement", id), - "data_requirement", - projectJSON, - sourceType, - "requirement", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueExtendedContactDetail != nil { - if x.ValueExtendedContactDetail.Organization != nil { - if x.ValueExtendedContactDetail.Organization.Reference != nil { - refVal := *x.ValueExtendedContactDetail.Organization.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueExtendedContactDetail_organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("organization", targetID), - "valueExtendedContactDetail_organization", - projectJSON, - sourceType, - "organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extended_contact_detail") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("detail", id), - "extended_contact_detail", - projectJSON, - sourceType, - "detail", - )) + if x.Procedure != nil { + for _, item_3_x_Procedure := range x.Procedure { + if item_3_x_Procedure != nil { + if item_3_x_Procedure.Reference != nil { + if item_3_x_Procedure.Reference.Reference != nil { + refVal := *item_3_x_Procedure.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "procedure_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "procedure_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueRelatedArtifact_resourceReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "valueRelatedArtifact_resourceReference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueRelatedArtifact_resourceReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueRelatedArtifact_resourceReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "valueRelatedArtifact_resourceReference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueRelatedArtifact_resourceReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "valueRelatedArtifact_resourceReference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "valueRelatedArtifact_resourceReference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "valueRelatedArtifact_resourceReference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) + } + } + } + } + } + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) + } + } + } + } + } + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + } + } + } + } + } + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "valueRelatedArtifact_resourceReference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) + } + } + } + } + } + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) + } + } + } + } + } + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + } + } + } + } + } + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "valueRelatedArtifact_resourceReference_Observation", - projectJSON, - sourceType, - "Observation", - )) + } + } + } + } + } + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) + } + } + } + } + } + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + } + } + } + } + } + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "valueRelatedArtifact_resourceReference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) + } + } + } + } + } + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) + } + } + } + } + } + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + } + } + } + } + } + if x.Series != nil { + for _, item_4_x_Series := range x.Series { + if item_4_x_Series != nil { + if item_4_x_Series.Specimen != nil { + for _, item_2_item_4_x_Series_Specimen := range item_4_x_Series.Specimen { + if item_2_item_4_x_Series_Specimen != nil { + if item_2_item_4_x_Series_Specimen.Reference != nil { + refVal := *item_2_item_4_x_Series_Specimen.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "series_specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "series_specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "specimen_imaging_study_series") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "specimen_imaging_study_series", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + return edges, nil +} + +// ExtractEdges extracts graph links from Medication. +func (x *Medication) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "Medication" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.MarketingAuthorizationHolder != nil { + if x.MarketingAuthorizationHolder.Reference != nil { + refVal := *x.MarketingAuthorizationHolder.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Condition") + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "marketingAuthorizationHolder") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -13176,14 +13362,14 @@ func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Condition", targetID), - "valueRelatedArtifact_resourceReference_Condition", + collectionID(refType, targetID), + "marketingAuthorizationHolder", projectJSON, sourceType, - "Condition", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") + backrefKey := getEdgeUUID(id, targetID, "medication") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -13191,12 +13377,12 @@ func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", + collectionID(refType, targetID), + collectionID(sourceType, id), + "medication", projectJSON, + refType, sourceType, - "artifact", )) } } @@ -13204,14 +13390,130 @@ func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + return edges, nil +} + +// ExtractEdges extracts graph links from MedicationAdministration. +func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "MedicationAdministration" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.PartOf != nil { + for _, item_2_x_PartOf := range x.PartOf { + if item_2_x_PartOf != nil { + if item_2_x_PartOf.Reference != nil { + refVal := *item_2_x_PartOf.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "partOf_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "partOf_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "partOf_medication_administration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "partOf_medication_administration", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + if x.PartOf != nil { + for _, item_2_x_PartOf := range x.PartOf { + if item_2_x_PartOf != nil { + if item_2_x_PartOf.Reference != nil { + refVal := *item_2_x_PartOf.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "partOf_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "partOf_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "partOf_medication_administration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "partOf_medication_administration", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + if x.Request != nil { + if x.Request.Reference != nil { + refVal := *x.Request.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Medication") + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -13220,14 +13522,14 @@ func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Medication", targetID), - "valueRelatedArtifact_resourceReference_Medication", + collectionID(refType, targetID), + "request", projectJSON, sourceType, - "Medication", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") + backrefKey := getEdgeUUID(id, targetID, "medication_administration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -13235,12 +13537,12 @@ func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", + collectionID(refType, targetID), + collectionID(sourceType, id), + "medication_administration", projectJSON, + refType, sourceType, - "artifact", )) } } @@ -13248,14 +13550,15 @@ func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_MedicationAdministration") + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "subject_Patient") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -13264,14 +13567,14 @@ func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "valueRelatedArtifact_resourceReference_MedicationAdministration", + collectionID(refType, targetID), + "subject_Patient", projectJSON, sourceType, - "MedicationAdministration", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") + backrefKey := getEdgeUUID(id, targetID, "medication_administration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -13279,12 +13582,12 @@ func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", + collectionID(refType, targetID), + collectionID(sourceType, id), + "medication_administration", projectJSON, + refType, sourceType, - "artifact", )) } } @@ -13292,14 +13595,15 @@ func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_MedicationStatement") + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "subject_Group") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -13308,14 +13612,14 @@ func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "valueRelatedArtifact_resourceReference_MedicationStatement", + collectionID(refType, targetID), + "subject_Group", projectJSON, sourceType, - "MedicationStatement", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") + backrefKey := getEdgeUUID(id, targetID, "medication_administration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -13323,12 +13627,12 @@ func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", + collectionID(refType, targetID), + collectionID(sourceType, id), + "medication_administration", projectJSON, + refType, sourceType, - "artifact", )) } } @@ -13336,884 +13640,458 @@ func (x *Extension) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "valueRelatedArtifact_resourceReference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInformation_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "valueRelatedArtifact_resourceReference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInformation_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "valueRelatedArtifact_resourceReference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInformation_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "valueRelatedArtifact_resourceReference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInformation_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "valueRelatedArtifact_resourceReference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInformation_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "valueRelatedArtifact_resourceReference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInformation_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "valueRelatedArtifact_resourceReference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInformation_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.ValueSignature != nil { - if x.ValueSignature.OnBehalfOf != nil { - if x.ValueSignature.OnBehalfOf.Reference != nil { - refVal := *x.ValueSignature.OnBehalfOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_onBehalfOf_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueSignature_onBehalfOf_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "onBehalfOf_signature", - projectJSON, - sourceType, - "signature", - )) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInformation_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.ValueSignature != nil { - if x.ValueSignature.OnBehalfOf != nil { - if x.ValueSignature.OnBehalfOf.Reference != nil { - refVal := *x.ValueSignature.OnBehalfOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_onBehalfOf_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueSignature_onBehalfOf_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInformation_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", + projectJSON, + refType, + sourceType, + )) + } + } } - backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "onBehalfOf_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.OnBehalfOf != nil { - if x.ValueSignature.OnBehalfOf.Reference != nil { - refVal := *x.ValueSignature.OnBehalfOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_onBehalfOf_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueSignature_onBehalfOf_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "onBehalfOf_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.OnBehalfOf != nil { - if x.ValueSignature.OnBehalfOf.Reference != nil { - refVal := *x.ValueSignature.OnBehalfOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_onBehalfOf_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueSignature_onBehalfOf_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "onBehalfOf_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.Who != nil { - if x.ValueSignature.Who.Reference != nil { - refVal := *x.ValueSignature.Who.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_who_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueSignature_who_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "who_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "who_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.Who != nil { - if x.ValueSignature.Who.Reference != nil { - refVal := *x.ValueSignature.Who.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_who_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueSignature_who_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "who_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "who_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.Who != nil { - if x.ValueSignature.Who.Reference != nil { - refVal := *x.ValueSignature.Who.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_who_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueSignature_who_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "who_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "who_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.Who != nil { - if x.ValueSignature.Who.Reference != nil { - refVal := *x.ValueSignature.Who.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_who_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueSignature_who_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "who_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "who_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueUsageContext != nil { - if x.ValueUsageContext.ValueReference != nil { - if x.ValueUsageContext.ValueReference.Reference != nil { - refVal := *x.ValueUsageContext.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueUsageContext_valueReference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "valueUsageContext_valueReference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "usage_context") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("context", id), - "usage_context", - projectJSON, - sourceType, - "context", - )) - } - } - } - } - } - } - if x.ValueUsageContext != nil { - if x.ValueUsageContext.ValueReference != nil { - if x.ValueUsageContext.ValueReference.Reference != nil { - refVal := *x.ValueUsageContext.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "valueUsageContext_valueReference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "valueUsageContext_valueReference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "usage_context") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("context", id), - "usage_context", - projectJSON, - sourceType, - "context", - )) - } - } - } - } - } - } - if x.ValueUsageContext != nil { - if x.ValueUsageContext.ValueReference != nil { - if x.ValueUsageContext.ValueReference.Reference != nil { - refVal := *x.ValueUsageContext.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueUsageContext_valueReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueUsageContext_valueReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "usage_context") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("context", id), - "usage_context", - projectJSON, - sourceType, - "context", - )) - } - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from FHIRPrimitiveExtension. -func (x *FHIRPrimitiveExtension) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "FHIRPrimitiveExtension" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from FamilyMemberHistory. -func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "FamilyMemberHistory" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Patient != nil { - if x.Patient.Reference != nil { - refVal := *x.Patient.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("patient", targetID), - "patient", - projectJSON, - sourceType, - "patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "family_member_history") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("history", id), - "family_member_history", - projectJSON, - sourceType, - "history", - )) } } } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Specimen") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14222,14 +14100,14 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "note_authorReference_Practitioner", + collectionID(refType, targetID), + "supportingInformation_Specimen", projectJSON, sourceType, - "Practitioner", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "annotation") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14237,12 +14115,12 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", projectJSON, + refType, sourceType, - "annotation", )) } } @@ -14252,16 +14130,17 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Observation") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14270,14 +14149,14 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "note_authorReference_PractitionerRole", + collectionID(refType, targetID), + "supportingInformation_Observation", projectJSON, sourceType, - "PractitionerRole", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "annotation") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14285,12 +14164,12 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", projectJSON, + refType, sourceType, - "annotation", )) } } @@ -14300,16 +14179,17 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_DiagnosticReport") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14318,14 +14198,14 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Patient", targetID), - "note_authorReference_Patient", + collectionID(refType, targetID), + "supportingInformation_DiagnosticReport", projectJSON, sourceType, - "Patient", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "annotation") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14333,12 +14213,12 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", projectJSON, + refType, sourceType, - "annotation", )) } } @@ -14348,16 +14228,17 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Condition") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14366,14 +14247,14 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Organization", targetID), - "note_authorReference_Organization", + collectionID(refType, targetID), + "supportingInformation_Condition", projectJSON, sourceType, - "Organization", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "annotation") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14381,12 +14262,12 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", projectJSON, + refType, sourceType, - "annotation", )) } } @@ -14396,16 +14277,17 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Participant != nil { - for _, item_3_x_Participant := range x.Participant { - if item_3_x_Participant != nil { - if item_3_x_Participant.Actor != nil { - if item_3_x_Participant.Actor.Reference != nil { - refVal := *item_3_x_Participant.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "participant_actor_Practitioner") + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Medication") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14414,14 +14296,14 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "participant_actor_Practitioner", + collectionID(refType, targetID), + "supportingInformation_Medication", projectJSON, sourceType, - "Practitioner", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "family_member_history_participant") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14429,12 +14311,12 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("participant", id), - "family_member_history_participant", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", projectJSON, + refType, sourceType, - "participant", )) } } @@ -14444,16 +14326,17 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Participant != nil { - for _, item_3_x_Participant := range x.Participant { - if item_3_x_Participant != nil { - if item_3_x_Participant.Actor != nil { - if item_3_x_Participant.Actor.Reference != nil { - refVal := *item_3_x_Participant.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "participant_actor_PractitionerRole") + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_MedicationAdministration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14462,14 +14345,14 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "participant_actor_PractitionerRole", + collectionID(refType, targetID), + "supportingInformation_MedicationAdministration", projectJSON, sourceType, - "PractitionerRole", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "family_member_history_participant") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14477,12 +14360,12 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("participant", id), - "family_member_history_participant", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", projectJSON, + refType, sourceType, - "participant", )) } } @@ -14492,16 +14375,17 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Participant != nil { - for _, item_3_x_Participant := range x.Participant { - if item_3_x_Participant != nil { - if item_3_x_Participant.Actor != nil { - if item_3_x_Participant.Actor.Reference != nil { - refVal := *item_3_x_Participant.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "participant_actor_Patient") + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_MedicationStatement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14510,14 +14394,14 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Patient", targetID), - "participant_actor_Patient", + collectionID(refType, targetID), + "supportingInformation_MedicationStatement", projectJSON, sourceType, - "Patient", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "family_member_history_participant") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14525,12 +14409,12 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("participant", id), - "family_member_history_participant", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", projectJSON, + refType, sourceType, - "participant", )) } } @@ -14540,16 +14424,17 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Participant != nil { - for _, item_3_x_Participant := range x.Participant { - if item_3_x_Participant != nil { - if item_3_x_Participant.Actor != nil { - if item_3_x_Participant.Actor.Reference != nil { - refVal := *item_3_x_Participant.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "participant_actor_Organization") + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_MedicationRequest") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14558,14 +14443,14 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Organization", targetID), - "participant_actor_Organization", + collectionID(refType, targetID), + "supportingInformation_MedicationRequest", projectJSON, sourceType, - "Organization", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "family_member_history_participant") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14573,12 +14458,12 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("participant", id), - "family_member_history_participant", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", projectJSON, + refType, sourceType, - "participant", )) } } @@ -14588,16 +14473,17 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Organization") + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14606,14 +14492,14 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Organization", targetID), - "reason_reference_Organization", + collectionID(refType, targetID), + "supportingInformation_Procedure", projectJSON, sourceType, - "Organization", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14621,12 +14507,12 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", projectJSON, + refType, sourceType, - "reference", )) } } @@ -14636,16 +14522,17 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Group") + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_DocumentReference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14654,14 +14541,14 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Group", targetID), - "reason_reference_Group", + collectionID(refType, targetID), + "supportingInformation_DocumentReference", projectJSON, sourceType, - "Group", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14669,12 +14556,12 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", projectJSON, + refType, sourceType, - "reference", )) } } @@ -14684,32 +14571,33 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } if _, exists := seen[forwardKey]; !exists { seen[forwardKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "reason_reference_Practitioner", + collectionID(refType, targetID), + "supportingInformation_Task", projectJSON, sourceType, - "Practitioner", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14717,12 +14605,12 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", projectJSON, + refType, sourceType, - "reference", )) } } @@ -14732,16 +14620,17 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_PractitionerRole") + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_ImagingStudy") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14750,14 +14639,14 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "reason_reference_PractitionerRole", + collectionID(refType, targetID), + "supportingInformation_ImagingStudy", projectJSON, sourceType, - "PractitionerRole", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14765,12 +14654,12 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", projectJSON, + refType, sourceType, - "reference", )) } } @@ -14780,16 +14669,17 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchStudy") + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_FamilyMemberHistory") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14798,14 +14688,14 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "reason_reference_ResearchStudy", + collectionID(refType, targetID), + "supportingInformation_FamilyMemberHistory", projectJSON, sourceType, - "ResearchStudy", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14813,12 +14703,12 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", projectJSON, + refType, sourceType, - "reference", )) } } @@ -14828,16 +14718,17 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Patient") + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_BodyStructure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14846,14 +14737,14 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Patient", targetID), - "reason_reference_Patient", + collectionID(refType, targetID), + "supportingInformation_BodyStructure", projectJSON, sourceType, - "Patient", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -14861,12 +14752,12 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_administration", projectJSON, + refType, sourceType, - "reference", )) } } @@ -14876,46 +14767,49 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "reason_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -14924,46 +14818,49 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "reason_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -14972,46 +14869,49 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "reason_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15020,46 +14920,49 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "reason_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15068,46 +14971,49 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "reason_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15116,46 +15022,49 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "reason_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15164,46 +15073,49 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "reason_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15212,46 +15124,49 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "reason_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15260,46 +15175,49 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "reason_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15308,46 +15226,49 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "reason_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15356,46 +15277,49 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "reason_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15404,46 +15328,49 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "reason_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15452,46 +15379,49 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "reason_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15500,46 +15430,49 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "reason_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15548,46 +15481,49 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "reason_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15596,46 +15532,49 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "reason_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15644,46 +15583,49 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "reason_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15692,63 +15634,49 @@ func (x *FamilyMemberHistory) ExtractEdges(project string) ([]json.RawMessage, e } } } - return edges, nil -} - -// ExtractEdges extracts graph links from FamilyMemberHistoryCondition. -func (x *FamilyMemberHistoryCondition) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "FamilyMemberHistoryCondition" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "note_authorReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15757,46 +15685,49 @@ func (x *FamilyMemberHistoryCondition) ExtractEdges(project string) ([]json.RawM } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "note_authorReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15805,46 +15736,49 @@ func (x *FamilyMemberHistoryCondition) ExtractEdges(project string) ([]json.RawM } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "note_authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15853,46 +15787,49 @@ func (x *FamilyMemberHistoryCondition) ExtractEdges(project string) ([]json.RawM } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "note_authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -15901,248 +15838,49 @@ func (x *FamilyMemberHistoryCondition) ExtractEdges(project string) ([]json.RawM } } } - return edges, nil -} - -// ExtractEdges extracts graph links from FamilyMemberHistoryParticipant. -func (x *FamilyMemberHistoryParticipant) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "FamilyMemberHistoryParticipant" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "actor_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "actor_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "family_member_history_participant") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("participant", id), - "family_member_history_participant", - projectJSON, - sourceType, - "participant", - )) - } - } - } - } - } - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "actor_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "actor_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "family_member_history_participant") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("participant", id), - "family_member_history_participant", - projectJSON, - sourceType, - "participant", - )) - } - } - } - } - } - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "actor_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "actor_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "family_member_history_participant") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("participant", id), - "family_member_history_participant", - projectJSON, - sourceType, - "participant", - )) - } - } - } - } - } - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "actor_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "actor_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "family_member_history_participant") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("participant", id), - "family_member_history_participant", - projectJSON, - sourceType, - "participant", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from FamilyMemberHistoryProcedure. -func (x *FamilyMemberHistoryProcedure) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "FamilyMemberHistoryProcedure" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "note_authorReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -16151,46 +15889,49 @@ func (x *FamilyMemberHistoryProcedure) ExtractEdges(project string) ([]json.RawM } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "note_authorReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -16199,47 +15940,46 @@ func (x *FamilyMemberHistoryProcedure) ExtractEdges(project string) ([]json.RawM } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "note_authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -16247,47 +15987,46 @@ func (x *FamilyMemberHistoryProcedure) ExtractEdges(project string) ([]json.RawM } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "note_authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -16295,190 +16034,187 @@ func (x *FamilyMemberHistoryProcedure) ExtractEdges(project string) ([]json.RawM } } } - return edges, nil -} - -// ExtractEdges extracts graph links from Group. -func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Group" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.ManagingEntity != nil { - if x.ManagingEntity.Reference != nil { - refVal := *x.ManagingEntity.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "managingEntity_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "managingEntity_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("group", id), - "group", - projectJSON, - sourceType, - "group", - )) + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } - if x.ManagingEntity != nil { - if x.ManagingEntity.Reference != nil { - refVal := *x.ManagingEntity.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "managingEntity_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "managingEntity_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("group", id), - "group", - projectJSON, - sourceType, - "group", - )) + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } - if x.ManagingEntity != nil { - if x.ManagingEntity.Reference != nil { - refVal := *x.ManagingEntity.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "managingEntity_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "managingEntity_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("group", id), - "group", - projectJSON, - sourceType, - "group", - )) + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "characteristic_valueReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -16486,47 +16222,46 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "characteristic_valueReference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -16534,47 +16269,46 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "characteristic_valueReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -16582,47 +16316,46 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "characteristic_valueReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -16630,47 +16363,46 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "characteristic_valueReference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -16678,47 +16410,46 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "characteristic_valueReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -16726,47 +16457,46 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "characteristic_valueReference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -16774,47 +16504,46 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "characteristic_valueReference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -16822,47 +16551,46 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "characteristic_valueReference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -16870,47 +16598,46 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "characteristic_valueReference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -16918,47 +16645,46 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "characteristic_valueReference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -16966,47 +16692,46 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "characteristic_valueReference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -17014,47 +16739,46 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "characteristic_valueReference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -17062,47 +16786,46 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "characteristic_valueReference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -17110,47 +16833,46 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "characteristic_valueReference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -17158,47 +16880,46 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "characteristic_valueReference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -17206,47 +16927,46 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "characteristic_valueReference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -17254,46 +16974,96 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "characteristic_valueReference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -17302,46 +17072,49 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "characteristic_valueReference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -17350,46 +17123,49 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "characteristic_valueReference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -17398,46 +17174,49 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "characteristic_valueReference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -17446,46 +17225,49 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "characteristic_valueReference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -17494,46 +17276,49 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Characteristic != nil { - for _, item_3_x_Characteristic := range x.Characteristic { - if item_3_x_Characteristic != nil { - if item_3_x_Characteristic.ValueReference != nil { - if item_3_x_Characteristic.ValueReference.Reference != nil { - refVal := *item_3_x_Characteristic.ValueReference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "characteristic_valueReference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "characteristic_valueReference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -17542,46 +17327,49 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Member != nil { - for _, item_3_x_Member := range x.Member { - if item_3_x_Member != nil { - if item_3_x_Member.Entity != nil { - if item_3_x_Member.Entity.Reference != nil { - refVal := *item_3_x_Member.Entity.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "member_entity_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "member_entity_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_member") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("member", id), - "group_member", - projectJSON, - sourceType, - "member", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -17590,46 +17378,49 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Member != nil { - for _, item_3_x_Member := range x.Member { - if item_3_x_Member != nil { - if item_3_x_Member.Entity != nil { - if item_3_x_Member.Entity.Reference != nil { - refVal := *item_3_x_Member.Entity.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "member_entity_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "member_entity_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_member") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("member", id), - "group_member", - projectJSON, - sourceType, - "member", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -17638,46 +17429,49 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Member != nil { - for _, item_3_x_Member := range x.Member { - if item_3_x_Member != nil { - if item_3_x_Member.Entity != nil { - if item_3_x_Member.Entity.Reference != nil { - refVal := *item_3_x_Member.Entity.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "member_entity_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "member_entity_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_member") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("member", id), - "group_member", - projectJSON, - sourceType, - "member", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -17686,46 +17480,49 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Member != nil { - for _, item_3_x_Member := range x.Member { - if item_3_x_Member != nil { - if item_3_x_Member.Entity != nil { - if item_3_x_Member.Entity.Reference != nil { - refVal := *item_3_x_Member.Entity.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "member_entity_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "member_entity_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_member") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("member", id), - "group_member", - projectJSON, - sourceType, - "member", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -17734,46 +17531,49 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Member != nil { - for _, item_3_x_Member := range x.Member { - if item_3_x_Member != nil { - if item_3_x_Member.Entity != nil { - if item_3_x_Member.Entity.Reference != nil { - refVal := *item_3_x_Member.Entity.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "member_entity_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "member_entity_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_member") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("member", id), - "group_member", - projectJSON, - sourceType, - "member", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -17782,46 +17582,49 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Member != nil { - for _, item_3_x_Member := range x.Member { - if item_3_x_Member != nil { - if item_3_x_Member.Entity != nil { - if item_3_x_Member.Entity.Reference != nil { - refVal := *item_3_x_Member.Entity.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "member_entity_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "member_entity_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_member") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("member", id), - "group_member", - projectJSON, - sourceType, - "member", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -17830,1390 +17633,203 @@ func (x *Group) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - return edges, nil -} - -// ExtractEdges extracts graph links from GroupCharacteristic. -func (x *GroupCharacteristic) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "GroupCharacteristic" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "valueReference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "valueReference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "valueReference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "valueReference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "valueReference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "valueReference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "valueReference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "valueReference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "valueReference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "valueReference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "valueReference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "valueReference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "valueReference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "valueReference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "valueReference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "valueReference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "valueReference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "valueReference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "valueReference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_characteristic") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("characteristic", id), - "group_characteristic", - projectJSON, - sourceType, - "characteristic", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - return edges, nil -} - -// ExtractEdges extracts graph links from GroupMember. -func (x *GroupMember) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "GroupMember" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Entity != nil { - if x.Entity.Reference != nil { - refVal := *x.Entity.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "entity_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "entity_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_member") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("member", id), - "group_member", - projectJSON, - sourceType, - "member", - )) - } - } - } - } - } - if x.Entity != nil { - if x.Entity.Reference != nil { - refVal := *x.Entity.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "entity_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "entity_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_member") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("member", id), - "group_member", - projectJSON, - sourceType, - "member", - )) - } - } - } - } - } - if x.Entity != nil { - if x.Entity.Reference != nil { - refVal := *x.Entity.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "entity_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "entity_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_member") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("member", id), - "group_member", - projectJSON, - sourceType, - "member", - )) - } - } - } - } - } - if x.Entity != nil { - if x.Entity.Reference != nil { - refVal := *x.Entity.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "entity_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "entity_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_member") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("member", id), - "group_member", - projectJSON, - sourceType, - "member", - )) - } - } - } - } - } - if x.Entity != nil { - if x.Entity.Reference != nil { - refVal := *x.Entity.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "entity_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "entity_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_member") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("member", id), - "group_member", - projectJSON, - sourceType, - "member", - )) - } - } - } - } - } - if x.Entity != nil { - if x.Entity.Reference != nil { - refVal := *x.Entity.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "entity_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "entity_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "group_member") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("member", id), - "group_member", - projectJSON, - sourceType, - "member", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - return edges, nil -} - -// ExtractEdges extracts graph links from HumanName. -func (x *HumanName) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "HumanName" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from Identifier. -func (x *Identifier) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Identifier" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Assigner != nil { - if x.Assigner.Reference != nil { - refVal := *x.Assigner.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "assigner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("assigner", targetID), - "assigner", - projectJSON, - sourceType, - "assigner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "identifier") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("identifier", id), - "identifier", - projectJSON, - sourceType, - "identifier", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - return edges, nil -} - -// ExtractEdges extracts graph links from ImagingStudy. -func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ImagingStudy" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "basedOn_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_imaging_study") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("study", id), - "basedOn_imaging_study", - projectJSON, - sourceType, - "study", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -19221,45 +17837,50 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.PartOf != nil { - for _, item_2_x_PartOf := range x.PartOf { - if item_2_x_PartOf != nil { - if item_2_x_PartOf.Reference != nil { - refVal := *item_2_x_PartOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "partOf") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("partOf", targetID), - "partOf", - projectJSON, - sourceType, - "partOf", - )) - } - backrefKey := getEdgeUUID(id, targetID, "partOf_imaging_study") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("study", id), - "partOf_imaging_study", - projectJSON, - sourceType, - "study", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -19267,214 +17888,253 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Referrer != nil { - if x.Referrer.Reference != nil { - refVal := *x.Referrer.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "referrer_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "referrer_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "imaging_study") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("study", id), - "imaging_study", - projectJSON, - sourceType, - "study", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Referrer != nil { - if x.Referrer.Reference != nil { - refVal := *x.Referrer.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "referrer_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "referrer_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "imaging_study") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("study", id), - "imaging_study", - projectJSON, - sourceType, - "study", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "subject_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "subject_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "imaging_study") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("study", id), - "imaging_study", - projectJSON, - sourceType, - "study", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "subject_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "subject_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "imaging_study") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("study", id), - "imaging_study", - projectJSON, - sourceType, - "study", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "note_authorReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -19483,46 +18143,49 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "note_authorReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -19531,46 +18194,49 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "note_authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -19579,46 +18245,49 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "note_authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -19627,46 +18296,49 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "procedure_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -19675,16 +18347,85 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Group") + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + return edges, nil +} + +// ExtractEdges extracts graph links from MedicationRequest. +func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "MedicationRequest" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_MedicationRequest") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -19693,14 +18434,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Group", targetID), - "procedure_reference_Group", + collectionID(refType, targetID), + "basedOn_MedicationRequest", projectJSON, sourceType, - "Group", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "basedOn_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -19708,12 +18449,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -19723,16 +18464,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.InformationSource != nil { + for _, item_2_x_InformationSource := range x.InformationSource { + if item_2_x_InformationSource != nil { + if item_2_x_InformationSource.Reference != nil { + refVal := *item_2_x_InformationSource.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Practitioner") + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "informationSource_Patient") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -19741,14 +18483,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "procedure_reference_Practitioner", + collectionID(refType, targetID), + "informationSource_Patient", projectJSON, sourceType, - "Practitioner", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "informationSource_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -19756,12 +18498,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "informationSource_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -19771,16 +18513,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.InformationSource != nil { + for _, item_2_x_InformationSource := range x.InformationSource { + if item_2_x_InformationSource != nil { + if item_2_x_InformationSource.Reference != nil { + refVal := *item_2_x_InformationSource.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_PractitionerRole") + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "informationSource_Practitioner") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -19789,14 +18532,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "procedure_reference_PractitionerRole", + collectionID(refType, targetID), + "informationSource_Practitioner", projectJSON, sourceType, - "PractitionerRole", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "informationSource_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -19804,12 +18547,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "informationSource_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -19819,16 +18562,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.InformationSource != nil { + for _, item_2_x_InformationSource := range x.InformationSource { + if item_2_x_InformationSource != nil { + if item_2_x_InformationSource.Reference != nil { + refVal := *item_2_x_InformationSource.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_ResearchStudy") + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "informationSource_PractitionerRole") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -19837,14 +18581,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "procedure_reference_ResearchStudy", + collectionID(refType, targetID), + "informationSource_PractitionerRole", projectJSON, sourceType, - "ResearchStudy", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "informationSource_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -19852,12 +18596,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "informationSource_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -19867,16 +18611,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.InformationSource != nil { + for _, item_2_x_InformationSource := range x.InformationSource { + if item_2_x_InformationSource != nil { + if item_2_x_InformationSource.Reference != nil { + refVal := *item_2_x_InformationSource.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Patient") + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "informationSource_Organization") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -19885,14 +18630,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Patient", targetID), - "procedure_reference_Patient", + collectionID(refType, targetID), + "informationSource_Organization", projectJSON, sourceType, - "Patient", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "informationSource_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -19900,12 +18645,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "informationSource_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -19915,16 +18660,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Performer != nil { + for _, item_2_x_Performer := range x.Performer { + if item_2_x_Performer != nil { + if item_2_x_Performer.Reference != nil { + refVal := *item_2_x_Performer.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_ResearchSubject") + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "performer_Practitioner") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -19933,14 +18679,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "procedure_reference_ResearchSubject", + collectionID(refType, targetID), + "performer_Practitioner", projectJSON, sourceType, - "ResearchSubject", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "performer_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -19948,12 +18694,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "performer_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -19963,16 +18709,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Performer != nil { + for _, item_2_x_Performer := range x.Performer { + if item_2_x_Performer != nil { + if item_2_x_Performer.Reference != nil { + refVal := *item_2_x_Performer.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Substance") + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "performer_PractitionerRole") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -19981,14 +18728,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Substance", targetID), - "procedure_reference_Substance", + collectionID(refType, targetID), + "performer_PractitionerRole", projectJSON, sourceType, - "Substance", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "performer_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -19996,12 +18743,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "performer_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20011,16 +18758,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Performer != nil { + for _, item_2_x_Performer := range x.Performer { + if item_2_x_Performer != nil { + if item_2_x_Performer.Reference != nil { + refVal := *item_2_x_Performer.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_SubstanceDefinition") + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "performer_Organization") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20029,14 +18777,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "procedure_reference_SubstanceDefinition", + collectionID(refType, targetID), + "performer_Organization", projectJSON, sourceType, - "SubstanceDefinition", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "performer_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20044,12 +18792,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "performer_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20059,16 +18807,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Performer != nil { + for _, item_2_x_Performer := range x.Performer { + if item_2_x_Performer != nil { + if item_2_x_Performer.Reference != nil { + refVal := *item_2_x_Performer.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Specimen") + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "performer_Patient") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20077,14 +18826,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Specimen", targetID), - "procedure_reference_Specimen", + collectionID(refType, targetID), + "performer_Patient", projectJSON, sourceType, - "Specimen", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "performer_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20092,12 +18841,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "performer_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20107,16 +18856,422 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.PriorPrescription != nil { + if x.PriorPrescription.Reference != nil { + refVal := *x.PriorPrescription.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "priorPrescription") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "priorPrescription", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "priorPrescription_medication_request") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "priorPrescription_medication_request", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Recorder != nil { + if x.Recorder.Reference != nil { + refVal := *x.Recorder.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "recorder_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "recorder_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "recorder_medication_request") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "recorder_medication_request", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Recorder != nil { + if x.Recorder.Reference != nil { + refVal := *x.Recorder.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "recorder_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "recorder_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "recorder_medication_request") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "recorder_medication_request", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Requester != nil { + if x.Requester.Reference != nil { + refVal := *x.Requester.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "requester_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requester_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "requester_medication_request") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "requester_medication_request", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Requester != nil { + if x.Requester.Reference != nil { + refVal := *x.Requester.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "requester_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requester_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "requester_medication_request") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "requester_medication_request", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Requester != nil { + if x.Requester.Reference != nil { + refVal := *x.Requester.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "requester_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requester_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "requester_medication_request") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "requester_medication_request", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Requester != nil { + if x.Requester.Reference != nil { + refVal := *x.Requester.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "requester_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requester_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "requester_medication_request") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "requester_medication_request", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "subject_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "subject_medication_request") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_medication_request", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "subject_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "subject_medication_request") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_medication_request", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Observation") + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Organization") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20125,14 +19280,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Observation", targetID), - "procedure_reference_Observation", + collectionID(refType, targetID), + "supportingInformation_Organization", projectJSON, sourceType, - "Observation", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20140,12 +19295,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20155,16 +19310,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_DiagnosticReport") + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Group") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20173,14 +19329,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "procedure_reference_DiagnosticReport", + collectionID(refType, targetID), + "supportingInformation_Group", projectJSON, sourceType, - "DiagnosticReport", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20188,12 +19344,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20203,16 +19359,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Condition") + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Practitioner") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20221,14 +19378,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Condition", targetID), - "procedure_reference_Condition", + collectionID(refType, targetID), + "supportingInformation_Practitioner", projectJSON, sourceType, - "Condition", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20236,12 +19393,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20251,16 +19408,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Medication") + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_PractitionerRole") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20269,14 +19427,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Medication", targetID), - "procedure_reference_Medication", + collectionID(refType, targetID), + "supportingInformation_PractitionerRole", projectJSON, sourceType, - "Medication", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20284,12 +19442,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20299,16 +19457,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_MedicationAdministration") + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_ResearchStudy") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20317,14 +19476,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "procedure_reference_MedicationAdministration", + collectionID(refType, targetID), + "supportingInformation_ResearchStudy", projectJSON, sourceType, - "MedicationAdministration", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20332,12 +19491,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20347,16 +19506,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_MedicationStatement") + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Patient") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20365,14 +19525,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "procedure_reference_MedicationStatement", + collectionID(refType, targetID), + "supportingInformation_Patient", projectJSON, sourceType, - "MedicationStatement", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20380,12 +19540,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20395,16 +19555,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_MedicationRequest") + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_ResearchSubject") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20413,14 +19574,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "procedure_reference_MedicationRequest", + collectionID(refType, targetID), + "supportingInformation_ResearchSubject", projectJSON, sourceType, - "MedicationRequest", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20428,12 +19589,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20443,16 +19604,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Procedure") + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Substance") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20461,14 +19623,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Procedure", targetID), - "procedure_reference_Procedure", + collectionID(refType, targetID), + "supportingInformation_Substance", projectJSON, sourceType, - "Procedure", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20476,12 +19638,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20491,16 +19653,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_DocumentReference") + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_SubstanceDefinition") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20509,14 +19672,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "procedure_reference_DocumentReference", + collectionID(refType, targetID), + "supportingInformation_SubstanceDefinition", projectJSON, sourceType, - "DocumentReference", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20524,12 +19687,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20539,16 +19702,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_Task") + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Specimen") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20557,14 +19721,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Task", targetID), - "procedure_reference_Task", + collectionID(refType, targetID), + "supportingInformation_Specimen", projectJSON, sourceType, - "Task", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20572,12 +19736,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20587,16 +19751,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_ImagingStudy") + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Observation") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20605,14 +19770,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "procedure_reference_ImagingStudy", + collectionID(refType, targetID), + "supportingInformation_Observation", projectJSON, sourceType, - "ImagingStudy", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20620,12 +19785,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20635,16 +19800,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_FamilyMemberHistory") + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_DiagnosticReport") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20653,14 +19819,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "procedure_reference_FamilyMemberHistory", + collectionID(refType, targetID), + "supportingInformation_DiagnosticReport", projectJSON, sourceType, - "FamilyMemberHistory", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20668,12 +19834,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20683,16 +19849,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Procedure != nil { - for _, item_3_x_Procedure := range x.Procedure { - if item_3_x_Procedure != nil { - if item_3_x_Procedure.Reference != nil { - if item_3_x_Procedure.Reference.Reference != nil { - refVal := *item_3_x_Procedure.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "procedure_reference_BodyStructure") + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Condition") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20701,14 +19868,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "procedure_reference_BodyStructure", + collectionID(refType, targetID), + "supportingInformation_Condition", projectJSON, sourceType, - "BodyStructure", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20716,12 +19883,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20731,16 +19898,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Organization") + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Medication") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20749,14 +19917,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Organization", targetID), - "reason_reference_Organization", + collectionID(refType, targetID), + "supportingInformation_Medication", projectJSON, sourceType, - "Organization", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20764,12 +19932,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20779,16 +19947,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Group") + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_MedicationAdministration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20797,14 +19966,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Group", targetID), - "reason_reference_Group", + collectionID(refType, targetID), + "supportingInformation_MedicationAdministration", projectJSON, sourceType, - "Group", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20812,12 +19981,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20827,16 +19996,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Practitioner") + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_MedicationStatement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20845,14 +20015,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "reason_reference_Practitioner", + collectionID(refType, targetID), + "supportingInformation_MedicationStatement", projectJSON, sourceType, - "Practitioner", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20860,12 +20030,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20875,16 +20045,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_PractitionerRole") + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_MedicationRequest") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20893,14 +20064,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "reason_reference_PractitionerRole", + collectionID(refType, targetID), + "supportingInformation_MedicationRequest", projectJSON, sourceType, - "PractitionerRole", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20908,12 +20079,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20923,16 +20094,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchStudy") + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20941,14 +20113,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "reason_reference_ResearchStudy", + collectionID(refType, targetID), + "supportingInformation_Procedure", projectJSON, sourceType, - "ResearchStudy", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20956,12 +20128,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -20971,16 +20143,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Patient") + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_DocumentReference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -20989,14 +20162,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Patient", targetID), - "reason_reference_Patient", + collectionID(refType, targetID), + "supportingInformation_DocumentReference", projectJSON, sourceType, - "Patient", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -21004,12 +20177,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -21019,16 +20192,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchSubject") + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Task") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -21037,14 +20211,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "reason_reference_ResearchSubject", + collectionID(refType, targetID), + "supportingInformation_Task", projectJSON, sourceType, - "ResearchSubject", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -21052,12 +20226,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -21067,16 +20241,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Substance") + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_ImagingStudy") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -21085,14 +20260,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Substance", targetID), - "reason_reference_Substance", + collectionID(refType, targetID), + "supportingInformation_ImagingStudy", projectJSON, sourceType, - "Substance", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -21100,12 +20275,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -21115,16 +20290,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_SubstanceDefinition") + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_FamilyMemberHistory") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -21133,14 +20309,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "reason_reference_SubstanceDefinition", + collectionID(refType, targetID), + "supportingInformation_FamilyMemberHistory", projectJSON, sourceType, - "SubstanceDefinition", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -21148,12 +20324,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -21163,16 +20339,17 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInformation != nil { + for _, item_2_x_SupportingInformation := range x.SupportingInformation { + if item_2_x_SupportingInformation != nil { + if item_2_x_SupportingInformation.Reference != nil { + refVal := *item_2_x_SupportingInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Specimen") + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "supportingInformation_BodyStructure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -21181,14 +20358,14 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Specimen", targetID), - "reason_reference_Specimen", + collectionID(refType, targetID), + "supportingInformation_BodyStructure", projectJSON, sourceType, - "Specimen", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -21196,12 +20373,12 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInformation_medication_request", projectJSON, + refType, sourceType, - "reference", )) } } @@ -21211,46 +20388,49 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "reason_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -21259,46 +20439,49 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "reason_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -21307,46 +20490,49 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "reason_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -21355,46 +20541,49 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "reason_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -21403,46 +20592,49 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "reason_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -21451,46 +20643,49 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "reason_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -21499,46 +20694,49 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "reason_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -21547,46 +20745,49 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "reason_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -21595,46 +20796,49 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "reason_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -21643,46 +20847,49 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "reason_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -21691,46 +20898,151 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "reason_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) + } + } + } + } + } + } + } + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + } + } + } + } + } + } + } + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -21739,46 +21051,202 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "reason_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) + } + } + } + } + } + } + } + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) + } + } + } + } + } + } + } + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + } + } + } + } + } + } + } + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -21787,46 +21255,202 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "reason_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) + } + } + } + } + } + } + } + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) + } + } + } + } + } + } + } + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + } + } + } + } + } + } + } + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -21835,49 +21459,48 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Series != nil { - for _, item_4_x_Series := range x.Series { - if item_4_x_Series != nil { - if item_4_x_Series.Specimen != nil { - for _, item_2_item_4_x_Series_Specimen := range item_4_x_Series.Specimen { - if item_2_item_4_x_Series_Specimen != nil { - if item_2_item_4_x_Series_Specimen.Reference != nil { - refVal := *item_2_item_4_x_Series_Specimen.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "series_specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("specimen", targetID), - "series_specimen", - projectJSON, - sourceType, - "specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "specimen_imaging_study_series") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("series", id), - "specimen_imaging_study_series", - projectJSON, - sourceType, - "series", - )) - } + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -21887,32 +21510,67 @@ func (x *ImagingStudy) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - return edges, nil -} - -// ExtractEdges extracts graph links from ImagingStudySeries. -func (x *ImagingStudySeries) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil + if x.Device != nil { + for _, item_3_x_Device := range x.Device { + if item_3_x_Device != nil { + if item_3_x_Device.Reference != nil { + if item_3_x_Device.Reference.Reference != nil { + refVal := *item_3_x_Device.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "device_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "device_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } } - id := *x.ID - sourceType := "ImagingStudySeries" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Specimen != nil { - for _, item_2_x_Specimen := range x.Specimen { - if item_2_x_Specimen != nil { - if item_2_x_Specimen.Reference != nil { - refVal := *item_2_x_Specimen.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DispenseRequest != nil { + if x.DispenseRequest.Dispenser != nil { + if x.DispenseRequest.Dispenser.Reference != nil { + refVal := *x.DispenseRequest.Dispenser.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "specimen") + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "dispenseRequest_dispenser") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -21921,14 +21579,14 @@ func (x *ImagingStudySeries) ExtractEdges(project string) ([]json.RawMessage, er edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("specimen", targetID), - "specimen", + collectionID(refType, targetID), + "dispenseRequest_dispenser", projectJSON, sourceType, - "specimen", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "specimen_imaging_study_series") + backrefKey := getEdgeUUID(id, targetID, "medication_request_dispense_request") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -21936,12 +21594,12 @@ func (x *ImagingStudySeries) ExtractEdges(project string) ([]json.RawMessage, er seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("series", id), - "specimen_imaging_study_series", + collectionID(refType, targetID), + collectionID(sourceType, id), + "medication_request_dispense_request", projectJSON, + refType, sourceType, - "series", )) } } @@ -21950,1497 +21608,1003 @@ func (x *ImagingStudySeries) ExtractEdges(project string) ([]json.RawMessage, er } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "bodySite_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "bodySite_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "bodySite_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "bodySite_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "bodySite_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "bodySite_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "bodySite_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "bodySite_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "bodySite_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "bodySite_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "bodySite_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "bodySite_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "bodySite_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "bodySite_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "bodySite_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "bodySite_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "bodySite_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "bodySite_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "bodySite_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "bodySite_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "bodySite_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "bodySite_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "bodySite_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Performer != nil { - for _, item_3_x_Performer := range x.Performer { - if item_3_x_Performer != nil { - if item_3_x_Performer.Actor != nil { - if item_3_x_Performer.Actor.Reference != nil { - refVal := *item_3_x_Performer.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "performer_actor_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "performer_actor_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "imaging_study_series_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "imaging_study_series_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - } - } - } - if x.Performer != nil { - for _, item_3_x_Performer := range x.Performer { - if item_3_x_Performer != nil { - if item_3_x_Performer.Actor != nil { - if item_3_x_Performer.Actor.Reference != nil { - refVal := *item_3_x_Performer.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "performer_actor_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "performer_actor_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "imaging_study_series_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "imaging_study_series_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - } - } - } - if x.Performer != nil { - for _, item_3_x_Performer := range x.Performer { - if item_3_x_Performer != nil { - if item_3_x_Performer.Actor != nil { - if item_3_x_Performer.Actor.Reference != nil { - refVal := *item_3_x_Performer.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "performer_actor_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "performer_actor_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "imaging_study_series_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "imaging_study_series_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - } - } - } - if x.Performer != nil { - for _, item_3_x_Performer := range x.Performer { - if item_3_x_Performer != nil { - if item_3_x_Performer.Actor != nil { - if item_3_x_Performer.Actor.Reference != nil { - refVal := *item_3_x_Performer.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "performer_actor_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "performer_actor_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "imaging_study_series_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "imaging_study_series_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from ImagingStudySeriesInstance. -func (x *ImagingStudySeriesInstance) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ImagingStudySeriesInstance" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from ImagingStudySeriesPerformer. -func (x *ImagingStudySeriesPerformer) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ImagingStudySeriesPerformer" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "actor_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "actor_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "imaging_study_series_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "imaging_study_series_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "actor_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "actor_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "imaging_study_series_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "imaging_study_series_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "actor_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "actor_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "imaging_study_series_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "imaging_study_series_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "actor_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "actor_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "imaging_study_series_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "imaging_study_series_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from Medication. -func (x *Medication) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Medication" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.MarketingAuthorizationHolder != nil { - if x.MarketingAuthorizationHolder.Reference != nil { - refVal := *x.MarketingAuthorizationHolder.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "marketingAuthorizationHolder") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("marketingAuthorizationHolder", targetID), - "marketingAuthorizationHolder", - projectJSON, - sourceType, - "marketingAuthorizationHolder", - )) - } - backrefKey := getEdgeUUID(id, targetID, "medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("medication", id), - "medication", - projectJSON, - sourceType, - "medication", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from MedicationAdministration. -func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "MedicationAdministration" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.PartOf != nil { - for _, item_2_x_PartOf := range x.PartOf { - if item_2_x_PartOf != nil { - if item_2_x_PartOf.Reference != nil { - refVal := *item_2_x_PartOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "partOf_MedicationAdministration") + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_FamilyMemberHistory") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -23449,14 +22613,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "partOf_MedicationAdministration", + collectionID(refType, targetID), + "medication_reference_FamilyMemberHistory", projectJSON, sourceType, - "MedicationAdministration", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "partOf_medication_administration") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -23464,12 +22628,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "partOf_medication_administration", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "administration", )) } } @@ -23478,15 +22642,16 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.PartOf != nil { - for _, item_2_x_PartOf := range x.PartOf { - if item_2_x_PartOf != nil { - if item_2_x_PartOf.Reference != nil { - refVal := *item_2_x_PartOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "partOf_Procedure") + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_BodyStructure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -23495,14 +22660,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Procedure", targetID), - "partOf_Procedure", + collectionID(refType, targetID), + "medication_reference_BodyStructure", projectJSON, sourceType, - "Procedure", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "partOf_medication_administration") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -23510,12 +22675,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "partOf_medication_administration", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "administration", )) } } @@ -23524,171 +22689,203 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Request != nil { - if x.Request.Reference != nil { - refVal := *x.Request.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("request", targetID), - "request", - projectJSON, - sourceType, - "request", - )) - } - backrefKey := getEdgeUUID(id, targetID, "medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "subject_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "subject_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "subject_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "subject_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "supportingInformation_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -23696,45 +22893,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "supportingInformation_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -23742,45 +22944,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "supportingInformation_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -23788,45 +22995,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "supportingInformation_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -23834,45 +23046,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "supportingInformation_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -23880,45 +23097,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "supportingInformation_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -23926,45 +23148,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "supportingInformation_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -23972,45 +23199,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "supportingInformation_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -24018,45 +23250,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "supportingInformation_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -24064,45 +23301,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "supportingInformation_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -24110,45 +23352,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "supportingInformation_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -24156,45 +23403,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "supportingInformation_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -24202,45 +23454,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "supportingInformation_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -24248,45 +23505,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "supportingInformation_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -24294,45 +23556,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "supportingInformation_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -24340,45 +23607,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "supportingInformation_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -24386,45 +23658,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "supportingInformation_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -24432,45 +23709,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "supportingInformation_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -24478,45 +23760,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "supportingInformation_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -24524,45 +23811,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "supportingInformation_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -24570,45 +23862,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "supportingInformation_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -24616,45 +23913,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "supportingInformation_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -24662,45 +23964,50 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "supportingInformation_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_administration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("administration", id), - "supportingInformation_medication_administration", - projectJSON, - sourceType, - "administration", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -24708,16 +24015,85 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + return edges, nil +} + +// ExtractEdges extracts graph links from MedicationStatement. +func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "MedicationStatement" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Organization") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Organization") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -24726,14 +24102,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Organization", targetID), - "device_reference_Organization", + collectionID(refType, targetID), + "derivedFrom_Organization", projectJSON, sourceType, - "Organization", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -24741,12 +24117,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -24756,16 +24132,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Group") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Group") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -24774,14 +24151,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Group", targetID), - "device_reference_Group", + collectionID(refType, targetID), + "derivedFrom_Group", projectJSON, sourceType, - "Group", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -24789,12 +24166,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -24804,16 +24181,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Practitioner") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Practitioner") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -24822,14 +24200,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "device_reference_Practitioner", + collectionID(refType, targetID), + "derivedFrom_Practitioner", projectJSON, sourceType, - "Practitioner", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -24837,12 +24215,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -24852,16 +24230,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_PractitionerRole") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_PractitionerRole") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -24870,14 +24249,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "device_reference_PractitionerRole", + collectionID(refType, targetID), + "derivedFrom_PractitionerRole", projectJSON, sourceType, - "PractitionerRole", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -24885,12 +24264,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -24900,16 +24279,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_ResearchStudy") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_ResearchStudy") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -24918,14 +24298,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "device_reference_ResearchStudy", + collectionID(refType, targetID), + "derivedFrom_ResearchStudy", projectJSON, sourceType, - "ResearchStudy", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -24933,12 +24313,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -24948,16 +24328,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Patient") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Patient") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -24966,14 +24347,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Patient", targetID), - "device_reference_Patient", + collectionID(refType, targetID), + "derivedFrom_Patient", projectJSON, sourceType, - "Patient", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -24981,12 +24362,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -24996,16 +24377,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_ResearchSubject") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_ResearchSubject") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25014,14 +24396,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "device_reference_ResearchSubject", + collectionID(refType, targetID), + "derivedFrom_ResearchSubject", projectJSON, sourceType, - "ResearchSubject", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25029,12 +24411,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -25044,16 +24426,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Substance") + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Substance") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25062,14 +24445,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Substance", targetID), - "device_reference_Substance", + collectionID(refType, targetID), + "derivedFrom_Substance", projectJSON, sourceType, - "Substance", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25077,12 +24460,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -25092,16 +24475,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_SubstanceDefinition") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_SubstanceDefinition") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25110,14 +24494,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "device_reference_SubstanceDefinition", + collectionID(refType, targetID), + "derivedFrom_SubstanceDefinition", projectJSON, sourceType, - "SubstanceDefinition", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25125,12 +24509,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -25140,16 +24524,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Specimen") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Specimen") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25158,14 +24543,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Specimen", targetID), - "device_reference_Specimen", + collectionID(refType, targetID), + "derivedFrom_Specimen", projectJSON, sourceType, - "Specimen", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25173,12 +24558,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -25188,16 +24573,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Observation") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Observation") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25206,14 +24592,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Observation", targetID), - "device_reference_Observation", + collectionID(refType, targetID), + "derivedFrom_Observation", projectJSON, sourceType, - "Observation", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25221,12 +24607,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -25236,16 +24622,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_DiagnosticReport") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_DiagnosticReport") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25254,14 +24641,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "device_reference_DiagnosticReport", + collectionID(refType, targetID), + "derivedFrom_DiagnosticReport", projectJSON, sourceType, - "DiagnosticReport", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25269,12 +24656,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -25284,16 +24671,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Condition") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Condition") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25302,14 +24690,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Condition", targetID), - "device_reference_Condition", + collectionID(refType, targetID), + "derivedFrom_Condition", projectJSON, sourceType, - "Condition", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25317,12 +24705,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -25332,16 +24720,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Medication") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Medication") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25350,14 +24739,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Medication", targetID), - "device_reference_Medication", + collectionID(refType, targetID), + "derivedFrom_Medication", projectJSON, sourceType, - "Medication", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25365,12 +24754,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -25380,16 +24769,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_MedicationAdministration") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_MedicationAdministration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25398,14 +24788,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "device_reference_MedicationAdministration", + collectionID(refType, targetID), + "derivedFrom_MedicationAdministration", projectJSON, sourceType, - "MedicationAdministration", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25413,12 +24803,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -25428,16 +24818,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_MedicationStatement") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_MedicationStatement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25446,14 +24837,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "device_reference_MedicationStatement", + collectionID(refType, targetID), + "derivedFrom_MedicationStatement", projectJSON, sourceType, - "MedicationStatement", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25461,12 +24852,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -25476,16 +24867,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_MedicationRequest") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_MedicationRequest") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25494,14 +24886,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "device_reference_MedicationRequest", + collectionID(refType, targetID), + "derivedFrom_MedicationRequest", projectJSON, sourceType, - "MedicationRequest", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25509,12 +24901,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -25524,16 +24916,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Procedure") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25542,14 +24935,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Procedure", targetID), - "device_reference_Procedure", + collectionID(refType, targetID), + "derivedFrom_Procedure", projectJSON, sourceType, - "Procedure", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25557,12 +24950,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -25572,16 +24965,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_DocumentReference") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_DocumentReference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25590,14 +24984,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "device_reference_DocumentReference", + collectionID(refType, targetID), + "derivedFrom_DocumentReference", projectJSON, sourceType, - "DocumentReference", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25605,12 +24999,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -25620,16 +25014,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Task") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Task") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25638,14 +25033,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Task", targetID), - "device_reference_Task", + collectionID(refType, targetID), + "derivedFrom_Task", projectJSON, sourceType, - "Task", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25653,12 +25048,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -25668,16 +25063,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_ImagingStudy") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_ImagingStudy") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25686,14 +25082,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "device_reference_ImagingStudy", + collectionID(refType, targetID), + "derivedFrom_ImagingStudy", projectJSON, sourceType, - "ImagingStudy", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25701,12 +25097,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -25716,16 +25112,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_FamilyMemberHistory") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_FamilyMemberHistory") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25734,14 +25131,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "device_reference_FamilyMemberHistory", + collectionID(refType, targetID), + "derivedFrom_FamilyMemberHistory", projectJSON, sourceType, - "FamilyMemberHistory", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25749,12 +25146,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -25764,16 +25161,17 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_BodyStructure") + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_BodyStructure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25782,14 +25180,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "device_reference_BodyStructure", + collectionID(refType, targetID), + "derivedFrom_BodyStructure", projectJSON, sourceType, - "BodyStructure", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -25797,12 +25195,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -25812,278 +25210,407 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "medication_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.InformationSource != nil { + for _, item_2_x_InformationSource := range x.InformationSource { + if item_2_x_InformationSource != nil { + if item_2_x_InformationSource.Reference != nil { + refVal := *item_2_x_InformationSource.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "informationSource_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "informationSource_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "informationSource_medication_statement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "informationSource_medication_statement", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "medication_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.InformationSource != nil { + for _, item_2_x_InformationSource := range x.InformationSource { + if item_2_x_InformationSource != nil { + if item_2_x_InformationSource.Reference != nil { + refVal := *item_2_x_InformationSource.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "informationSource_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "informationSource_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "informationSource_medication_statement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "informationSource_medication_statement", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "medication_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.InformationSource != nil { + for _, item_2_x_InformationSource := range x.InformationSource { + if item_2_x_InformationSource != nil { + if item_2_x_InformationSource.Reference != nil { + refVal := *item_2_x_InformationSource.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "informationSource_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "informationSource_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "informationSource_medication_statement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "informationSource_medication_statement", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "medication_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.InformationSource != nil { + for _, item_2_x_InformationSource := range x.InformationSource { + if item_2_x_InformationSource != nil { + if item_2_x_InformationSource.Reference != nil { + refVal := *item_2_x_InformationSource.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "informationSource_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "informationSource_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "informationSource_medication_statement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "informationSource_medication_statement", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "medication_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.PartOf != nil { + for _, item_2_x_PartOf := range x.PartOf { + if item_2_x_PartOf != nil { + if item_2_x_PartOf.Reference != nil { + refVal := *item_2_x_PartOf.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "partOf_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "partOf_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "partOf_medication_statement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "partOf_medication_statement", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "medication_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) + if x.PartOf != nil { + for _, item_2_x_PartOf := range x.PartOf { + if item_2_x_PartOf != nil { + if item_2_x_PartOf.Reference != nil { + refVal := *item_2_x_PartOf.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "partOf_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "partOf_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "partOf_medication_statement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "partOf_medication_statement", + projectJSON, + refType, + sourceType, + )) + } + } } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) + } + } + } + } + } + if x.RelatedClinicalInformation != nil { + for _, item_2_x_RelatedClinicalInformation := range x.RelatedClinicalInformation { + if item_2_x_RelatedClinicalInformation != nil { + if item_2_x_RelatedClinicalInformation.Reference != nil { + refVal := *item_2_x_RelatedClinicalInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "relatedClinicalInformation_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedClinicalInformation_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "relatedClinicalInformation_medication_statement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "relatedClinicalInformation_medication_statement", + projectJSON, + refType, + sourceType, + )) + } + } } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + } + } + } + } + } + if x.RelatedClinicalInformation != nil { + for _, item_2_x_RelatedClinicalInformation := range x.RelatedClinicalInformation { + if item_2_x_RelatedClinicalInformation != nil { + if item_2_x_RelatedClinicalInformation.Reference != nil { + refVal := *item_2_x_RelatedClinicalInformation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "relatedClinicalInformation_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedClinicalInformation_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "relatedClinicalInformation_medication_statement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "relatedClinicalInformation_medication_statement", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_ResearchSubject") + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "subject_Patient") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -26092,14 +25619,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "medication_reference_ResearchSubject", + collectionID(refType, targetID), + "subject_Patient", projectJSON, sourceType, - "ResearchSubject", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "subject_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -26107,12 +25634,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -26120,14 +25647,15 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Substance") + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "subject_Group") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -26136,14 +25664,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Substance", targetID), - "medication_reference_Substance", + collectionID(refType, targetID), + "subject_Group", projectJSON, sourceType, - "Substance", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "subject_medication_statement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -26151,12 +25679,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_medication_statement", projectJSON, + refType, sourceType, - "reference", )) } } @@ -26170,38 +25698,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "medication_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -26214,38 +25745,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "medication_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -26258,38 +25792,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "medication_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -26302,38 +25839,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "medication_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -26346,38 +25886,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "medication_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -26390,38 +25933,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "medication_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -26434,38 +25980,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "medication_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -26478,38 +26027,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "medication_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -26522,38 +26074,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "medication_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -26566,38 +26121,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "medication_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -26610,38 +26168,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "medication_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -26654,38 +26215,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "medication_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -26698,38 +26262,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "medication_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -26742,38 +26309,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "medication_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -26786,85 +26356,87 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *x.Medication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "medication_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "note_authorReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -26872,47 +26444,328 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "note_authorReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + if x.Medication != nil { + if x.Medication.Reference != nil { + if x.Medication.Reference.Reference != nil { + refVal := *x.Medication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "medication_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "medication_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -26928,38 +26781,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Note.AuthorReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "note_authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -26976,38 +26832,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Note.AuthorReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "note_authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27016,46 +26875,49 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "reason_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27064,46 +26926,49 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "reason_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27120,38 +26985,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "reason_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27168,38 +27036,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "reason_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27216,38 +27087,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "reason_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27264,38 +27138,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "reason_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27312,38 +27189,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "reason_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27360,38 +27240,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "reason_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27408,38 +27291,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "reason_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27456,38 +27342,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "reason_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27504,38 +27393,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "reason_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27552,38 +27444,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "reason_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27600,38 +27495,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "reason_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27648,38 +27546,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "reason_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27696,38 +27597,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "reason_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27744,38 +27648,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "reason_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27792,38 +27699,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "reason_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27840,38 +27750,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "reason_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27888,38 +27801,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "reason_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27936,38 +27852,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "reason_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -27984,38 +27903,41 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "reason_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -28032,38 +27954,143 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "reason_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) + } + } + } + } + } + } + } + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + } + } + } + } + } + } + } + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -28080,8 +28107,77 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_BodyStructure") + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + return edges, nil +} + +// ExtractEdges extracts graph links from Observation. +func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "Observation" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_MedicationRequest") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -28090,14 +28186,14 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "reason_reference_BodyStructure", + collectionID(refType, targetID), + "basedOn_MedicationRequest", projectJSON, sourceType, - "BodyStructure", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "basedOn_observation") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -28105,12 +28201,12 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_observation", projectJSON, + refType, sourceType, - "reference", )) } } @@ -28120,48 +28216,15 @@ func (x *MedicationAdministration) ExtractEdges(project string) ([]json.RawMessa } } } - return edges, nil -} - -// ExtractEdges extracts graph links from MedicationAdministrationDosage. -func (x *MedicationAdministrationDosage) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "MedicationAdministrationDosage" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from MedicationAdministrationPerformer. -func (x *MedicationAdministrationPerformer) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "MedicationAdministrationPerformer" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.BodyStructure != nil { + if x.BodyStructure.Reference != nil { + refVal := *x.BodyStructure.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_Organization") + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "bodyStructure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -28170,14 +28233,14 @@ func (x *MedicationAdministrationPerformer) ExtractEdges(project string) ([]json edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Organization", targetID), - "actor_reference_Organization", + collectionID(refType, targetID), + "bodyStructure", projectJSON, sourceType, - "Organization", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "observation") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -28185,12 +28248,12 @@ func (x *MedicationAdministrationPerformer) ExtractEdges(project string) ([]json seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "observation", projectJSON, + refType, sourceType, - "reference", )) } } @@ -28198,1236 +28261,1730 @@ func (x *MedicationAdministrationPerformer) ExtractEdges(project string) ([]json } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "actor_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "derivedFrom_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "actor_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "derivedFrom_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "actor_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.DerivedFrom != nil { + for _, item_2_x_DerivedFrom := range x.DerivedFrom { + if item_2_x_DerivedFrom != nil { + if item_2_x_DerivedFrom.Reference != nil { + refVal := *item_2_x_DerivedFrom.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "derivedFrom_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "derivedFrom_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "derivedFrom_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "actor_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "focus_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "actor_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "focus_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "actor_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "focus_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "actor_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "focus_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "actor_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "focus_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "actor_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "focus_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "actor_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "focus_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "actor_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "focus_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "actor_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "focus_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "actor_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "focus_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "actor_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "focus_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "actor_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "focus_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "actor_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "focus_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "actor_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "focus_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "actor_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "focus_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "actor_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "focus_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "actor_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "focus_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "actor_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "focus_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Actor != nil { - if x.Actor.Reference != nil { - if x.Actor.Reference.Reference != nil { - refVal := *x.Actor.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "actor_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "actor_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "focus_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - return edges, nil -} - -// ExtractEdges extracts graph links from MedicationBatch. -func (x *MedicationBatch) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "MedicationBatch" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from MedicationIngredient. -func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "MedicationIngredient" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "item_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "focus_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "item_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "focus_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "item_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "focus_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) + if x.Focus != nil { + for _, item_2_x_Focus := range x.Focus { + if item_2_x_Focus != nil { + if item_2_x_Focus.Reference != nil { + refVal := *item_2_x_Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "focus_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_observation", + projectJSON, + refType, + sourceType, + )) + } + } } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "item_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) + } + } + } + } + } + if x.HasMember != nil { + for _, item_2_x_HasMember := range x.HasMember { + if item_2_x_HasMember != nil { + if item_2_x_HasMember.Reference != nil { + refVal := *item_2_x_HasMember.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "hasMember_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "hasMember_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "hasMember_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "hasMember_observation", + projectJSON, + refType, + sourceType, + )) + } + } } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) + } + } + } + } + } + if x.PartOf != nil { + for _, item_2_x_PartOf := range x.PartOf { + if item_2_x_PartOf != nil { + if item_2_x_PartOf.Reference != nil { + refVal := *item_2_x_PartOf.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "partOf_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "partOf_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "partOf_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "partOf_observation", + projectJSON, + refType, + sourceType, + )) + } + } } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + } + } + } + } + } + if x.PartOf != nil { + for _, item_2_x_PartOf := range x.PartOf { + if item_2_x_PartOf != nil { + if item_2_x_PartOf.Reference != nil { + refVal := *item_2_x_PartOf.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "partOf_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "partOf_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "partOf_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "partOf_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) + if x.PartOf != nil { + for _, item_2_x_PartOf := range x.PartOf { + if item_2_x_PartOf != nil { + if item_2_x_PartOf.Reference != nil { + refVal := *item_2_x_PartOf.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "partOf_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "partOf_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "partOf_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "partOf_observation", + projectJSON, + refType, + sourceType, + )) + } + } } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "item_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) + } + } + } + } + } + if x.PartOf != nil { + for _, item_2_x_PartOf := range x.PartOf { + if item_2_x_PartOf != nil { + if item_2_x_PartOf.Reference != nil { + refVal := *item_2_x_PartOf.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "partOf_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "partOf_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "partOf_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "partOf_observation", + projectJSON, + refType, + sourceType, + )) + } + } } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) + } + } + } + } + } + if x.Performer != nil { + for _, item_2_x_Performer := range x.Performer { + if item_2_x_Performer != nil { + if item_2_x_Performer.Reference != nil { + refVal := *item_2_x_Performer.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "performer_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "performer_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "performer_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "performer_observation", + projectJSON, + refType, + sourceType, + )) + } + } } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + } + } + } + } + } + if x.Performer != nil { + for _, item_2_x_Performer := range x.Performer { + if item_2_x_Performer != nil { + if item_2_x_Performer.Reference != nil { + refVal := *item_2_x_Performer.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "performer_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "performer_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "performer_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "performer_observation", + projectJSON, + refType, + sourceType, + )) + } + } } } } } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Performer != nil { + for _, item_2_x_Performer := range x.Performer { + if item_2_x_Performer != nil { + if item_2_x_Performer.Reference != nil { + refVal := *item_2_x_Performer.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "performer_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "performer_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "performer_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "performer_observation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + if x.Performer != nil { + for _, item_2_x_Performer := range x.Performer { + if item_2_x_Performer != nil { + if item_2_x_Performer.Reference != nil { + refVal := *item_2_x_Performer.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "performer_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "performer_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "performer_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "performer_observation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + if x.Specimen != nil { + if x.Specimen.Reference != nil { + refVal := *x.Specimen.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_Patient") + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "specimen_Specimen") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29436,14 +29993,14 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Patient", targetID), - "item_reference_Patient", + collectionID(refType, targetID), + "specimen_Specimen", projectJSON, sourceType, - "Patient", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "specimen_observation") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29451,12 +30008,12 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "specimen_observation", projectJSON, + refType, sourceType, - "reference", )) } } @@ -29464,14 +30021,15 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Specimen != nil { + if x.Specimen.Reference != nil { + refVal := *x.Specimen.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_ResearchSubject") + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "specimen_Group") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29480,14 +30038,14 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "item_reference_ResearchSubject", + collectionID(refType, targetID), + "specimen_Group", projectJSON, sourceType, - "ResearchSubject", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "specimen_observation") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29495,12 +30053,12 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "specimen_observation", projectJSON, + refType, sourceType, - "reference", )) } } @@ -29508,14 +30066,15 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_Substance") + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "subject_Patient") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29524,14 +30083,14 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Substance", targetID), - "item_reference_Substance", + collectionID(refType, targetID), + "subject_Patient", projectJSON, sourceType, - "Substance", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "subject_observation") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29539,12 +30098,12 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_observation", projectJSON, + refType, sourceType, - "reference", )) } } @@ -29552,14 +30111,15 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_SubstanceDefinition") + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "subject_Group") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29568,14 +30128,14 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "item_reference_SubstanceDefinition", + collectionID(refType, targetID), + "subject_Group", projectJSON, sourceType, - "SubstanceDefinition", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "subject_observation") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29583,12 +30143,12 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_observation", projectJSON, + refType, sourceType, - "reference", )) } } @@ -29596,14 +30156,15 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_Specimen") + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "subject_Organization") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29612,14 +30173,14 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Specimen", targetID), - "item_reference_Specimen", + collectionID(refType, targetID), + "subject_Organization", projectJSON, sourceType, - "Specimen", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "subject_observation") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29627,12 +30188,12 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_observation", projectJSON, + refType, sourceType, - "reference", )) } } @@ -29640,14 +30201,15 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_Observation") + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "subject_Procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29656,14 +30218,14 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Observation", targetID), - "item_reference_Observation", + collectionID(refType, targetID), + "subject_Procedure", projectJSON, sourceType, - "Observation", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "subject_observation") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29671,12 +30233,12 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_observation", projectJSON, + refType, sourceType, - "reference", )) } } @@ -29684,14 +30246,15 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_DiagnosticReport") + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "subject_Practitioner") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29700,14 +30263,14 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "item_reference_DiagnosticReport", + collectionID(refType, targetID), + "subject_Practitioner", projectJSON, sourceType, - "DiagnosticReport", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "subject_observation") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29715,12 +30278,12 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_observation", projectJSON, + refType, sourceType, - "reference", )) } } @@ -29728,14 +30291,15 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_Condition") + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "subject_Medication") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29744,14 +30308,14 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Condition", targetID), - "item_reference_Condition", + collectionID(refType, targetID), + "subject_Medication", projectJSON, sourceType, - "Condition", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "subject_observation") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29759,12 +30323,12 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_observation", projectJSON, + refType, sourceType, - "reference", )) } } @@ -29772,14 +30336,15 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_Medication") + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "subject_Substance") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29788,14 +30353,14 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Medication", targetID), - "item_reference_Medication", + collectionID(refType, targetID), + "subject_Substance", projectJSON, sourceType, - "Medication", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "subject_observation") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29803,12 +30368,12 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_observation", projectJSON, + refType, sourceType, - "reference", )) } } @@ -29816,30 +30381,303 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + if x.TriggeredBy != nil { + for _, item_3_x_TriggeredBy := range x.TriggeredBy { + if item_3_x_TriggeredBy != nil { + if item_3_x_TriggeredBy.Observation != nil { + if item_3_x_TriggeredBy.Observation.Reference != nil { + refVal := *item_3_x_TriggeredBy.Observation.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "triggeredBy_observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "triggeredBy_observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "observation_triggered_by") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "observation_triggered_by", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + return edges, nil +} + +// ExtractEdges extracts graph links from Organization. +func (x *Organization) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "Organization" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.PartOf != nil { + if x.PartOf.Reference != nil { + refVal := *x.PartOf.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "partOf") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "item_reference_MedicationAdministration", + collectionID(refType, targetID), + "partOf", projectJSON, sourceType, - "MedicationAdministration", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "organization") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29847,12 +30685,12 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "organization", projectJSON, + refType, sourceType, - "reference", )) } } @@ -29860,14 +30698,281 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Contact != nil { + for _, item_3_x_Contact := range x.Contact { + if item_3_x_Contact != nil { + if item_3_x_Contact.Organization != nil { + if item_3_x_Contact.Organization.Reference != nil { + refVal := *item_3_x_Contact.Organization.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "contact_organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "contact_organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "extended_contact_detail") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "extended_contact_detail", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + if x.Qualification != nil { + for _, item_3_x_Qualification := range x.Qualification { + if item_3_x_Qualification != nil { + if item_3_x_Qualification.Issuer != nil { + if item_3_x_Qualification.Issuer.Reference != nil { + refVal := *item_3_x_Qualification.Issuer.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "qualification_issuer") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "qualification_issuer", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "organization_qualification") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "organization_qualification", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + return edges, nil +} + +// ExtractEdges extracts graph links from Patient. +func (x *Patient) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "Patient" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.GeneralPractitioner != nil { + for _, item_2_x_GeneralPractitioner := range x.GeneralPractitioner { + if item_2_x_GeneralPractitioner != nil { + if item_2_x_GeneralPractitioner.Reference != nil { + refVal := *item_2_x_GeneralPractitioner.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "generalPractitioner_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "generalPractitioner_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "generalPractitioner_patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "generalPractitioner_patient", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + if x.GeneralPractitioner != nil { + for _, item_2_x_GeneralPractitioner := range x.GeneralPractitioner { + if item_2_x_GeneralPractitioner != nil { + if item_2_x_GeneralPractitioner.Reference != nil { + refVal := *item_2_x_GeneralPractitioner.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "generalPractitioner_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "generalPractitioner_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "generalPractitioner_patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "generalPractitioner_patient", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + if x.GeneralPractitioner != nil { + for _, item_2_x_GeneralPractitioner := range x.GeneralPractitioner { + if item_2_x_GeneralPractitioner != nil { + if item_2_x_GeneralPractitioner.Reference != nil { + refVal := *item_2_x_GeneralPractitioner.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "generalPractitioner_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "generalPractitioner_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "generalPractitioner_patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "generalPractitioner_patient", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + if x.ManagingOrganization != nil { + if x.ManagingOrganization.Reference != nil { + refVal := *x.ManagingOrganization.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_MedicationStatement") + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "managingOrganization") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29876,14 +30981,14 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "item_reference_MedicationStatement", + collectionID(refType, targetID), + "managingOrganization", projectJSON, sourceType, - "MedicationStatement", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "managingOrganization_patient") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29891,12 +30996,12 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "managingOrganization_patient", projectJSON, + refType, sourceType, - "reference", )) } } @@ -29904,14 +31009,202 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Contact != nil { + for _, item_3_x_Contact := range x.Contact { + if item_3_x_Contact != nil { + if item_3_x_Contact.Organization != nil { + if item_3_x_Contact.Organization.Reference != nil { + refVal := *item_3_x_Contact.Organization.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "contact_organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "contact_organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "patient_contact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "patient_contact", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + if x.Link != nil { + for _, item_3_x_Link := range x.Link { + if item_3_x_Link != nil { + if item_3_x_Link.Other != nil { + if item_3_x_Link.Other.Reference != nil { + refVal := *item_3_x_Link.Other.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "link_other_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "link_other_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "patient_link") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "patient_link", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + return edges, nil +} + +// ExtractEdges extracts graph links from Practitioner. +func (x *Practitioner) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "Practitioner" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.Qualification != nil { + for _, item_3_x_Qualification := range x.Qualification { + if item_3_x_Qualification != nil { + if item_3_x_Qualification.Issuer != nil { + if item_3_x_Qualification.Issuer.Reference != nil { + refVal := *item_3_x_Qualification.Issuer.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "qualification_issuer") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "qualification_issuer", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "practitioner_qualification") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "practitioner_qualification", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + return edges, nil +} + +// ExtractEdges extracts graph links from PractitionerRole. +func (x *PractitionerRole) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "PractitionerRole" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.Organization != nil { + if x.Organization.Reference != nil { + refVal := *x.Organization.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_MedicationRequest") + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "organization") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29920,14 +31213,14 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "item_reference_MedicationRequest", + collectionID(refType, targetID), + "organization", projectJSON, sourceType, - "MedicationRequest", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "practitioner_role") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29935,12 +31228,12 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "practitioner_role", projectJSON, + refType, sourceType, - "reference", )) } } @@ -29948,14 +31241,15 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Practitioner != nil { + if x.Practitioner.Reference != nil { + refVal := *x.Practitioner.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_Procedure") + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "practitioner") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29964,14 +31258,14 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Procedure", targetID), - "item_reference_Procedure", + collectionID(refType, targetID), + "practitioner", projectJSON, sourceType, - "Procedure", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "practitioner_role") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -29979,12 +31273,12 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "practitioner_role", projectJSON, + refType, sourceType, - "reference", )) } } @@ -29992,14 +31286,83 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Contact != nil { + for _, item_3_x_Contact := range x.Contact { + if item_3_x_Contact != nil { + if item_3_x_Contact.Organization != nil { + if item_3_x_Contact.Organization.Reference != nil { + refVal := *item_3_x_Contact.Organization.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "contact_organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "contact_organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "extended_contact_detail") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "extended_contact_detail", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } + } + } + } + return edges, nil +} + +// ExtractEdges extracts graph links from Procedure. +func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "Procedure" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_DocumentReference") + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "focus_Patient") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -30008,14 +31371,14 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "item_reference_DocumentReference", + collectionID(refType, targetID), + "focus_Patient", projectJSON, sourceType, - "DocumentReference", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "focus_procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -30023,12 +31386,12 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_procedure", projectJSON, + refType, sourceType, - "reference", )) } } @@ -30036,14 +31399,15 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_Task") + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "focus_Group") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -30052,14 +31416,14 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Task", targetID), - "item_reference_Task", + collectionID(refType, targetID), + "focus_Group", projectJSON, sourceType, - "Task", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "focus_procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -30067,12 +31431,12 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_procedure", projectJSON, + refType, sourceType, - "reference", )) } } @@ -30080,14 +31444,15 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_ImagingStudy") + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "focus_Practitioner") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -30096,14 +31461,14 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "item_reference_ImagingStudy", + collectionID(refType, targetID), + "focus_Practitioner", projectJSON, sourceType, - "ImagingStudy", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "focus_procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -30111,12 +31476,12 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_procedure", projectJSON, + refType, sourceType, - "reference", )) } } @@ -30124,14 +31489,15 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_FamilyMemberHistory") + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "focus_Organization") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -30140,14 +31506,14 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "item_reference_FamilyMemberHistory", + collectionID(refType, targetID), + "focus_Organization", projectJSON, sourceType, - "FamilyMemberHistory", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "focus_procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -30155,12 +31521,12 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_procedure", projectJSON, + refType, sourceType, - "reference", )) } } @@ -30168,14 +31534,15 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, } } } - if x.Item != nil { - if x.Item.Reference != nil { - if x.Item.Reference.Reference != nil { - refVal := *x.Item.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "item_reference_BodyStructure") + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "focus_PractitionerRole") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -30184,14 +31551,14 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "item_reference_BodyStructure", + collectionID(refType, targetID), + "focus_PractitionerRole", projectJSON, sourceType, - "BodyStructure", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "focus_procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -30199,12 +31566,12 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_procedure", projectJSON, + refType, sourceType, - "reference", )) } } @@ -30212,108 +31579,93 @@ func (x *MedicationIngredient) ExtractEdges(project string) ([]json.RawMessage, } } } - return edges, nil -} - -// ExtractEdges extracts graph links from MedicationRequest. -func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "MedicationRequest" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "basedOn_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "basedOn_medication_request", - projectJSON, - sourceType, - "request", - )) - } + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "focus_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_procedure", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.InformationSource != nil { - for _, item_2_x_InformationSource := range x.InformationSource { - if item_2_x_InformationSource != nil { - if item_2_x_InformationSource.Reference != nil { - refVal := *item_2_x_InformationSource.Reference + if x.PartOf != nil { + for _, item_2_x_PartOf := range x.PartOf { + if item_2_x_PartOf != nil { + if item_2_x_PartOf.Reference != nil { + refVal := *item_2_x_PartOf.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "informationSource_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "informationSource_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "informationSource_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "informationSource_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "partOf_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "partOf_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "partOf_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "partOf_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -30321,45 +31673,48 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.InformationSource != nil { - for _, item_2_x_InformationSource := range x.InformationSource { - if item_2_x_InformationSource != nil { - if item_2_x_InformationSource.Reference != nil { - refVal := *item_2_x_InformationSource.Reference + if x.PartOf != nil { + for _, item_2_x_PartOf := range x.PartOf { + if item_2_x_PartOf != nil { + if item_2_x_PartOf.Reference != nil { + refVal := *item_2_x_PartOf.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "informationSource_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "informationSource_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "informationSource_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "informationSource_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "partOf_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "partOf_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "partOf_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "partOf_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -30367,45 +31722,48 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.InformationSource != nil { - for _, item_2_x_InformationSource := range x.InformationSource { - if item_2_x_InformationSource != nil { - if item_2_x_InformationSource.Reference != nil { - refVal := *item_2_x_InformationSource.Reference + if x.PartOf != nil { + for _, item_2_x_PartOf := range x.PartOf { + if item_2_x_PartOf != nil { + if item_2_x_PartOf.Reference != nil { + refVal := *item_2_x_PartOf.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "informationSource_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "informationSource_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "informationSource_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "informationSource_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "partOf_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "partOf_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "partOf_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "partOf_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -30413,183 +31771,183 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.InformationSource != nil { - for _, item_2_x_InformationSource := range x.InformationSource { - if item_2_x_InformationSource != nil { - if item_2_x_InformationSource.Reference != nil { - refVal := *item_2_x_InformationSource.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "informationSource_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "informationSource_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "informationSource_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "informationSource_medication_request", - projectJSON, - sourceType, - "request", - )) - } + if x.Recorder != nil { + if x.Recorder.Reference != nil { + refVal := *x.Recorder.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "recorder_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "recorder_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "recorder_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "recorder_procedure", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Performer != nil { - for _, item_2_x_Performer := range x.Performer { - if item_2_x_Performer != nil { - if item_2_x_Performer.Reference != nil { - refVal := *item_2_x_Performer.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "performer_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "performer_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "performer_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "performer_medication_request", - projectJSON, - sourceType, - "request", - )) - } + if x.Recorder != nil { + if x.Recorder.Reference != nil { + refVal := *x.Recorder.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "recorder_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "recorder_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "recorder_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "recorder_procedure", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Performer != nil { - for _, item_2_x_Performer := range x.Performer { - if item_2_x_Performer != nil { - if item_2_x_Performer.Reference != nil { - refVal := *item_2_x_Performer.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "performer_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "performer_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "performer_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "performer_medication_request", - projectJSON, - sourceType, - "request", - )) - } + if x.Recorder != nil { + if x.Recorder.Reference != nil { + refVal := *x.Recorder.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "recorder_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "recorder_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "recorder_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "recorder_procedure", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Performer != nil { - for _, item_2_x_Performer := range x.Performer { - if item_2_x_Performer != nil { - if item_2_x_Performer.Reference != nil { - refVal := *item_2_x_Performer.Reference + if x.Report != nil { + for _, item_2_x_Report := range x.Report { + if item_2_x_Report != nil { + if item_2_x_Report.Reference != nil { + refVal := *item_2_x_Report.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "performer_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "performer_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "performer_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "performer_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "report_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "report_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "report_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "report_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -30597,45 +31955,48 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Performer != nil { - for _, item_2_x_Performer := range x.Performer { - if item_2_x_Performer != nil { - if item_2_x_Performer.Reference != nil { - refVal := *item_2_x_Performer.Reference + if x.Report != nil { + for _, item_2_x_Report := range x.Report { + if item_2_x_Report != nil { + if item_2_x_Report.Reference != nil { + refVal := *item_2_x_Report.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "performer_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "performer_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "performer_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "performer_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "report_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "report_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "report_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "report_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -30643,295 +32004,271 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.PriorPrescription != nil { - if x.PriorPrescription.Reference != nil { - refVal := *x.PriorPrescription.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "priorPrescription") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("priorPrescription", targetID), - "priorPrescription", - projectJSON, - sourceType, - "priorPrescription", - )) - } - backrefKey := getEdgeUUID(id, targetID, "priorPrescription_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "priorPrescription_medication_request", - projectJSON, - sourceType, - "request", - )) - } - } - } - } - } - if x.Recorder != nil { - if x.Recorder.Reference != nil { - refVal := *x.Recorder.Reference + if x.ReportedReference != nil { + if x.ReportedReference.Reference != nil { + refVal := *x.ReportedReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "recorder_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "recorder_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "recorder_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "recorder_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "reportedReference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reportedReference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "reportedReference_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "reportedReference_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } } } - if x.Recorder != nil { - if x.Recorder.Reference != nil { - refVal := *x.Recorder.Reference + if x.ReportedReference != nil { + if x.ReportedReference.Reference != nil { + refVal := *x.ReportedReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "recorder_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "recorder_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "recorder_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "recorder_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "reportedReference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reportedReference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "reportedReference_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "reportedReference_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } } } - if x.Requester != nil { - if x.Requester.Reference != nil { - refVal := *x.Requester.Reference + if x.ReportedReference != nil { + if x.ReportedReference.Reference != nil { + refVal := *x.ReportedReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "requester_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "requester_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "requester_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "requester_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "reportedReference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reportedReference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "reportedReference_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "reportedReference_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } } } - if x.Requester != nil { - if x.Requester.Reference != nil { - refVal := *x.Requester.Reference + if x.ReportedReference != nil { + if x.ReportedReference.Reference != nil { + refVal := *x.ReportedReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "requester_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "requester_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "requester_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "requester_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "reportedReference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reportedReference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "reportedReference_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "reportedReference_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } } } - if x.Requester != nil { - if x.Requester.Reference != nil { - refVal := *x.Requester.Reference + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "requester_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "requester_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "requester_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "requester_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "subject_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "subject_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } } } - if x.Requester != nil { - if x.Requester.Reference != nil { - refVal := *x.Requester.Reference + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "requester_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "requester_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "requester_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "requester_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "subject_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "subject_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -30942,38 +32279,41 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err refVal := *x.Subject.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "subject_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "subject_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "subject_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "subject_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "subject_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -30984,82 +32324,88 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err refVal := *x.Subject.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "subject_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "subject_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "subject_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "subject_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "subject_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "subject_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "supportingInformation_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInfo_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -31067,45 +32413,48 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "supportingInformation_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInfo_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -31113,45 +32462,48 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "supportingInformation_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInfo_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -31159,91 +32511,97 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "supportingInformation_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) - } - } - } + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInfo_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "supportingInformation_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInfo_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -31251,45 +32609,48 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "supportingInformation_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInfo_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -31297,45 +32658,48 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "supportingInformation_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInfo_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -31343,45 +32707,48 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "supportingInformation_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInfo_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -31389,45 +32756,48 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "supportingInformation_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInfo_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -31435,45 +32805,48 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "supportingInformation_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInfo_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -31481,45 +32854,48 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "supportingInformation_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInfo_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -31527,45 +32903,48 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "supportingInformation_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supportingInfo_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -31573,522 +32952,17 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "supportingInformation_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) - } - } - } - } - } - } - } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "supportingInformation_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) - } - } - } - } - } - } - } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "supportingInformation_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) - } - } - } - } - } - } - } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "supportingInformation_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) - } - } - } - } - } - } - } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "supportingInformation_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) - } - } - } - } - } - } - } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "supportingInformation_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) - } - } - } - } - } - } - } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "supportingInformation_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) - } - } - } - } - } - } - } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "supportingInformation_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) - } - } - } - } - } - } - } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "supportingInformation_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) - } - } - } - } - } - } - } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "supportingInformation_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) - } - } - } - } - } - } - } - if x.SupportingInformation != nil { - for _, item_2_x_SupportingInformation := range x.SupportingInformation { - if item_2_x_SupportingInformation != nil { - if item_2_x_SupportingInformation.Reference != nil { - refVal := *item_2_x_SupportingInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "supportingInformation_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "supportingInformation_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInformation_medication_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "supportingInformation_medication_request", - projectJSON, - sourceType, - "request", - )) - } - } - } - } - } - } - } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Organization") + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Condition") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32097,14 +32971,14 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Organization", targetID), - "device_reference_Organization", + collectionID(refType, targetID), + "supportingInfo_Condition", projectJSON, sourceType, - "Organization", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32112,12 +32986,12 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", projectJSON, + refType, sourceType, - "reference", )) } } @@ -32127,16 +33001,17 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Group") + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Medication") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32145,14 +33020,14 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Group", targetID), - "device_reference_Group", + collectionID(refType, targetID), + "supportingInfo_Medication", projectJSON, sourceType, - "Group", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32160,12 +33035,12 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", projectJSON, + refType, sourceType, - "reference", )) } } @@ -32175,16 +33050,17 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Practitioner") + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_MedicationAdministration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32193,14 +33069,14 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "device_reference_Practitioner", + collectionID(refType, targetID), + "supportingInfo_MedicationAdministration", projectJSON, sourceType, - "Practitioner", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32208,12 +33084,12 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", projectJSON, + refType, sourceType, - "reference", )) } } @@ -32223,16 +33099,17 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_PractitionerRole") + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_MedicationStatement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32241,14 +33118,14 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "device_reference_PractitionerRole", + collectionID(refType, targetID), + "supportingInfo_MedicationStatement", projectJSON, sourceType, - "PractitionerRole", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32256,12 +33133,12 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", projectJSON, + refType, sourceType, - "reference", )) } } @@ -32271,16 +33148,17 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_ResearchStudy") + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_MedicationRequest") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32289,14 +33167,14 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "device_reference_ResearchStudy", + collectionID(refType, targetID), + "supportingInfo_MedicationRequest", projectJSON, sourceType, - "ResearchStudy", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32304,12 +33182,12 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", projectJSON, + refType, sourceType, - "reference", )) } } @@ -32319,16 +33197,17 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Patient") + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32337,14 +33216,14 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Patient", targetID), - "device_reference_Patient", + collectionID(refType, targetID), + "supportingInfo_Procedure", projectJSON, sourceType, - "Patient", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32352,12 +33231,12 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", projectJSON, + refType, sourceType, - "reference", )) } } @@ -32367,16 +33246,17 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_ResearchSubject") + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_DocumentReference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32385,14 +33265,14 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "device_reference_ResearchSubject", + collectionID(refType, targetID), + "supportingInfo_DocumentReference", projectJSON, sourceType, - "ResearchSubject", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32400,12 +33280,12 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", projectJSON, + refType, sourceType, - "reference", )) } } @@ -32415,16 +33295,17 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Substance") + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Task") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32433,14 +33314,14 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Substance", targetID), - "device_reference_Substance", + collectionID(refType, targetID), + "supportingInfo_Task", projectJSON, sourceType, - "Substance", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32448,12 +33329,12 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", projectJSON, + refType, sourceType, - "reference", )) } } @@ -32463,16 +33344,17 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_SubstanceDefinition") + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_ImagingStudy") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32481,14 +33363,14 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "device_reference_SubstanceDefinition", + collectionID(refType, targetID), + "supportingInfo_ImagingStudy", projectJSON, sourceType, - "SubstanceDefinition", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32496,12 +33378,12 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", projectJSON, + refType, sourceType, - "reference", )) } } @@ -32511,16 +33393,17 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Specimen") + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_FamilyMemberHistory") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32529,14 +33412,14 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Specimen", targetID), - "device_reference_Specimen", + collectionID(refType, targetID), + "supportingInfo_FamilyMemberHistory", projectJSON, sourceType, - "Specimen", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32544,12 +33427,12 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", projectJSON, + refType, sourceType, - "reference", )) } } @@ -32559,16 +33442,17 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.SupportingInfo != nil { + for _, item_2_x_SupportingInfo := range x.SupportingInfo { + if item_2_x_SupportingInfo != nil { + if item_2_x_SupportingInfo.Reference != nil { + refVal := *item_2_x_SupportingInfo.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Observation") + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "supportingInfo_BodyStructure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32577,14 +33461,14 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Observation", targetID), - "device_reference_Observation", + collectionID(refType, targetID), + "supportingInfo_BodyStructure", projectJSON, sourceType, - "Observation", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -32592,12 +33476,12 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "supportingInfo_procedure", projectJSON, + refType, sourceType, - "reference", )) } } @@ -32607,46 +33491,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "device_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -32655,46 +33542,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "device_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -32703,46 +33593,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "device_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -32751,46 +33644,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "device_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -32799,46 +33695,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "device_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -32847,46 +33746,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "device_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -32895,46 +33797,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "device_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -32943,46 +33848,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "device_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -32991,46 +33899,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "device_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -33039,46 +33950,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "device_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -33087,46 +34001,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "device_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -33135,46 +34052,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Device != nil { - for _, item_3_x_Device := range x.Device { - if item_3_x_Device != nil { - if item_3_x_Device.Reference != nil { - if item_3_x_Device.Reference.Reference != nil { - refVal := *item_3_x_Device.Reference.Reference + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "device_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -33183,1102 +34103,1273 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.DispenseRequest != nil { - if x.DispenseRequest.Dispenser != nil { - if x.DispenseRequest.Dispenser.Reference != nil { - refVal := *x.DispenseRequest.Dispenser.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "dispenseRequest_dispenser") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("dispenser", targetID), - "dispenseRequest_dispenser", - projectJSON, - sourceType, - "dispenser", - )) - } - backrefKey := getEdgeUUID(id, targetID, "medication_request_dispense_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "medication_request_dispense_request", - projectJSON, - sourceType, - "request", - )) + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "medication_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "medication_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "medication_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "medication_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "medication_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "medication_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "medication_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "medication_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "medication_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "medication_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Complication != nil { + for _, item_3_x_Complication := range x.Complication { + if item_3_x_Complication != nil { + if item_3_x_Complication.Reference != nil { + if item_3_x_Complication.Reference.Reference != nil { + refVal := *item_3_x_Complication.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "complication_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "complication_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "medication_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "medication_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "medication_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "medication_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "medication_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Performer != nil { + for _, item_3_x_Performer := range x.Performer { + if item_3_x_Performer != nil { + if item_3_x_Performer.Actor != nil { + if item_3_x_Performer.Actor.Reference != nil { + refVal := *item_3_x_Performer.Actor.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "performer_actor_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "performer_actor_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "actor_procedure_performer") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "actor_procedure_performer", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "medication_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Performer != nil { + for _, item_3_x_Performer := range x.Performer { + if item_3_x_Performer != nil { + if item_3_x_Performer.Actor != nil { + if item_3_x_Performer.Actor.Reference != nil { + refVal := *item_3_x_Performer.Actor.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "performer_actor_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "performer_actor_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "actor_procedure_performer") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "actor_procedure_performer", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "medication_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Performer != nil { + for _, item_3_x_Performer := range x.Performer { + if item_3_x_Performer != nil { + if item_3_x_Performer.Actor != nil { + if item_3_x_Performer.Actor.Reference != nil { + refVal := *item_3_x_Performer.Actor.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "performer_actor_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "performer_actor_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "actor_procedure_performer") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "actor_procedure_performer", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "medication_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Performer != nil { + for _, item_3_x_Performer := range x.Performer { + if item_3_x_Performer != nil { + if item_3_x_Performer.Actor != nil { + if item_3_x_Performer.Actor.Reference != nil { + refVal := *item_3_x_Performer.Actor.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "performer_actor_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "performer_actor_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "actor_procedure_performer") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "actor_procedure_performer", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "medication_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Performer != nil { + for _, item_3_x_Performer := range x.Performer { + if item_3_x_Performer != nil { + if item_3_x_Performer.OnBehalfOf != nil { + if item_3_x_Performer.OnBehalfOf.Reference != nil { + refVal := *item_3_x_Performer.OnBehalfOf.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "performer_onBehalfOf") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "performer_onBehalfOf", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_procedure_performer") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "onBehalfOf_procedure_performer", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "medication_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "medication_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "medication_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "medication_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "note_authorReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -34287,46 +35378,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "note_authorReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -34335,46 +35429,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "note_authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -34383,46 +35480,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "note_authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -34439,38 +35539,41 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "reason_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -34487,38 +35590,41 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "reason_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -34535,38 +35641,41 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "reason_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -34583,38 +35692,41 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "reason_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -34631,38 +35743,41 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "reason_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -34679,38 +35794,41 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "reason_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -34727,38 +35845,41 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "reason_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -34775,38 +35896,41 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "reason_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -34823,38 +35947,41 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "reason_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -34871,38 +35998,41 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "reason_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -34919,38 +36049,41 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "reason_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -34967,38 +36100,41 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "reason_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -35015,38 +36151,41 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "reason_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -35063,38 +36202,41 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "reason_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -35111,38 +36253,41 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "reason_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -35151,46 +36296,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "reason_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -35199,46 +36347,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "reason_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -35247,46 +36398,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "reason_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -35295,46 +36449,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "reason_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -35343,46 +36500,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "reason_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -35391,46 +36551,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "reason_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -35439,46 +36602,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "reason_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -35487,46 +36653,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "reason_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -35535,105 +36704,49 @@ func (x *MedicationRequest) ExtractEdges(project string) ([]json.RawMessage, err } } } - return edges, nil -} - -// ExtractEdges extracts graph links from MedicationRequestDispenseRequest. -func (x *MedicationRequestDispenseRequest) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "MedicationRequestDispenseRequest" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Dispenser != nil { - if x.Dispenser.Reference != nil { - refVal := *x.Dispenser.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "dispenser") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("dispenser", targetID), - "dispenser", - projectJSON, - sourceType, - "dispenser", - )) - } - backrefKey := getEdgeUUID(id, targetID, "medication_request_dispense_request") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("request", id), - "medication_request_dispense_request", - projectJSON, - sourceType, - "request", - )) - } - } - } - } - } - if x.DispenserInstruction != nil { - for _, item_3_x_DispenserInstruction := range x.DispenserInstruction { - if item_3_x_DispenserInstruction != nil { - if item_3_x_DispenserInstruction.AuthorReference != nil { - if item_3_x_DispenserInstruction.AuthorReference.Reference != nil { - refVal := *item_3_x_DispenserInstruction.AuthorReference.Reference + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "dispenserInstruction_authorReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "dispenserInstruction_authorReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -35642,46 +36755,49 @@ func (x *MedicationRequestDispenseRequest) ExtractEdges(project string) ([]json. } } } - if x.DispenserInstruction != nil { - for _, item_3_x_DispenserInstruction := range x.DispenserInstruction { - if item_3_x_DispenserInstruction != nil { - if item_3_x_DispenserInstruction.AuthorReference != nil { - if item_3_x_DispenserInstruction.AuthorReference.Reference != nil { - refVal := *item_3_x_DispenserInstruction.AuthorReference.Reference + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "dispenserInstruction_authorReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "dispenserInstruction_authorReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -35690,46 +36806,49 @@ func (x *MedicationRequestDispenseRequest) ExtractEdges(project string) ([]json. } } } - if x.DispenserInstruction != nil { - for _, item_3_x_DispenserInstruction := range x.DispenserInstruction { - if item_3_x_DispenserInstruction != nil { - if item_3_x_DispenserInstruction.AuthorReference != nil { - if item_3_x_DispenserInstruction.AuthorReference.Reference != nil { - refVal := *item_3_x_DispenserInstruction.AuthorReference.Reference + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "dispenserInstruction_authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "dispenserInstruction_authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -35738,46 +36857,49 @@ func (x *MedicationRequestDispenseRequest) ExtractEdges(project string) ([]json. } } } - if x.DispenserInstruction != nil { - for _, item_3_x_DispenserInstruction := range x.DispenserInstruction { - if item_3_x_DispenserInstruction != nil { - if item_3_x_DispenserInstruction.AuthorReference != nil { - if item_3_x_DispenserInstruction.AuthorReference.Reference != nil { - refVal := *item_3_x_DispenserInstruction.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "dispenserInstruction_authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "dispenserInstruction_authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -35786,96 +36908,50 @@ func (x *MedicationRequestDispenseRequest) ExtractEdges(project string) ([]json. } } } - return edges, nil -} - -// ExtractEdges extracts graph links from MedicationRequestDispenseRequestInitialFill. -func (x *MedicationRequestDispenseRequestInitialFill) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "MedicationRequestDispenseRequestInitialFill" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from MedicationRequestSubstitution. -func (x *MedicationRequestSubstitution) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "MedicationRequestSubstitution" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from MedicationStatement. -func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "MedicationStatement" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "derivedFrom_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -35883,45 +36959,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "derivedFrom_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -35929,45 +37010,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "derivedFrom_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -35975,45 +37061,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "derivedFrom_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -36021,45 +37112,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "derivedFrom_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -36067,45 +37163,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "derivedFrom_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -36113,45 +37214,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "derivedFrom_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -36159,45 +37265,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "derivedFrom_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -36205,45 +37316,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "derivedFrom_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -36251,45 +37367,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "derivedFrom_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -36297,45 +37418,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "derivedFrom_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Used != nil { + for _, item_3_x_Used := range x.Used { + if item_3_x_Used != nil { + if item_3_x_Used.Reference != nil { + if item_3_x_Used.Reference.Reference != nil { + refVal := *item_3_x_Used.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "used_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "used_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -36343,91 +37469,94 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "derivedFrom_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) - } + return edges, nil +} + +// ExtractEdges extracts graph links from ResearchStudy. +func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "ResearchStudy" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.RootDir != nil { + if x.RootDir.Reference != nil { + refVal := *x.RootDir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Directory" { + forwardKey := getEdgeUUID(targetID, id, "rootDir_Directory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "rootDir_Directory", + projectJSON, + sourceType, + refType, + )) } } } } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference + if x.PartOf != nil { + for _, item_2_x_PartOf := range x.PartOf { + if item_2_x_PartOf != nil { + if item_2_x_PartOf.Reference != nil { + refVal := *item_2_x_PartOf.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "derivedFrom_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "partOf") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "partOf", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "partOf_research_study") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "partOf_research_study", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -36435,45 +37564,48 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference + if x.Result != nil { + for _, item_2_x_Result := range x.Result { + if item_2_x_Result != nil { + if item_2_x_Result.Reference != nil { + refVal := *item_2_x_Result.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "derivedFrom_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "result_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "result_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "result_research_study") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "result_research_study", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -36481,45 +37613,48 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference + if x.Site != nil { + for _, item_2_x_Site := range x.Site { + if item_2_x_Site != nil { + if item_2_x_Site.Reference != nil { + refVal := *item_2_x_Site.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "derivedFrom_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "site_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "site_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "site_research_study") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "site_research_study", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -36527,45 +37662,48 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference + if x.Site != nil { + for _, item_2_x_Site := range x.Site { + if item_2_x_Site != nil { + if item_2_x_Site.Reference != nil { + refVal := *item_2_x_Site.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "derivedFrom_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "site_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "site_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "site_research_study") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "site_research_study", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -36573,45 +37711,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "derivedFrom_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.AssociatedParty != nil { + for _, item_3_x_AssociatedParty := range x.AssociatedParty { + if item_3_x_AssociatedParty != nil { + if item_3_x_AssociatedParty.Party != nil { + if item_3_x_AssociatedParty.Party.Reference != nil { + refVal := *item_3_x_AssociatedParty.Party.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "associatedParty_party_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "associatedParty_party_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "research_study_associated_party") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "research_study_associated_party", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -36619,45 +37762,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "derivedFrom_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.AssociatedParty != nil { + for _, item_3_x_AssociatedParty := range x.AssociatedParty { + if item_3_x_AssociatedParty != nil { + if item_3_x_AssociatedParty.Party != nil { + if item_3_x_AssociatedParty.Party.Reference != nil { + refVal := *item_3_x_AssociatedParty.Party.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "associatedParty_party_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "associatedParty_party_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "research_study_associated_party") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "research_study_associated_party", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -36665,45 +37813,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "derivedFrom_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.AssociatedParty != nil { + for _, item_3_x_AssociatedParty := range x.AssociatedParty { + if item_3_x_AssociatedParty != nil { + if item_3_x_AssociatedParty.Party != nil { + if item_3_x_AssociatedParty.Party.Reference != nil { + refVal := *item_3_x_AssociatedParty.Party.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "associatedParty_party_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "associatedParty_party_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "research_study_associated_party") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "research_study_associated_party", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -36711,45 +37864,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "derivedFrom_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.ComparisonGroup != nil { + for _, item_3_x_ComparisonGroup := range x.ComparisonGroup { + if item_3_x_ComparisonGroup != nil { + if item_3_x_ComparisonGroup.ObservedGroup != nil { + if item_3_x_ComparisonGroup.ObservedGroup.Reference != nil { + refVal := *item_3_x_ComparisonGroup.ObservedGroup.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "comparisonGroup_observedGroup") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "comparisonGroup_observedGroup", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "research_study_comparison_group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "research_study_comparison_group", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -36757,45 +37915,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "derivedFrom_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -36803,45 +37966,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "derivedFrom_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -36849,45 +38017,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "derivedFrom_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "derivedFrom_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -36895,45 +38068,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.InformationSource != nil { - for _, item_2_x_InformationSource := range x.InformationSource { - if item_2_x_InformationSource != nil { - if item_2_x_InformationSource.Reference != nil { - refVal := *item_2_x_InformationSource.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "informationSource_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "informationSource_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "informationSource_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "informationSource_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -36941,45 +38119,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.InformationSource != nil { - for _, item_2_x_InformationSource := range x.InformationSource { - if item_2_x_InformationSource != nil { - if item_2_x_InformationSource.Reference != nil { - refVal := *item_2_x_InformationSource.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "informationSource_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "informationSource_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "informationSource_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "informationSource_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -36987,45 +38170,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.InformationSource != nil { - for _, item_2_x_InformationSource := range x.InformationSource { - if item_2_x_InformationSource != nil { - if item_2_x_InformationSource.Reference != nil { - refVal := *item_2_x_InformationSource.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "informationSource_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "informationSource_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "informationSource_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "informationSource_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -37033,45 +38221,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.InformationSource != nil { - for _, item_2_x_InformationSource := range x.InformationSource { - if item_2_x_InformationSource != nil { - if item_2_x_InformationSource.Reference != nil { - refVal := *item_2_x_InformationSource.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "informationSource_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "informationSource_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "informationSource_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "informationSource_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -37079,45 +38272,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.PartOf != nil { - for _, item_2_x_PartOf := range x.PartOf { - if item_2_x_PartOf != nil { - if item_2_x_PartOf.Reference != nil { - refVal := *item_2_x_PartOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "partOf_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "partOf_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "partOf_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "partOf_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -37125,45 +38323,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.PartOf != nil { - for _, item_2_x_PartOf := range x.PartOf { - if item_2_x_PartOf != nil { - if item_2_x_PartOf.Reference != nil { - refVal := *item_2_x_PartOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "partOf_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "partOf_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "partOf_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "partOf_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -37171,45 +38374,50 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.RelatedClinicalInformation != nil { - for _, item_2_x_RelatedClinicalInformation := range x.RelatedClinicalInformation { - if item_2_x_RelatedClinicalInformation != nil { - if item_2_x_RelatedClinicalInformation.Reference != nil { - refVal := *item_2_x_RelatedClinicalInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "relatedClinicalInformation_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "relatedClinicalInformation_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "relatedClinicalInformation_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "relatedClinicalInformation_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -37217,45 +38425,101 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.RelatedClinicalInformation != nil { - for _, item_2_x_RelatedClinicalInformation := range x.RelatedClinicalInformation { - if item_2_x_RelatedClinicalInformation != nil { - if item_2_x_RelatedClinicalInformation.Reference != nil { - refVal := *item_2_x_RelatedClinicalInformation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "relatedClinicalInformation_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "relatedClinicalInformation_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "relatedClinicalInformation_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "relatedClinicalInformation_medication_statement", - projectJSON, - sourceType, - "statement", - )) + } + } + } + } + } + } + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -37263,1142 +38527,1367 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "subject_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "subject_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "subject_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "subject_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "subject_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_medication_statement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("statement", id), - "subject_medication_statement", - projectJSON, - sourceType, - "statement", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "medication_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "medication_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "medication_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "medication_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "medication_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "medication_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "medication_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "medication_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "medication_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Focus != nil { + for _, item_3_x_Focus := range x.Focus { + if item_3_x_Focus != nil { + if item_3_x_Focus.Reference != nil { + if item_3_x_Focus.Reference.Reference != nil { + refVal := *item_3_x_Focus.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "focus_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "medication_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "medication_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + } + } + } + } + } + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "medication_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference + if x.Recruitment != nil { + if x.Recruitment.ActualGroup != nil { + if x.Recruitment.ActualGroup.Reference != nil { + refVal := *x.Recruitment.ActualGroup.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "medication_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "recruitment_actualGroup") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "recruitment_actualGroup", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "actualGroup_research_study_recruitment") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "actualGroup_research_study_recruitment", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference + if x.Recruitment != nil { + if x.Recruitment.Eligibility != nil { + if x.Recruitment.Eligibility.Reference != nil { + refVal := *x.Recruitment.Eligibility.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "medication_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "recruitment_eligibility_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "recruitment_eligibility_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "eligibility_research_study_recruitment") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "eligibility_research_study_recruitment", + projectJSON, + refType, + sourceType, + )) + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "medication_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "medication_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "medication_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "medication_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "medication_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "medication_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "medication_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "medication_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Medication != nil { - if x.Medication.Reference != nil { - if x.Medication.Reference.Reference != nil { - refVal := *x.Medication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "medication_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "medication_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "note_authorReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -38407,46 +39896,49 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "note_authorReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -38455,46 +39947,49 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "note_authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -38503,46 +39998,49 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "note_authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -38551,46 +40049,49 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "reason_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -38599,46 +40100,49 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "reason_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -38647,46 +40151,49 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "reason_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -38695,46 +40202,49 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "reason_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -38743,46 +40253,49 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "reason_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -38791,46 +40304,49 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "reason_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -38839,46 +40355,49 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "reason_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -38887,46 +40406,49 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "reason_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -38935,46 +40457,49 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "reason_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -38983,46 +40508,49 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.RelatedArtifact != nil { + for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { + if item_3_x_RelatedArtifact != nil { + if item_3_x_RelatedArtifact.ResourceReference != nil { + if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { + refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "reason_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relatedArtifact_resourceReference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "related_artifact") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "related_artifact", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -39031,304 +40559,321 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "reason_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + return edges, nil +} + +// ExtractEdges extracts graph links from ResearchSubject. +func (x *ResearchSubject) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "ResearchSubject" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.Study != nil { + if x.Study.Reference != nil { + refVal := *x.Study.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "study") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "study", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "research_subject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "research_subject", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "reason_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "subject_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "research_subject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "research_subject", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "reason_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "subject_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "research_subject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "research_subject", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "reason_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "subject_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "research_subject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "research_subject", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "reason_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "subject_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "research_subject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "research_subject", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "reason_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "subject_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "research_subject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "research_subject", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + return edges, nil +} + +// ExtractEdges extracts graph links from Specimen. +func (x *Specimen) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "Specimen" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.Parent != nil { + for _, item_2_x_Parent := range x.Parent { + if item_2_x_Parent != nil { + if item_2_x_Parent.Reference != nil { + refVal := *item_2_x_Parent.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationRequest") + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "parent") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -39337,14 +40882,14 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "reason_reference_MedicationRequest", + collectionID(refType, targetID), + "parent", projectJSON, sourceType, - "MedicationRequest", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "parent_specimen") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -39352,12 +40897,12 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "parent_specimen", projectJSON, + refType, sourceType, - "reference", )) } } @@ -39367,388 +40912,151 @@ func (x *MedicationStatement) ExtractEdges(project string) ([]json.RawMessage, e } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "reason_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "subject_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "reason_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Patient", + projectJSON, + sourceType, + refType, + )) } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "reason_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + backrefKey := getEdgeUUID(id, targetID, "specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "reason_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "specimen", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "reason_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "subject_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "specimen", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "reason_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Subject != nil { + if x.Subject.Reference != nil { + refVal := *x.Subject.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "subject_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "subject_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "specimen", + projectJSON, + refType, + sourceType, + )) } } } } } } - return edges, nil -} - -// ExtractEdges extracts graph links from MedicationStatementAdherence. -func (x *MedicationStatementAdherence) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "MedicationStatementAdherence" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from Meta. -func (x *Meta) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Meta" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from Money. -func (x *Money) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Money" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from Narrative. -func (x *Narrative) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Narrative" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from Observation. -func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Observation" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Collection != nil { + if x.Collection.Collector != nil { + if x.Collection.Collector.Reference != nil { + refVal := *x.Collection.Collector.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_MedicationRequest") + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "collection_collector_Practitioner") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -39757,14 +41065,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "basedOn_MedicationRequest", + collectionID(refType, targetID), + "collection_collector_Practitioner", projectJSON, sourceType, - "MedicationRequest", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "basedOn_observation") + backrefKey := getEdgeUUID(id, targetID, "specimen_collection") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -39772,12 +41080,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "basedOn_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "specimen_collection", projectJSON, + refType, sourceType, - "observation", )) } } @@ -39786,57 +41094,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.BodyStructure != nil { - if x.BodyStructure.Reference != nil { - refVal := *x.BodyStructure.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "bodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("bodyStructure", targetID), - "bodyStructure", - projectJSON, - sourceType, - "bodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "observation", - projectJSON, - sourceType, - "observation", - )) - } - } - } - } - } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Collection != nil { + if x.Collection.Collector != nil { + if x.Collection.Collector.Reference != nil { + refVal := *x.Collection.Collector.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_DocumentReference") + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "collection_collector_PractitionerRole") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -39845,14 +41112,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "derivedFrom_DocumentReference", + collectionID(refType, targetID), + "collection_collector_PractitionerRole", projectJSON, sourceType, - "DocumentReference", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_observation") + backrefKey := getEdgeUUID(id, targetID, "specimen_collection") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -39860,12 +41127,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "derivedFrom_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "specimen_collection", projectJSON, + refType, sourceType, - "observation", )) } } @@ -39874,15 +41141,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Collection != nil { + if x.Collection.Collector != nil { + if x.Collection.Collector.Reference != nil { + refVal := *x.Collection.Collector.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_ImagingStudy") + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "collection_collector_Patient") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -39891,14 +41159,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "derivedFrom_ImagingStudy", + collectionID(refType, targetID), + "collection_collector_Patient", projectJSON, sourceType, - "ImagingStudy", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_observation") + backrefKey := getEdgeUUID(id, targetID, "specimen_collection") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -39906,12 +41174,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "derivedFrom_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "specimen_collection", projectJSON, + refType, sourceType, - "observation", )) } } @@ -39920,15 +41188,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.DerivedFrom != nil { - for _, item_2_x_DerivedFrom := range x.DerivedFrom { - if item_2_x_DerivedFrom != nil { - if item_2_x_DerivedFrom.Reference != nil { - refVal := *item_2_x_DerivedFrom.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Collection != nil { + if x.Collection.Procedure != nil { + if x.Collection.Procedure.Reference != nil { + refVal := *x.Collection.Procedure.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "derivedFrom_Observation") + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "collection_procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -39937,14 +41206,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Observation", targetID), - "derivedFrom_Observation", + collectionID(refType, targetID), + "collection_procedure", projectJSON, sourceType, - "Observation", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "derivedFrom_observation") + backrefKey := getEdgeUUID(id, targetID, "specimen_collection") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -39952,12 +41221,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "derivedFrom_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "specimen_collection", projectJSON, + refType, sourceType, - "observation", )) } } @@ -39966,45 +41235,50 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "focus_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "focus_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", - projectJSON, - sourceType, - "observation", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -40012,45 +41286,50 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "focus_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "focus_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", - projectJSON, - sourceType, - "observation", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -40058,45 +41337,50 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "focus_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "focus_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", - projectJSON, - sourceType, - "observation", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -40104,45 +41388,50 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "focus_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "focus_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", - projectJSON, - sourceType, - "observation", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -40150,45 +41439,54 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "focus_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "focus_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", - projectJSON, - sourceType, - "observation", - )) + if x.Processing != nil { + for _, item_4_x_Processing := range x.Processing { + if item_4_x_Processing != nil { + if item_4_x_Processing.Additive != nil { + for _, item_2_item_4_x_Processing_Additive := range item_4_x_Processing.Additive { + if item_2_item_4_x_Processing_Additive != nil { + if item_2_item_4_x_Processing_Additive.Reference != nil { + refVal := *item_2_item_4_x_Processing_Additive.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "processing_additive") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "processing_additive", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "additive_specimen_processing") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "additive_specimen_processing", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } @@ -40196,15 +41494,33 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) + return edges, nil +} + +// ExtractEdges extracts graph links from Substance. +func (x *Substance) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "Substance" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "focus_Patient") + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_Organization") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40213,14 +41529,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Patient", targetID), - "focus_Patient", + collectionID(refType, targetID), + "code_reference_Organization", projectJSON, sourceType, - "Patient", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40228,12 +41544,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -40242,15 +41558,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "focus_ResearchSubject") + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_Group") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40259,14 +41576,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "focus_ResearchSubject", + collectionID(refType, targetID), + "code_reference_Group", projectJSON, sourceType, - "ResearchSubject", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40274,12 +41591,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -40288,15 +41605,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "focus_Substance") + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_Practitioner") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40305,14 +41623,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Substance", targetID), - "focus_Substance", + collectionID(refType, targetID), + "code_reference_Practitioner", projectJSON, sourceType, - "Substance", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40320,12 +41638,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -40334,15 +41652,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "focus_SubstanceDefinition") + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_PractitionerRole") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40351,14 +41670,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "focus_SubstanceDefinition", + collectionID(refType, targetID), + "code_reference_PractitionerRole", projectJSON, sourceType, - "SubstanceDefinition", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40366,12 +41685,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -40380,15 +41699,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "focus_Specimen") + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_ResearchStudy") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40397,14 +41717,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Specimen", targetID), - "focus_Specimen", + collectionID(refType, targetID), + "code_reference_ResearchStudy", projectJSON, sourceType, - "Specimen", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40412,12 +41732,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -40426,15 +41746,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "focus_Observation") + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_Patient") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40443,14 +41764,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Observation", targetID), - "focus_Observation", + collectionID(refType, targetID), + "code_reference_Patient", projectJSON, sourceType, - "Observation", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40458,12 +41779,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -40472,15 +41793,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "focus_DiagnosticReport") + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_ResearchSubject") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40489,14 +41811,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "focus_DiagnosticReport", + collectionID(refType, targetID), + "code_reference_ResearchSubject", projectJSON, sourceType, - "DiagnosticReport", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40504,12 +41826,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -40518,15 +41840,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "focus_Condition") + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_Substance") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40535,14 +41858,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Condition", targetID), - "focus_Condition", + collectionID(refType, targetID), + "code_reference_Substance", projectJSON, sourceType, - "Condition", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40550,12 +41873,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -40564,15 +41887,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "focus_Medication") + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_SubstanceDefinition") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40581,14 +41905,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Medication", targetID), - "focus_Medication", + collectionID(refType, targetID), + "code_reference_SubstanceDefinition", projectJSON, sourceType, - "Medication", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40596,12 +41920,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -40610,15 +41934,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "focus_MedicationAdministration") + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_Specimen") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40627,14 +41952,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "focus_MedicationAdministration", + collectionID(refType, targetID), + "code_reference_Specimen", projectJSON, sourceType, - "MedicationAdministration", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40642,12 +41967,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -40656,15 +41981,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "focus_MedicationStatement") + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_Observation") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40673,14 +41999,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "focus_MedicationStatement", + collectionID(refType, targetID), + "code_reference_Observation", projectJSON, sourceType, - "MedicationStatement", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40688,12 +42014,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -40702,15 +42028,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "focus_MedicationRequest") + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_DiagnosticReport") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40719,14 +42046,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "focus_MedicationRequest", + collectionID(refType, targetID), + "code_reference_DiagnosticReport", projectJSON, sourceType, - "MedicationRequest", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40734,12 +42061,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -40748,15 +42075,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "focus_Procedure") + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_Condition") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40765,14 +42093,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Procedure", targetID), - "focus_Procedure", + collectionID(refType, targetID), + "code_reference_Condition", projectJSON, sourceType, - "Procedure", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40780,12 +42108,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -40794,15 +42122,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "focus_DocumentReference") + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_Medication") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40811,14 +42140,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "focus_DocumentReference", + collectionID(refType, targetID), + "code_reference_Medication", projectJSON, sourceType, - "DocumentReference", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40826,12 +42155,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -40840,15 +42169,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "focus_Task") + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_MedicationAdministration") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40857,14 +42187,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Task", targetID), - "focus_Task", + collectionID(refType, targetID), + "code_reference_MedicationAdministration", projectJSON, sourceType, - "Task", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40872,12 +42202,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -40886,15 +42216,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "focus_ImagingStudy") + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_MedicationStatement") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40903,14 +42234,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "focus_ImagingStudy", + collectionID(refType, targetID), + "code_reference_MedicationStatement", projectJSON, sourceType, - "ImagingStudy", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40918,12 +42249,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -40932,15 +42263,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "focus_FamilyMemberHistory") + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_MedicationRequest") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40949,14 +42281,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "focus_FamilyMemberHistory", + collectionID(refType, targetID), + "code_reference_MedicationRequest", projectJSON, sourceType, - "FamilyMemberHistory", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40964,12 +42296,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -40978,15 +42310,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Focus != nil { - for _, item_2_x_Focus := range x.Focus { - if item_2_x_Focus != nil { - if item_2_x_Focus.Reference != nil { - refVal := *item_2_x_Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "focus_BodyStructure") + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_Procedure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -40995,14 +42328,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "focus_BodyStructure", + collectionID(refType, targetID), + "code_reference_Procedure", projectJSON, sourceType, - "BodyStructure", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "focus_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41010,12 +42343,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "focus_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -41024,15 +42357,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.HasMember != nil { - for _, item_2_x_HasMember := range x.HasMember { - if item_2_x_HasMember != nil { - if item_2_x_HasMember.Reference != nil { - refVal := *item_2_x_HasMember.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "hasMember_Observation") + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_DocumentReference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41041,14 +42375,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Observation", targetID), - "hasMember_Observation", + collectionID(refType, targetID), + "code_reference_DocumentReference", projectJSON, sourceType, - "Observation", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "hasMember_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41056,12 +42390,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "hasMember_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -41070,15 +42404,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.PartOf != nil { - for _, item_2_x_PartOf := range x.PartOf { - if item_2_x_PartOf != nil { - if item_2_x_PartOf.Reference != nil { - refVal := *item_2_x_PartOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "partOf_MedicationAdministration") + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_Task") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41087,14 +42422,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "partOf_MedicationAdministration", + collectionID(refType, targetID), + "code_reference_Task", projectJSON, sourceType, - "MedicationAdministration", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "partOf_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41102,12 +42437,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "partOf_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -41116,15 +42451,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.PartOf != nil { - for _, item_2_x_PartOf := range x.PartOf { - if item_2_x_PartOf != nil { - if item_2_x_PartOf.Reference != nil { - refVal := *item_2_x_PartOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "partOf_MedicationStatement") + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_ImagingStudy") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41133,14 +42469,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "partOf_MedicationStatement", + collectionID(refType, targetID), + "code_reference_ImagingStudy", projectJSON, sourceType, - "MedicationStatement", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "partOf_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41148,12 +42484,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "partOf_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -41162,15 +42498,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.PartOf != nil { - for _, item_2_x_PartOf := range x.PartOf { - if item_2_x_PartOf != nil { - if item_2_x_PartOf.Reference != nil { - refVal := *item_2_x_PartOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "partOf_Procedure") + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_FamilyMemberHistory") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41179,14 +42516,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Procedure", targetID), - "partOf_Procedure", + collectionID(refType, targetID), + "code_reference_FamilyMemberHistory", projectJSON, sourceType, - "Procedure", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "partOf_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41194,12 +42531,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "partOf_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -41208,15 +42545,16 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.PartOf != nil { - for _, item_2_x_PartOf := range x.PartOf { - if item_2_x_PartOf != nil { - if item_2_x_PartOf.Reference != nil { - refVal := *item_2_x_PartOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.Code != nil { + if x.Code.Reference != nil { + if x.Code.Reference.Reference != nil { + refVal := *x.Code.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "partOf_ImagingStudy") + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "code_reference_BodyStructure") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41225,14 +42563,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "partOf_ImagingStudy", + collectionID(refType, targetID), + "code_reference_BodyStructure", projectJSON, sourceType, - "ImagingStudy", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "partOf_observation") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41240,12 +42578,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "partOf_observation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "observation", )) } } @@ -41254,45 +42592,50 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Performer != nil { - for _, item_2_x_Performer := range x.Performer { - if item_2_x_Performer != nil { - if item_2_x_Performer.Reference != nil { - refVal := *item_2_x_Performer.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "performer_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "performer_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "performer_observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "performer_observation", - projectJSON, - sourceType, - "observation", - )) + if x.Ingredient != nil { + for _, item_3_x_Ingredient := range x.Ingredient { + if item_3_x_Ingredient != nil { + if item_3_x_Ingredient.SubstanceReference != nil { + if item_3_x_Ingredient.SubstanceReference.Reference != nil { + refVal := *item_3_x_Ingredient.SubstanceReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "ingredient_substanceReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "ingredient_substanceReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "substance_ingredient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "substance_ingredient", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -41300,45 +42643,65 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Performer != nil { - for _, item_2_x_Performer := range x.Performer { - if item_2_x_Performer != nil { - if item_2_x_Performer.Reference != nil { - refVal := *item_2_x_Performer.Reference + return edges, nil +} + +// ExtractEdges extracts graph links from SubstanceDefinition. +func (x *SubstanceDefinition) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "SubstanceDefinition" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.Manufacturer != nil { + for _, item_2_x_Manufacturer := range x.Manufacturer { + if item_2_x_Manufacturer != nil { + if item_2_x_Manufacturer.Reference != nil { + refVal := *item_2_x_Manufacturer.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "performer_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "performer_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "performer_observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "performer_observation", - projectJSON, - sourceType, - "observation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "manufacturer") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "manufacturer", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "manufacturer_substance_definition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "manufacturer_substance_definition", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -41346,45 +42709,48 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Performer != nil { - for _, item_2_x_Performer := range x.Performer { - if item_2_x_Performer != nil { - if item_2_x_Performer.Reference != nil { - refVal := *item_2_x_Performer.Reference + if x.Supplier != nil { + for _, item_2_x_Supplier := range x.Supplier { + if item_2_x_Supplier != nil { + if item_2_x_Supplier.Reference != nil { + refVal := *item_2_x_Supplier.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "performer_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "performer_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "performer_observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "performer_observation", - projectJSON, - sourceType, - "observation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "supplier") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "supplier", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "supplier_substance_definition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "supplier_substance_definition", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -41392,45 +42758,54 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Performer != nil { - for _, item_2_x_Performer := range x.Performer { - if item_2_x_Performer != nil { - if item_2_x_Performer.Reference != nil { - refVal := *item_2_x_Performer.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "performer_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "performer_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "performer_observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "performer_observation", - projectJSON, - sourceType, - "observation", - )) + if x.Code != nil { + for _, item_4_x_Code := range x.Code { + if item_4_x_Code != nil { + if item_4_x_Code.Source != nil { + for _, item_2_item_4_x_Code_Source := range item_4_x_Code.Source { + if item_2_item_4_x_Code_Source != nil { + if item_2_item_4_x_Code_Source.Reference != nil { + refVal := *item_2_item_4_x_Code_Source.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "code_source") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "code_source", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "source_substance_definition_code") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "source_substance_definition_code", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } @@ -41438,394 +42813,499 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Specimen != nil { - if x.Specimen.Reference != nil { - refVal := *x.Specimen.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "specimen_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "specimen_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "specimen_observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "specimen_observation", - projectJSON, - sourceType, - "observation", - )) + if x.Name != nil { + for _, item_4_x_Name := range x.Name { + if item_4_x_Name != nil { + if item_4_x_Name.Source != nil { + for _, item_2_item_4_x_Name_Source := range item_4_x_Name.Source { + if item_2_item_4_x_Name_Source != nil { + if item_2_item_4_x_Name_Source.Reference != nil { + refVal := *item_2_item_4_x_Name_Source.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "name_source") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "name_source", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "source_substance_definition_name") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "source_substance_definition_name", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } } } } } } - if x.Specimen != nil { - if x.Specimen.Reference != nil { - refVal := *x.Specimen.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "specimen_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "specimen_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "specimen_observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "specimen_observation", - projectJSON, - sourceType, - "observation", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "subject_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "subject_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "subject_observation", - projectJSON, - sourceType, - "observation", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "subject_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "subject_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "subject_observation", - projectJSON, - sourceType, - "observation", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "subject_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "subject_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "subject_observation", - projectJSON, - sourceType, - "observation", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "subject_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "subject_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "subject_observation", - projectJSON, - sourceType, - "observation", - )) + if x.Relationship != nil { + for _, item_4_x_Relationship := range x.Relationship { + if item_4_x_Relationship != nil { + if item_4_x_Relationship.Source != nil { + for _, item_2_item_4_x_Relationship_Source := range item_4_x_Relationship.Source { + if item_2_item_4_x_Relationship_Source != nil { + if item_2_item_4_x_Relationship_Source.Reference != nil { + refVal := *item_2_item_4_x_Relationship_Source.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "relationship_source") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relationship_source", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "source_substance_definition_relationship") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "source_substance_definition_relationship", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "subject_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "subject_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "subject_observation", - projectJSON, - sourceType, - "observation", - )) + if x.Relationship != nil { + for _, item_3_x_Relationship := range x.Relationship { + if item_3_x_Relationship != nil { + if item_3_x_Relationship.SubstanceDefinitionReference != nil { + if item_3_x_Relationship.SubstanceDefinitionReference.Reference != nil { + refVal := *item_3_x_Relationship.SubstanceDefinitionReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "relationship_substanceDefinitionReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "relationship_substanceDefinitionReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "substance_definition_relationship") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "substance_definition_relationship", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "subject_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "subject_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "subject_observation", - projectJSON, - sourceType, - "observation", - )) + if x.Structure != nil { + if x.Structure.SourceDocument != nil { + for _, item_2_x_Structure_SourceDocument := range x.Structure.SourceDocument { + if item_2_x_Structure_SourceDocument != nil { + if item_2_x_Structure_SourceDocument.Reference != nil { + refVal := *item_2_x_Structure_SourceDocument.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "structure_sourceDocument") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "structure_sourceDocument", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "sourceDocument_substance_definition_structure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "sourceDocument_substance_definition_structure", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "subject_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "subject_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("observation", id), - "subject_observation", - projectJSON, - sourceType, - "observation", - )) + return edges, nil +} + +// ExtractEdges extracts graph links from Task. +func (x *Task) ExtractEdges(project string) ([]json.RawMessage, error) { + var edges []json.RawMessage + if x == nil || x.ID == nil { + return edges, nil + } + id := *x.ID + sourceType := "Task" + projectJSON := strconv.Quote(project) + _ = id + _ = sourceType + _ = projectJSON + var seen map[string]struct{} + _ = seen + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "basedOn_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_Group") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41834,14 +43314,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "note_authorReference_Practitioner", + collectionID(refType, targetID), + "basedOn_Group", projectJSON, sourceType, - "Practitioner", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "annotation") + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41849,12 +43329,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", projectJSON, + refType, sourceType, - "annotation", )) } } @@ -41864,16 +43344,17 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_Practitioner") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41882,14 +43363,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "note_authorReference_PractitionerRole", + collectionID(refType, targetID), + "basedOn_Practitioner", projectJSON, sourceType, - "PractitionerRole", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "annotation") + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41897,12 +43378,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", projectJSON, + refType, sourceType, - "annotation", )) } } @@ -41912,16 +43393,17 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_PractitionerRole") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41930,14 +43412,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Patient", targetID), - "note_authorReference_Patient", + collectionID(refType, targetID), + "basedOn_PractitionerRole", projectJSON, sourceType, - "Patient", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "annotation") + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41945,12 +43427,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", projectJSON, + refType, sourceType, - "annotation", )) } } @@ -41960,16 +43442,17 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_ResearchStudy") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41978,14 +43461,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Organization", targetID), - "note_authorReference_Organization", + collectionID(refType, targetID), + "basedOn_ResearchStudy", projectJSON, sourceType, - "Organization", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "annotation") + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -41993,12 +43476,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", projectJSON, + refType, sourceType, - "annotation", )) } } @@ -42008,16 +43491,17 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.TriggeredBy != nil { - for _, item_3_x_TriggeredBy := range x.TriggeredBy { - if item_3_x_TriggeredBy != nil { - if item_3_x_TriggeredBy.Observation != nil { - if item_3_x_TriggeredBy.Observation.Reference != nil { - refVal := *item_3_x_TriggeredBy.Observation.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "triggeredBy_observation") + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_Patient") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -42026,14 +43510,14 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("observation", targetID), - "triggeredBy_observation", + collectionID(refType, targetID), + "basedOn_Patient", projectJSON, sourceType, - "observation", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "observation_triggered_by") + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -42041,12 +43525,12 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("by", id), - "observation_triggered_by", + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", projectJSON, + refType, sourceType, - "by", )) } } @@ -42056,168 +43540,17 @@ func (x *Observation) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - return edges, nil -} - -// ExtractEdges extracts graph links from ObservationComponent. -func (x *ObservationComponent) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ObservationComponent" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from ObservationReferenceRange. -func (x *ObservationReferenceRange) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ObservationReferenceRange" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from ObservationTriggeredBy. -func (x *ObservationTriggeredBy) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ObservationTriggeredBy" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Observation != nil { - if x.Observation.Reference != nil { - refVal := *x.Observation.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("observation", targetID), - "observation", - projectJSON, - sourceType, - "observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "observation_triggered_by") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("by", id), - "observation_triggered_by", - projectJSON, - sourceType, - "by", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from Organization. -func (x *Organization) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Organization" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.PartOf != nil { - if x.PartOf.Reference != nil { - refVal := *x.PartOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "partOf") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("partOf", targetID), - "partOf", - projectJSON, - sourceType, - "partOf", - )) - } - backrefKey := getEdgeUUID(id, targetID, "organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("organization", id), - "organization", - projectJSON, - sourceType, - "organization", - )) - } - } - } - } - } - if x.Contact != nil { - for _, item_3_x_Contact := range x.Contact { - if item_3_x_Contact != nil { - if item_3_x_Contact.Organization != nil { - if item_3_x_Contact.Organization.Reference != nil { - refVal := *item_3_x_Contact.Organization.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "contact_organization") + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_ResearchSubject") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -42226,14 +43559,14 @@ func (x *Organization) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("organization", targetID), - "contact_organization", + collectionID(refType, targetID), + "basedOn_ResearchSubject", projectJSON, sourceType, - "organization", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "extended_contact_detail") + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -42241,12 +43574,12 @@ func (x *Organization) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("detail", id), - "extended_contact_detail", + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", projectJSON, + refType, sourceType, - "detail", )) } } @@ -42256,16 +43589,17 @@ func (x *Organization) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Qualification != nil { - for _, item_3_x_Qualification := range x.Qualification { - if item_3_x_Qualification != nil { - if item_3_x_Qualification.Issuer != nil { - if item_3_x_Qualification.Issuer.Reference != nil { - refVal := *item_3_x_Qualification.Issuer.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "qualification_issuer") + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_Substance") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -42274,14 +43608,14 @@ func (x *Organization) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("issuer", targetID), - "qualification_issuer", + collectionID(refType, targetID), + "basedOn_Substance", projectJSON, sourceType, - "issuer", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "organization_qualification") + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -42289,12 +43623,12 @@ func (x *Organization) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("qualification", id), - "organization_qualification", + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", projectJSON, + refType, sourceType, - "qualification", )) } } @@ -42304,289 +43638,17 @@ func (x *Organization) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - return edges, nil -} - -// ExtractEdges extracts graph links from OrganizationQualification. -func (x *OrganizationQualification) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "OrganizationQualification" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Issuer != nil { - if x.Issuer.Reference != nil { - refVal := *x.Issuer.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "issuer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("issuer", targetID), - "issuer", - projectJSON, - sourceType, - "issuer", - )) - } - backrefKey := getEdgeUUID(id, targetID, "organization_qualification") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("qualification", id), - "organization_qualification", - projectJSON, - sourceType, - "qualification", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from ParameterDefinition. -func (x *ParameterDefinition) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ParameterDefinition" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from Patient. -func (x *Patient) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Patient" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.GeneralPractitioner != nil { - for _, item_2_x_GeneralPractitioner := range x.GeneralPractitioner { - if item_2_x_GeneralPractitioner != nil { - if item_2_x_GeneralPractitioner.Reference != nil { - refVal := *item_2_x_GeneralPractitioner.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "generalPractitioner_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "generalPractitioner_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "generalPractitioner_patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("patient", id), - "generalPractitioner_patient", - projectJSON, - sourceType, - "patient", - )) - } - } - } - } - } - } - } - if x.GeneralPractitioner != nil { - for _, item_2_x_GeneralPractitioner := range x.GeneralPractitioner { - if item_2_x_GeneralPractitioner != nil { - if item_2_x_GeneralPractitioner.Reference != nil { - refVal := *item_2_x_GeneralPractitioner.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "generalPractitioner_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "generalPractitioner_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "generalPractitioner_patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("patient", id), - "generalPractitioner_patient", - projectJSON, - sourceType, - "patient", - )) - } - } - } - } - } - } - } - if x.GeneralPractitioner != nil { - for _, item_2_x_GeneralPractitioner := range x.GeneralPractitioner { - if item_2_x_GeneralPractitioner != nil { - if item_2_x_GeneralPractitioner.Reference != nil { - refVal := *item_2_x_GeneralPractitioner.Reference + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "generalPractitioner_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "generalPractitioner_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "generalPractitioner_patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("patient", id), - "generalPractitioner_patient", - projectJSON, - sourceType, - "patient", - )) - } - } - } - } - } - } - } - if x.ManagingOrganization != nil { - if x.ManagingOrganization.Reference != nil { - refVal := *x.ManagingOrganization.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "managingOrganization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("managingOrganization", targetID), - "managingOrganization", - projectJSON, - sourceType, - "managingOrganization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "managingOrganization_patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("patient", id), - "managingOrganization_patient", - projectJSON, - sourceType, - "patient", - )) - } - } - } - } - } - if x.Contact != nil { - for _, item_3_x_Contact := range x.Contact { - if item_3_x_Contact != nil { - if item_3_x_Contact.Organization != nil { - if item_3_x_Contact.Organization.Reference != nil { - refVal := *item_3_x_Contact.Organization.Reference - refType, targetID, ok := splitFHIRReference(refVal) + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "contact_organization") + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_SubstanceDefinition") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -42595,14 +43657,14 @@ func (x *Patient) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("organization", targetID), - "contact_organization", + collectionID(refType, targetID), + "basedOn_SubstanceDefinition", projectJSON, sourceType, - "organization", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "patient_contact") + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -42610,12 +43672,12 @@ func (x *Patient) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("contact", id), - "patient_contact", + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", projectJSON, + refType, sourceType, - "contact", )) } } @@ -42625,16 +43687,17 @@ func (x *Patient) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Link != nil { - for _, item_3_x_Link := range x.Link { - if item_3_x_Link != nil { - if item_3_x_Link.Other != nil { - if item_3_x_Link.Other.Reference != nil { - refVal := *item_3_x_Link.Other.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "link_other_Patient") + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_Specimen") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -42643,14 +43706,14 @@ func (x *Patient) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Patient", targetID), - "link_other_Patient", + collectionID(refType, targetID), + "basedOn_Specimen", projectJSON, sourceType, - "Patient", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "patient_link") + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -42658,12 +43721,12 @@ func (x *Patient) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("link", id), - "patient_link", + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", projectJSON, + refType, sourceType, - "link", )) } } @@ -42673,185 +43736,17 @@ func (x *Patient) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - return edges, nil -} - -// ExtractEdges extracts graph links from PatientCommunication. -func (x *PatientCommunication) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "PatientCommunication" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from PatientContact. -func (x *PatientContact) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "PatientContact" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Organization != nil { - if x.Organization.Reference != nil { - refVal := *x.Organization.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("organization", targetID), - "organization", - projectJSON, - sourceType, - "organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "patient_contact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("contact", id), - "patient_contact", - projectJSON, - sourceType, - "contact", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from PatientLink. -func (x *PatientLink) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "PatientLink" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Other != nil { - if x.Other.Reference != nil { - refVal := *x.Other.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "other_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "other_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "patient_link") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("link", id), - "patient_link", - projectJSON, - sourceType, - "link", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from Period. -func (x *Period) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Period" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from Practitioner. -func (x *Practitioner) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Practitioner" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Qualification != nil { - for _, item_3_x_Qualification := range x.Qualification { - if item_3_x_Qualification != nil { - if item_3_x_Qualification.Issuer != nil { - if item_3_x_Qualification.Issuer.Reference != nil { - refVal := *item_3_x_Qualification.Issuer.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "qualification_issuer") + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_Observation") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -42860,14 +43755,14 @@ func (x *Practitioner) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("issuer", targetID), - "qualification_issuer", + collectionID(refType, targetID), + "basedOn_Observation", projectJSON, sourceType, - "issuer", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "practitioner_qualification") + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -42875,12 +43770,12 @@ func (x *Practitioner) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("qualification", id), - "practitioner_qualification", + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", projectJSON, + refType, sourceType, - "qualification", )) } } @@ -42890,193 +43785,17 @@ func (x *Practitioner) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - return edges, nil -} - -// ExtractEdges extracts graph links from PractitionerCommunication. -func (x *PractitionerCommunication) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "PractitionerCommunication" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from PractitionerQualification. -func (x *PractitionerQualification) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "PractitionerQualification" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Issuer != nil { - if x.Issuer.Reference != nil { - refVal := *x.Issuer.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "issuer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("issuer", targetID), - "issuer", - projectJSON, - sourceType, - "issuer", - )) - } - backrefKey := getEdgeUUID(id, targetID, "practitioner_qualification") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("qualification", id), - "practitioner_qualification", - projectJSON, - sourceType, - "qualification", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from PractitionerRole. -func (x *PractitionerRole) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "PractitionerRole" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Organization != nil { - if x.Organization.Reference != nil { - refVal := *x.Organization.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("organization", targetID), - "organization", - projectJSON, - sourceType, - "organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "practitioner_role") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("role", id), - "practitioner_role", - projectJSON, - sourceType, - "role", - )) - } - } - } - } - } - if x.Practitioner != nil { - if x.Practitioner.Reference != nil { - refVal := *x.Practitioner.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("practitioner", targetID), - "practitioner", - projectJSON, - sourceType, - "practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "practitioner_role") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("role", id), - "practitioner_role", - projectJSON, - sourceType, - "role", - )) - } - } - } - } - } - if x.Contact != nil { - for _, item_3_x_Contact := range x.Contact { - if item_3_x_Contact != nil { - if item_3_x_Contact.Organization != nil { - if item_3_x_Contact.Organization.Reference != nil { - refVal := *item_3_x_Contact.Organization.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "contact_organization") + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_DiagnosticReport") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -43085,14 +43804,14 @@ func (x *PractitionerRole) ExtractEdges(project string) ([]json.RawMessage, erro edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("organization", targetID), - "contact_organization", + collectionID(refType, targetID), + "basedOn_DiagnosticReport", projectJSON, sourceType, - "organization", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "extended_contact_detail") + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -43100,12 +43819,12 @@ func (x *PractitionerRole) ExtractEdges(project string) ([]json.RawMessage, erro seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("detail", id), - "extended_contact_detail", + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", projectJSON, + refType, sourceType, - "detail", )) } } @@ -43115,314 +43834,342 @@ func (x *PractitionerRole) ExtractEdges(project string) ([]json.RawMessage, erro } } } - return edges, nil -} - -// ExtractEdges extracts graph links from Procedure. -func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Procedure" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "focus_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "focus_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "focus_procedure", - projectJSON, - sourceType, - "procedure", - )) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "basedOn_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "focus_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "focus_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "focus_procedure", - projectJSON, - sourceType, - "procedure", - )) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "basedOn_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "focus_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "focus_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "focus_procedure", - projectJSON, - sourceType, - "procedure", - )) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "basedOn_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "focus_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "focus_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "focus_procedure", - projectJSON, - sourceType, - "procedure", - )) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "basedOn_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "focus_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "focus_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "focus_procedure", - projectJSON, - sourceType, - "procedure", - )) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "basedOn_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "focus_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "focus_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "focus_procedure", - projectJSON, - sourceType, - "procedure", - )) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "basedOn_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } - if x.PartOf != nil { - for _, item_2_x_PartOf := range x.PartOf { - if item_2_x_PartOf != nil { - if item_2_x_PartOf.Reference != nil { - refVal := *item_2_x_PartOf.Reference + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "partOf_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "partOf_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "partOf_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "partOf_procedure", - projectJSON, - sourceType, - "procedure", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "basedOn_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -43430,45 +44177,48 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.PartOf != nil { - for _, item_2_x_PartOf := range x.PartOf { - if item_2_x_PartOf != nil { - if item_2_x_PartOf.Reference != nil { - refVal := *item_2_x_PartOf.Reference + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "partOf_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "partOf_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "partOf_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "partOf_procedure", - projectJSON, - sourceType, - "procedure", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "basedOn_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -43476,45 +44226,48 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.PartOf != nil { - for _, item_2_x_PartOf := range x.PartOf { - if item_2_x_PartOf != nil { - if item_2_x_PartOf.Reference != nil { - refVal := *item_2_x_PartOf.Reference + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "partOf_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "partOf_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "partOf_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "partOf_procedure", - projectJSON, - sourceType, - "procedure", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "basedOn_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -43522,2540 +44275,2365 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Recorder != nil { - if x.Recorder.Reference != nil { - refVal := *x.Recorder.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "recorder_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "recorder_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "recorder_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "recorder_procedure", - projectJSON, - sourceType, - "procedure", - )) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "basedOn_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } - if x.Recorder != nil { - if x.Recorder.Reference != nil { - refVal := *x.Recorder.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "recorder_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "recorder_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "recorder_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "recorder_procedure", - projectJSON, - sourceType, - "procedure", - )) + if x.BasedOn != nil { + for _, item_2_x_BasedOn := range x.BasedOn { + if item_2_x_BasedOn != nil { + if item_2_x_BasedOn.Reference != nil { + refVal := *item_2_x_BasedOn.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "basedOn_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "basedOn_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "basedOn_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "basedOn_task", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } - if x.Recorder != nil { - if x.Recorder.Reference != nil { - refVal := *x.Recorder.Reference + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "recorder_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "recorder_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "recorder_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "recorder_procedure", - projectJSON, - sourceType, - "procedure", - )) - } - } - } - } - } - if x.Report != nil { - for _, item_2_x_Report := range x.Report { - if item_2_x_Report != nil { - if item_2_x_Report.Reference != nil { - refVal := *item_2_x_Report.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "report_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "report_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "report_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "report_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "focus_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Report != nil { - for _, item_2_x_Report := range x.Report { - if item_2_x_Report != nil { - if item_2_x_Report.Reference != nil { - refVal := *item_2_x_Report.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "report_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "report_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "report_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "report_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "focus_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.ReportedReference != nil { - if x.ReportedReference.Reference != nil { - refVal := *x.ReportedReference.Reference + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "reportedReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "reportedReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "reportedReference_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "reportedReference_procedure", - projectJSON, - sourceType, - "procedure", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "focus_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) + } } } } } } - if x.ReportedReference != nil { - if x.ReportedReference.Reference != nil { - refVal := *x.ReportedReference.Reference + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "reportedReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "reportedReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "reportedReference_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "reportedReference_procedure", - projectJSON, - sourceType, - "procedure", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "focus_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) + } } } } } } - if x.ReportedReference != nil { - if x.ReportedReference.Reference != nil { - refVal := *x.ReportedReference.Reference + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "reportedReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "reportedReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "reportedReference_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "reportedReference_procedure", - projectJSON, - sourceType, - "procedure", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "focus_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) + } } } } } } - if x.ReportedReference != nil { - if x.ReportedReference.Reference != nil { - refVal := *x.ReportedReference.Reference + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "reportedReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "reportedReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "reportedReference_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "reportedReference_procedure", - projectJSON, - sourceType, - "procedure", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "focus_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "subject_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "subject_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "subject_procedure", - projectJSON, - sourceType, - "procedure", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "focus_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "subject_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "subject_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "subject_procedure", - projectJSON, - sourceType, - "procedure", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "focus_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "subject_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "subject_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "subject_procedure", - projectJSON, - sourceType, - "procedure", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "focus_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) + } } } } } } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "subject_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "subject_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "subject_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "subject_procedure", - projectJSON, - sourceType, - "procedure", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "focus_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) + } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "supportingInfo_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "focus_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "supportingInfo_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "focus_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "supportingInfo_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "focus_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) } - } - } - } - } - } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "supportingInfo_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "supportingInfo_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "focus_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "supportingInfo_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "focus_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "supportingInfo_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "focus_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "supportingInfo_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "focus_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "supportingInfo_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "focus_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "supportingInfo_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "focus_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "supportingInfo_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "focus_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "supportingInfo_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "focus_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "supportingInfo_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "focus_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "supportingInfo_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.Focus != nil { + if x.Focus.Reference != nil { + refVal := *x.Focus.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "focus_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "focus_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "focus_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "focus_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "supportingInfo_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "supportingInfo_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "supportingInfo_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "supportingInfo_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "supportingInfo_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "supportingInfo_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } - } - } - } - } - } - } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "supportingInfo_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "supportingInfo_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.SupportingInfo != nil { - for _, item_2_x_SupportingInfo := range x.SupportingInfo { - if item_2_x_SupportingInfo != nil { - if item_2_x_SupportingInfo.Reference != nil { - refVal := *item_2_x_SupportingInfo.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "supportingInfo_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "supportingInfo_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supportingInfo_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("procedure", id), - "supportingInfo_procedure", - projectJSON, - sourceType, - "procedure", - )) - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "complication_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "complication_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "complication_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "complication_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "complication_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "complication_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "complication_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "complication_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "complication_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "complication_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "complication_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "complication_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "complication_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "complication_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "complication_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.ForFhir != nil { + if x.ForFhir.Reference != nil { + refVal := *x.ForFhir.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "for_fhir_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "for_fhir_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "for_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "for_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "complication_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Owner != nil { + if x.Owner.Reference != nil { + refVal := *x.Owner.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "owner_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "owner_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "owner_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "owner_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "complication_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Owner != nil { + if x.Owner.Reference != nil { + refVal := *x.Owner.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "owner_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "owner_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "owner_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "owner_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "complication_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Owner != nil { + if x.Owner.Reference != nil { + refVal := *x.Owner.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "owner_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "owner_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "owner_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "owner_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "complication_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Owner != nil { + if x.Owner.Reference != nil { + refVal := *x.Owner.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "owner_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "owner_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "owner_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "owner_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.PartOf != nil { + for _, item_2_x_PartOf := range x.PartOf { + if item_2_x_PartOf != nil { + if item_2_x_PartOf.Reference != nil { + refVal := *item_2_x_PartOf.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_Task") + forwardKey := getEdgeUUID(targetID, id, "partOf") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -46064,14 +46642,14 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("Task", targetID), - "complication_reference_Task", + collectionID(refType, targetID), + "partOf", projectJSON, sourceType, - "Task", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + backrefKey := getEdgeUUID(id, targetID, "partOf_task") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -46079,12 +46657,12 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", + collectionID(refType, targetID), + collectionID(sourceType, id), + "partOf_task", projectJSON, + refType, sourceType, - "reference", )) } } @@ -46094,238 +46672,229 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "complication_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Requester != nil { + if x.Requester.Reference != nil { + refVal := *x.Requester.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "requester_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requester_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "requester_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "requester_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "complication_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Requester != nil { + if x.Requester.Reference != nil { + refVal := *x.Requester.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "requester_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requester_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "requester_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "requester_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Complication != nil { - for _, item_3_x_Complication := range x.Complication { - if item_3_x_Complication != nil { - if item_3_x_Complication.Reference != nil { - if item_3_x_Complication.Reference.Reference != nil { - refVal := *item_3_x_Complication.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "complication_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "complication_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } + if x.Requester != nil { + if x.Requester.Reference != nil { + refVal := *x.Requester.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "requester_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requester_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "requester_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "requester_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "note_authorReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } + if x.Requester != nil { + if x.Requester.Reference != nil { + refVal := *x.Requester.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "requester_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requester_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "requester_task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "requester_task", + projectJSON, + refType, + sourceType, + )) } } } } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "note_authorReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -46334,46 +46903,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "note_authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -46382,46 +46954,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "note_authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -46430,46 +47005,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Performer != nil { - for _, item_3_x_Performer := range x.Performer { - if item_3_x_Performer != nil { - if item_3_x_Performer.Actor != nil { - if item_3_x_Performer.Actor.Reference != nil { - refVal := *item_3_x_Performer.Actor.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "performer_actor_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "performer_actor_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "actor_procedure_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "actor_procedure_performer", - projectJSON, - sourceType, - "performer", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -46478,46 +47056,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Performer != nil { - for _, item_3_x_Performer := range x.Performer { - if item_3_x_Performer != nil { - if item_3_x_Performer.Actor != nil { - if item_3_x_Performer.Actor.Reference != nil { - refVal := *item_3_x_Performer.Actor.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "performer_actor_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "performer_actor_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "actor_procedure_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "actor_procedure_performer", - projectJSON, - sourceType, - "performer", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -46526,46 +47107,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Performer != nil { - for _, item_3_x_Performer := range x.Performer { - if item_3_x_Performer != nil { - if item_3_x_Performer.Actor != nil { - if item_3_x_Performer.Actor.Reference != nil { - refVal := *item_3_x_Performer.Actor.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "performer_actor_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "performer_actor_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "actor_procedure_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "actor_procedure_performer", - projectJSON, - sourceType, - "performer", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -46574,46 +47158,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Performer != nil { - for _, item_3_x_Performer := range x.Performer { - if item_3_x_Performer != nil { - if item_3_x_Performer.Actor != nil { - if item_3_x_Performer.Actor.Reference != nil { - refVal := *item_3_x_Performer.Actor.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "performer_actor_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "performer_actor_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "actor_procedure_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "actor_procedure_performer", - projectJSON, - sourceType, - "performer", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -46622,46 +47209,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Performer != nil { - for _, item_3_x_Performer := range x.Performer { - if item_3_x_Performer != nil { - if item_3_x_Performer.OnBehalfOf != nil { - if item_3_x_Performer.OnBehalfOf.Reference != nil { - refVal := *item_3_x_Performer.OnBehalfOf.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "performer_onBehalfOf") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("onBehalfOf", targetID), - "performer_onBehalfOf", - projectJSON, - sourceType, - "onBehalfOf", - )) - } - backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_procedure_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "onBehalfOf_procedure_performer", - projectJSON, - sourceType, - "performer", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -46670,46 +47260,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "reason_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -46718,46 +47311,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "reason_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -46766,46 +47362,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "reason_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -46814,46 +47413,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "reason_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -46862,46 +47464,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "reason_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -46910,46 +47515,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "reason_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -46958,46 +47566,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "reason_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47006,46 +47617,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "reason_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47054,46 +47668,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "reason_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47102,46 +47719,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "reason_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47150,46 +47770,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "reason_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47198,46 +47821,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "reason_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47246,46 +47872,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "reason_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47294,46 +47923,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "reason_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47342,46 +47974,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Input != nil { + for _, item_3_x_Input := range x.Input { + if item_3_x_Input != nil { + if item_3_x_Input.ValueReference != nil { + if item_3_x_Input.ValueReference.Reference != nil { + refVal := *item_3_x_Input.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "reason_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "input_valueReference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "input_valueReference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_input") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_input", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47390,46 +48025,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "reason_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47438,46 +48076,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "reason_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47486,46 +48127,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "reason_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47534,46 +48178,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Note != nil { + for _, item_3_x_Note := range x.Note { + if item_3_x_Note != nil { + if item_3_x_Note.AuthorReference != nil { + if item_3_x_Note.AuthorReference.Reference != nil { + refVal := *item_3_x_Note.AuthorReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "reason_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "note_authorReference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "annotation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "annotation", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47582,46 +48229,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "reason_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47630,46 +48280,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "reason_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47678,46 +48331,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "reason_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47726,46 +48382,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "reason_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47774,46 +48433,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "used_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47822,46 +48484,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "used_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47870,46 +48535,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "used_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47918,46 +48586,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "used_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -47966,46 +48637,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "used_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48014,46 +48688,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "used_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48062,46 +48739,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "used_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48110,46 +48790,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "used_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48158,46 +48841,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "used_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48206,46 +48892,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "used_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48254,46 +48943,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "used_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48302,46 +48994,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "used_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48350,46 +49045,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "used_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48398,46 +49096,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "used_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48446,46 +49147,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "used_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48494,46 +49198,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "used_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48542,46 +49249,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "used_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48590,46 +49300,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "used_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48638,46 +49351,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Output != nil { + for _, item_3_x_Output := range x.Output { + if item_3_x_Output != nil { + if item_3_x_Output.ValueReference != nil { + if item_3_x_Output.ValueReference.Reference != nil { + refVal := *item_3_x_Output.ValueReference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "used_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "output_valueReference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "output_valueReference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_output") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_output", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48686,46 +49402,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Performer != nil { + for _, item_3_x_Performer := range x.Performer { + if item_3_x_Performer != nil { + if item_3_x_Performer.Actor != nil { + if item_3_x_Performer.Actor.Reference != nil { + refVal := *item_3_x_Performer.Actor.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "used_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "performer_actor_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "performer_actor_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_performer") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_performer", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48734,46 +49453,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Performer != nil { + for _, item_3_x_Performer := range x.Performer { + if item_3_x_Performer != nil { + if item_3_x_Performer.Actor != nil { + if item_3_x_Performer.Actor.Reference != nil { + refVal := *item_3_x_Performer.Actor.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "used_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "performer_actor_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "performer_actor_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_performer") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_performer", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48782,46 +49504,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Performer != nil { + for _, item_3_x_Performer := range x.Performer { + if item_3_x_Performer != nil { + if item_3_x_Performer.Actor != nil { + if item_3_x_Performer.Actor.Reference != nil { + refVal := *item_3_x_Performer.Actor.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "used_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "performer_actor_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "performer_actor_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_performer") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_performer", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48830,46 +49555,49 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - if x.Used != nil { - for _, item_3_x_Used := range x.Used { - if item_3_x_Used != nil { - if item_3_x_Used.Reference != nil { - if item_3_x_Used.Reference.Reference != nil { - refVal := *item_3_x_Used.Reference.Reference + if x.Performer != nil { + for _, item_3_x_Performer := range x.Performer { + if item_3_x_Performer != nil { + if item_3_x_Performer.Actor != nil { + if item_3_x_Performer.Actor.Reference != nil { + refVal := *item_3_x_Performer.Actor.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "used_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "used_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "performer_actor_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "performer_actor_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "task_performer") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "task_performer", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -48878,1400 +49606,203 @@ func (x *Procedure) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - return edges, nil -} - -// ExtractEdges extracts graph links from ProcedureFocalDevice. -func (x *ProcedureFocalDevice) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ProcedureFocalDevice" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from ProcedurePerformer. -func (x *ProcedurePerformer) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ProcedurePerformer" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "actor_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "actor_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "actor_procedure_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "actor_procedure_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "actor_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "actor_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "actor_procedure_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "actor_procedure_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "actor_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "actor_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "actor_procedure_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "actor_procedure_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "actor_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "actor_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "actor_procedure_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "actor_procedure_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - if x.OnBehalfOf != nil { - if x.OnBehalfOf.Reference != nil { - refVal := *x.OnBehalfOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "onBehalfOf") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("onBehalfOf", targetID), - "onBehalfOf", - projectJSON, - sourceType, - "onBehalfOf", - )) - } - backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_procedure_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "onBehalfOf_procedure_performer", - projectJSON, - sourceType, - "performer", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - return edges, nil -} - -// ExtractEdges extracts graph links from Quantity. -func (x *Quantity) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Quantity" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from Range. -func (x *Range) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Range" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from Ratio. -func (x *Ratio) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Ratio" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from RatioRange. -func (x *RatioRange) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "RatioRange" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from Reference. -func (x *Reference) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Reference" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from RelatedArtifact. -func (x *RelatedArtifact) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "RelatedArtifact" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "resourceReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "resourceReference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "resourceReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "resourceReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "resourceReference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "resourceReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "resourceReference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "resourceReference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "resourceReference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "resourceReference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "resourceReference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "resourceReference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "resourceReference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "resourceReference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "resourceReference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "resourceReference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "resourceReference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "resourceReference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "resourceReference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "resourceReference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "resourceReference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "resourceReference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - if x.ResourceReference != nil { - if x.ResourceReference.Reference != nil { - refVal := *x.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "resourceReference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "resourceReference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - return edges, nil -} - -// ExtractEdges extracts graph links from ResearchStudy. -func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ResearchStudy" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.RootDir != nil { - if x.RootDir.Reference != nil { - refVal := *x.RootDir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Directory" { - forwardKey := getEdgeUUID(targetID, id, "rootDir_Directory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Directory", targetID), - "rootDir_Directory", - projectJSON, - sourceType, - "Directory", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } } } } } } - if x.PartOf != nil { - for _, item_2_x_PartOf := range x.PartOf { - if item_2_x_PartOf != nil { - if item_2_x_PartOf.Reference != nil { - refVal := *item_2_x_PartOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "partOf") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("partOf", targetID), - "partOf", - projectJSON, - sourceType, - "partOf", - )) - } - backrefKey := getEdgeUUID(id, targetID, "partOf_research_study") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("study", id), - "partOf_research_study", - projectJSON, - sourceType, - "study", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -50279,45 +49810,50 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Result != nil { - for _, item_2_x_Result := range x.Result { - if item_2_x_Result != nil { - if item_2_x_Result.Reference != nil { - refVal := *item_2_x_Result.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "result_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "result_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "result_research_study") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("study", id), - "result_research_study", - projectJSON, - sourceType, - "study", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -50325,45 +49861,50 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Site != nil { - for _, item_2_x_Site := range x.Site { - if item_2_x_Site != nil { - if item_2_x_Site.Reference != nil { - refVal := *item_2_x_Site.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "site_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "site_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "site_research_study") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("study", id), - "site_research_study", - projectJSON, - sourceType, - "study", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -50371,45 +49912,50 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Site != nil { - for _, item_2_x_Site := range x.Site { - if item_2_x_Site != nil { - if item_2_x_Site.Reference != nil { - refVal := *item_2_x_Site.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "site_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "site_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "site_research_study") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("study", id), - "site_research_study", - projectJSON, - sourceType, - "study", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } } } } @@ -50417,46 +49963,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.AssociatedParty != nil { - for _, item_3_x_AssociatedParty := range x.AssociatedParty { - if item_3_x_AssociatedParty != nil { - if item_3_x_AssociatedParty.Party != nil { - if item_3_x_AssociatedParty.Party.Reference != nil { - refVal := *item_3_x_AssociatedParty.Party.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "associatedParty_party_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "associatedParty_party_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "research_study_associated_party") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("party", id), - "research_study_associated_party", - projectJSON, - sourceType, - "party", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -50465,46 +50014,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.AssociatedParty != nil { - for _, item_3_x_AssociatedParty := range x.AssociatedParty { - if item_3_x_AssociatedParty != nil { - if item_3_x_AssociatedParty.Party != nil { - if item_3_x_AssociatedParty.Party.Reference != nil { - refVal := *item_3_x_AssociatedParty.Party.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "associatedParty_party_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "associatedParty_party_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "research_study_associated_party") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("party", id), - "research_study_associated_party", - projectJSON, - sourceType, - "party", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -50513,46 +50065,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.AssociatedParty != nil { - for _, item_3_x_AssociatedParty := range x.AssociatedParty { - if item_3_x_AssociatedParty != nil { - if item_3_x_AssociatedParty.Party != nil { - if item_3_x_AssociatedParty.Party.Reference != nil { - refVal := *item_3_x_AssociatedParty.Party.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "associatedParty_party_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "associatedParty_party_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "research_study_associated_party") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("party", id), - "research_study_associated_party", - projectJSON, - sourceType, - "party", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -50561,46 +50116,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.ComparisonGroup != nil { - for _, item_3_x_ComparisonGroup := range x.ComparisonGroup { - if item_3_x_ComparisonGroup != nil { - if item_3_x_ComparisonGroup.ObservedGroup != nil { - if item_3_x_ComparisonGroup.ObservedGroup.Reference != nil { - refVal := *item_3_x_ComparisonGroup.ObservedGroup.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "comparisonGroup_observedGroup") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("observedGroup", targetID), - "comparisonGroup_observedGroup", - projectJSON, - sourceType, - "observedGroup", - )) - } - backrefKey := getEdgeUUID(id, targetID, "research_study_comparison_group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("group", id), - "research_study_comparison_group", - projectJSON, - sourceType, - "group", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -50609,46 +50167,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "focus_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -50657,46 +50218,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "focus_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -50705,46 +50269,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "focus_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -50753,46 +50320,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "focus_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -50801,46 +50371,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "focus_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -50849,46 +50422,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "focus_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -50897,46 +50473,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "focus_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -50945,46 +50524,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "focus_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -50993,46 +50575,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "focus_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51041,46 +50626,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "focus_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51089,46 +50677,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "focus_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51137,46 +50728,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.Reason != nil { + for _, item_3_x_Reason := range x.Reason { + if item_3_x_Reason != nil { + if item_3_x_Reason.Reference != nil { + if item_3_x_Reason.Reference.Reference != nil { + refVal := *item_3_x_Reason.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "focus_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "reason_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "reason_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51185,46 +50779,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "focus_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51233,46 +50830,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "focus_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51281,46 +50881,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "focus_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51329,46 +50932,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "focus_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51377,46 +50983,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "focus_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51425,46 +51034,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "focus_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51473,46 +51085,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "focus_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51521,46 +51136,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "focus_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51569,46 +51187,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "focus_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51617,46 +51238,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "focus_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51665,46 +51289,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Focus != nil { - for _, item_3_x_Focus := range x.Focus { - if item_3_x_Focus != nil { - if item_3_x_Focus.Reference != nil { - if item_3_x_Focus.Reference.Reference != nil { - refVal := *item_3_x_Focus.Reference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "focus_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "focus_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51713,46 +51340,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "note_authorReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_DiagnosticReport") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_DiagnosticReport", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51761,46 +51391,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "note_authorReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51809,46 +51442,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "note_authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51857,46 +51493,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "note_authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -51905,134 +51544,151 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.Recruitment != nil { - if x.Recruitment.ActualGroup != nil { - if x.Recruitment.ActualGroup.Reference != nil { - refVal := *x.Recruitment.ActualGroup.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "recruitment_actualGroup") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("actualGroup", targetID), - "recruitment_actualGroup", - projectJSON, - sourceType, - "actualGroup", - )) - } - backrefKey := getEdgeUUID(id, targetID, "actualGroup_research_study_recruitment") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("recruitment", id), - "actualGroup_research_study_recruitment", - projectJSON, - sourceType, - "recruitment", - )) + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.Recruitment != nil { - if x.Recruitment.Eligibility != nil { - if x.Recruitment.Eligibility.Reference != nil { - refVal := *x.Recruitment.Eligibility.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "recruitment_eligibility_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "recruitment_eligibility_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "eligibility_research_study_recruitment") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("recruitment", id), - "eligibility_research_study_recruitment", - projectJSON, - sourceType, - "recruitment", - )) + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } } } } } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "relatedArtifact_resourceReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -52041,46 +51697,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "relatedArtifact_resourceReference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -52089,46 +51748,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "relatedArtifact_resourceReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -52137,46 +51799,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "relatedArtifact_resourceReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -52185,46 +51850,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "relatedArtifact_resourceReference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -52233,46 +51901,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + if x.RequestedPerformer != nil { + for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { + if item_3_x_RequestedPerformer != nil { + if item_3_x_RequestedPerformer.Reference != nil { + if item_3_x_RequestedPerformer.Reference.Reference != nil { + refVal := *item_3_x_RequestedPerformer.Reference.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "relatedArtifact_resourceReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "requestedPerformer_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -52281,46 +51952,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + if x.Restriction != nil { + if x.Restriction.Recipient != nil { + for _, item_2_x_Restriction_Recipient := range x.Restriction.Recipient { + if item_2_x_Restriction_Recipient != nil { + if item_2_x_Restriction_Recipient.Reference != nil { + refVal := *item_2_x_Restriction_Recipient.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "relatedArtifact_resourceReference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "restriction_recipient_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "restriction_recipient_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "recipient_task_restriction") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "recipient_task_restriction", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -52329,46 +52003,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + if x.Restriction != nil { + if x.Restriction.Recipient != nil { + for _, item_2_x_Restriction_Recipient := range x.Restriction.Recipient { + if item_2_x_Restriction_Recipient != nil { + if item_2_x_Restriction_Recipient.Reference != nil { + refVal := *item_2_x_Restriction_Recipient.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "relatedArtifact_resourceReference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "restriction_recipient_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "restriction_recipient_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "recipient_task_restriction") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "recipient_task_restriction", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -52377,46 +52054,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + if x.Restriction != nil { + if x.Restriction.Recipient != nil { + for _, item_2_x_Restriction_Recipient := range x.Restriction.Recipient { + if item_2_x_Restriction_Recipient != nil { + if item_2_x_Restriction_Recipient.Reference != nil { + refVal := *item_2_x_Restriction_Recipient.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "relatedArtifact_resourceReference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "restriction_recipient_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "restriction_recipient_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "recipient_task_restriction") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "recipient_task_restriction", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -52425,46 +52105,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + if x.Restriction != nil { + if x.Restriction.Recipient != nil { + for _, item_2_x_Restriction_Recipient := range x.Restriction.Recipient { + if item_2_x_Restriction_Recipient != nil { + if item_2_x_Restriction_Recipient.Reference != nil { + refVal := *item_2_x_Restriction_Recipient.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "relatedArtifact_resourceReference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "restriction_recipient_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "restriction_recipient_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "recipient_task_restriction") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "recipient_task_restriction", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -52473,46 +52156,49 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference + if x.Restriction != nil { + if x.Restriction.Recipient != nil { + for _, item_2_x_Restriction_Recipient := range x.Restriction.Recipient { + if item_2_x_Restriction_Recipient != nil { + if item_2_x_Restriction_Recipient.Reference != nil { + refVal := *item_2_x_Restriction_Recipient.Reference refType, targetID, ok := splitFHIRReference(refVal) if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "relatedArtifact_resourceReference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "restriction_recipient_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "restriction_recipient_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "recipient_task_restriction") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "recipient_task_restriction", + projectJSON, + refType, + sourceType, + )) + } } } } @@ -52521,95 +52207,46 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "relatedArtifact_resourceReference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Organization" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Organization") + if seen == nil { + seen = make(map[string]struct{}, 4) } - } - } - } - } - } - } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "relatedArtifact_resourceReference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_Organization", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -52617,47 +52254,46 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "relatedArtifact_resourceReference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Group" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Group") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_Group", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -52665,47 +52301,46 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "relatedArtifact_resourceReference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Practitioner" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Practitioner") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_Practitioner", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -52713,47 +52348,46 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "relatedArtifact_resourceReference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "PractitionerRole" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_PractitionerRole") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_PractitionerRole", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -52761,47 +52395,46 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "relatedArtifact_resourceReference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchStudy" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_ResearchStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_ResearchStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -52809,47 +52442,46 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "relatedArtifact_resourceReference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Patient" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Patient") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_Patient", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -52857,47 +52489,46 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "relatedArtifact_resourceReference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ResearchSubject" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_ResearchSubject") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_ResearchSubject", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -52905,47 +52536,46 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "relatedArtifact_resourceReference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Substance" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Substance") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_Substance", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -52953,47 +52583,46 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "relatedArtifact_resourceReference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "SubstanceDefinition" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_SubstanceDefinition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_SubstanceDefinition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -53001,47 +52630,46 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "relatedArtifact_resourceReference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Specimen" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Specimen") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_Specimen", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -53049,47 +52677,46 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - if x.RelatedArtifact != nil { - for _, item_3_x_RelatedArtifact := range x.RelatedArtifact { - if item_3_x_RelatedArtifact != nil { - if item_3_x_RelatedArtifact.ResourceReference != nil { - if item_3_x_RelatedArtifact.ResourceReference.Reference != nil { - refVal := *item_3_x_RelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "relatedArtifact_resourceReference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "relatedArtifact_resourceReference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Observation" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Observation") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_Observation", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) } } } @@ -53097,1076 +52724,16 @@ func (x *ResearchStudy) ExtractEdges(project string) ([]json.RawMessage, error) } } } - return edges, nil -} - -// ExtractEdges extracts graph links from ResearchStudyAssociatedParty. -func (x *ResearchStudyAssociatedParty) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ResearchStudyAssociatedParty" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Party != nil { - if x.Party.Reference != nil { - refVal := *x.Party.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "party_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "party_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "research_study_associated_party") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("party", id), - "research_study_associated_party", - projectJSON, - sourceType, - "party", - )) - } - } - } - } - } - if x.Party != nil { - if x.Party.Reference != nil { - refVal := *x.Party.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "party_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "party_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "research_study_associated_party") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("party", id), - "research_study_associated_party", - projectJSON, - sourceType, - "party", - )) - } - } - } - } - } - if x.Party != nil { - if x.Party.Reference != nil { - refVal := *x.Party.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "party_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "party_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "research_study_associated_party") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("party", id), - "research_study_associated_party", - projectJSON, - sourceType, - "party", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from ResearchStudyComparisonGroup. -func (x *ResearchStudyComparisonGroup) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ResearchStudyComparisonGroup" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.ObservedGroup != nil { - if x.ObservedGroup.Reference != nil { - refVal := *x.ObservedGroup.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "observedGroup") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("observedGroup", targetID), - "observedGroup", - projectJSON, - sourceType, - "observedGroup", - )) - } - backrefKey := getEdgeUUID(id, targetID, "research_study_comparison_group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("group", id), - "research_study_comparison_group", - projectJSON, - sourceType, - "group", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from ResearchStudyLabel. -func (x *ResearchStudyLabel) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ResearchStudyLabel" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from ResearchStudyObjective. -func (x *ResearchStudyObjective) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ResearchStudyObjective" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from ResearchStudyOutcomeMeasure. -func (x *ResearchStudyOutcomeMeasure) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ResearchStudyOutcomeMeasure" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from ResearchStudyProgressStatus. -func (x *ResearchStudyProgressStatus) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ResearchStudyProgressStatus" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from ResearchStudyRecruitment. -func (x *ResearchStudyRecruitment) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ResearchStudyRecruitment" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.ActualGroup != nil { - if x.ActualGroup.Reference != nil { - refVal := *x.ActualGroup.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "actualGroup") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("actualGroup", targetID), - "actualGroup", - projectJSON, - sourceType, - "actualGroup", - )) - } - backrefKey := getEdgeUUID(id, targetID, "actualGroup_research_study_recruitment") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("recruitment", id), - "actualGroup_research_study_recruitment", - projectJSON, - sourceType, - "recruitment", - )) - } - } - } - } - } - if x.Eligibility != nil { - if x.Eligibility.Reference != nil { - refVal := *x.Eligibility.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "eligibility_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "eligibility_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "eligibility_research_study_recruitment") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("recruitment", id), - "eligibility_research_study_recruitment", - projectJSON, - sourceType, - "recruitment", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from ResearchSubject. -func (x *ResearchSubject) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ResearchSubject" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Study != nil { - if x.Study.Reference != nil { - refVal := *x.Study.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "study") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "study", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "research_subject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("subject", id), - "research_subject", - projectJSON, - sourceType, - "subject", - )) - } - } - } - } - } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "subject_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "subject_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "research_subject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("subject", id), - "research_subject", - projectJSON, - sourceType, - "subject", - )) - } - } - } - } - } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "subject_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "subject_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "research_subject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("subject", id), - "research_subject", - projectJSON, - sourceType, - "subject", - )) - } - } - } - } - } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "subject_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "subject_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "research_subject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("subject", id), - "research_subject", - projectJSON, - sourceType, - "subject", - )) - } - } - } - } - } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "subject_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "subject_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "research_subject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("subject", id), - "research_subject", - projectJSON, - sourceType, - "subject", - )) - } - } - } - } - } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "subject_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "subject_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "research_subject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("subject", id), - "research_subject", - projectJSON, - sourceType, - "subject", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from ResearchSubjectProgress. -func (x *ResearchSubjectProgress) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "ResearchSubjectProgress" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from Resource. -func (x *Resource) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Resource" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from SampledData. -func (x *SampledData) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "SampledData" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from Signature. -func (x *Signature) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Signature" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.OnBehalfOf != nil { - if x.OnBehalfOf.Reference != nil { - refVal := *x.OnBehalfOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "onBehalfOf_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "onBehalfOf_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "onBehalfOf_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - if x.OnBehalfOf != nil { - if x.OnBehalfOf.Reference != nil { - refVal := *x.OnBehalfOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "onBehalfOf_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "onBehalfOf_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "onBehalfOf_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - if x.OnBehalfOf != nil { - if x.OnBehalfOf.Reference != nil { - refVal := *x.OnBehalfOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "onBehalfOf_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "onBehalfOf_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "onBehalfOf_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - if x.OnBehalfOf != nil { - if x.OnBehalfOf.Reference != nil { - refVal := *x.OnBehalfOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "onBehalfOf_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "onBehalfOf_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "onBehalfOf_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - if x.Who != nil { - if x.Who.Reference != nil { - refVal := *x.Who.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "who_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "who_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "who_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "who_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - if x.Who != nil { - if x.Who.Reference != nil { - refVal := *x.Who.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "who_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "who_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "who_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "who_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - if x.Who != nil { - if x.Who.Reference != nil { - refVal := *x.Who.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "who_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "who_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "who_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "who_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - if x.Who != nil { - if x.Who.Reference != nil { - refVal := *x.Who.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "who_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "who_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "who_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "who_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from Specimen. -func (x *Specimen) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Specimen" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Parent != nil { - for _, item_2_x_Parent := range x.Parent { - if item_2_x_Parent != nil { - if item_2_x_Parent.Reference != nil { - refVal := *item_2_x_Parent.Reference - refType, targetID, ok := splitFHIRReference(refVal) + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "parent") + if refType == "DiagnosticReport" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_DiagnosticReport") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -54175,14 +52742,14 @@ func (x *Specimen) ExtractEdges(project string) ([]json.RawMessage, error) { edges = append(edges, buildEdgeRawJSON( forwardKey, collectionID(sourceType, id), - collectionID("parent", targetID), - "parent", + collectionID(refType, targetID), + "statusReason_reference_DiagnosticReport", projectJSON, sourceType, - "parent", + refType, )) } - backrefKey := getEdgeUUID(id, targetID, "parent_specimen") + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") if seen == nil { seen = make(map[string]struct{}, 4) } @@ -54190,12 +52757,12 @@ func (x *Specimen) ExtractEdges(project string) ([]json.RawMessage, error) { seen[backrefKey] = struct{}{} edges = append(edges, buildEdgeRawJSON( backrefKey, - collectionID(sourceType, targetID), - collectionID("specimen", id), - "parent_specimen", + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", projectJSON, + refType, sourceType, - "specimen", )) } } @@ -54203,25466 +52770,532 @@ func (x *Specimen) ExtractEdges(project string) ([]json.RawMessage, error) { } } } - } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "subject_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "subject_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("specimen", id), - "specimen", - projectJSON, - sourceType, - "specimen", - )) - } - } - } - } - } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "subject_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "subject_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("specimen", id), - "specimen", - projectJSON, - sourceType, - "specimen", - )) - } - } - } - } - } - if x.Subject != nil { - if x.Subject.Reference != nil { - refVal := *x.Subject.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "subject_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "subject_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("specimen", id), - "specimen", - projectJSON, - sourceType, - "specimen", - )) - } - } - } - } - } - if x.Collection != nil { - if x.Collection.Collector != nil { - if x.Collection.Collector.Reference != nil { - refVal := *x.Collection.Collector.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "collection_collector_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "collection_collector_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "specimen_collection") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("collection", id), - "specimen_collection", - projectJSON, - sourceType, - "collection", - )) - } - } - } - } - } - } - if x.Collection != nil { - if x.Collection.Collector != nil { - if x.Collection.Collector.Reference != nil { - refVal := *x.Collection.Collector.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "collection_collector_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "collection_collector_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "specimen_collection") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("collection", id), - "specimen_collection", - projectJSON, - sourceType, - "collection", - )) - } - } - } - } - } - } - if x.Collection != nil { - if x.Collection.Collector != nil { - if x.Collection.Collector.Reference != nil { - refVal := *x.Collection.Collector.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "collection_collector_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "collection_collector_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "specimen_collection") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("collection", id), - "specimen_collection", - projectJSON, - sourceType, - "collection", - )) - } - } - } - } - } - } - if x.Collection != nil { - if x.Collection.Procedure != nil { - if x.Collection.Procedure.Reference != nil { - refVal := *x.Collection.Procedure.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "collection_procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("procedure", targetID), - "collection_procedure", - projectJSON, - sourceType, - "procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "specimen_collection") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("collection", id), - "specimen_collection", - projectJSON, - sourceType, - "collection", - )) - } - } - } - } - } - } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "note_authorReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - } - } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "note_authorReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - } - } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "note_authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - } - } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "note_authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - } - } - if x.Processing != nil { - for _, item_4_x_Processing := range x.Processing { - if item_4_x_Processing != nil { - if item_4_x_Processing.Additive != nil { - for _, item_2_item_4_x_Processing_Additive := range item_4_x_Processing.Additive { - if item_2_item_4_x_Processing_Additive != nil { - if item_2_item_4_x_Processing_Additive.Reference != nil { - refVal := *item_2_item_4_x_Processing_Additive.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "processing_additive") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("additive", targetID), - "processing_additive", - projectJSON, - sourceType, - "additive", - )) - } - backrefKey := getEdgeUUID(id, targetID, "additive_specimen_processing") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("processing", id), - "additive_specimen_processing", - projectJSON, - sourceType, - "processing", - )) - } - } - } - } - } - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from SpecimenCollection. -func (x *SpecimenCollection) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "SpecimenCollection" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Collector != nil { - if x.Collector.Reference != nil { - refVal := *x.Collector.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "collector_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "collector_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "specimen_collection") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("collection", id), - "specimen_collection", - projectJSON, - sourceType, - "collection", - )) - } - } - } - } - } - if x.Collector != nil { - if x.Collector.Reference != nil { - refVal := *x.Collector.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "collector_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "collector_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "specimen_collection") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("collection", id), - "specimen_collection", - projectJSON, - sourceType, - "collection", - )) - } - } - } - } - } - if x.Collector != nil { - if x.Collector.Reference != nil { - refVal := *x.Collector.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "collector_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "collector_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "specimen_collection") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("collection", id), - "specimen_collection", - projectJSON, - sourceType, - "collection", - )) - } - } - } - } - } - if x.Procedure != nil { - if x.Procedure.Reference != nil { - refVal := *x.Procedure.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("procedure", targetID), - "procedure", - projectJSON, - sourceType, - "procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "specimen_collection") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("collection", id), - "specimen_collection", - projectJSON, - sourceType, - "collection", - )) - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "bodySite_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "bodySite_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "bodySite_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "bodySite_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "bodySite_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "bodySite_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "bodySite_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "bodySite_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "bodySite_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "bodySite_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "bodySite_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "bodySite_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "bodySite_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "bodySite_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "bodySite_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "bodySite_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "bodySite_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "bodySite_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "bodySite_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "bodySite_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "bodySite_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "bodySite_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.BodySite != nil { - if x.BodySite.Reference != nil { - if x.BodySite.Reference.Reference != nil { - refVal := *x.BodySite.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "bodySite_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "bodySite_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "device_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "device_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "device_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "device_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "device_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "device_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "device_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "device_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "device_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "device_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "device_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "device_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "device_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "device_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "device_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "device_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "device_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "device_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "device_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "device_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "device_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "device_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Device != nil { - if x.Device.Reference != nil { - if x.Device.Reference.Reference != nil { - refVal := *x.Device.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "device_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "device_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from SpecimenContainer. -func (x *SpecimenContainer) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "SpecimenContainer" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from SpecimenFeature. -func (x *SpecimenFeature) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "SpecimenFeature" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from SpecimenProcessing. -func (x *SpecimenProcessing) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "SpecimenProcessing" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Additive != nil { - for _, item_2_x_Additive := range x.Additive { - if item_2_x_Additive != nil { - if item_2_x_Additive.Reference != nil { - refVal := *item_2_x_Additive.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "additive") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("additive", targetID), - "additive", - projectJSON, - sourceType, - "additive", - )) - } - backrefKey := getEdgeUUID(id, targetID, "additive_specimen_processing") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("processing", id), - "additive_specimen_processing", - projectJSON, - sourceType, - "processing", - )) - } - } - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from Substance. -func (x *Substance) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Substance" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "code_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "code_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "code_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "code_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "code_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "code_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "code_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "code_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "code_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "code_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "code_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "code_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "code_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "code_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "code_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "code_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "code_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "code_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "code_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "code_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "code_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "code_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Code != nil { - if x.Code.Reference != nil { - if x.Code.Reference.Reference != nil { - refVal := *x.Code.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "code_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "code_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.Ingredient != nil { - for _, item_3_x_Ingredient := range x.Ingredient { - if item_3_x_Ingredient != nil { - if item_3_x_Ingredient.SubstanceReference != nil { - if item_3_x_Ingredient.SubstanceReference.Reference != nil { - refVal := *item_3_x_Ingredient.SubstanceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "ingredient_substanceReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("substanceReference", targetID), - "ingredient_substanceReference", - projectJSON, - sourceType, - "substanceReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "substance_ingredient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("ingredient", id), - "substance_ingredient", - projectJSON, - sourceType, - "ingredient", - )) - } - } - } - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from SubstanceDefinition. -func (x *SubstanceDefinition) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "SubstanceDefinition" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Manufacturer != nil { - for _, item_2_x_Manufacturer := range x.Manufacturer { - if item_2_x_Manufacturer != nil { - if item_2_x_Manufacturer.Reference != nil { - refVal := *item_2_x_Manufacturer.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "manufacturer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("manufacturer", targetID), - "manufacturer", - projectJSON, - sourceType, - "manufacturer", - )) - } - backrefKey := getEdgeUUID(id, targetID, "manufacturer_substance_definition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("definition", id), - "manufacturer_substance_definition", - projectJSON, - sourceType, - "definition", - )) - } - } - } - } - } - } - } - if x.Supplier != nil { - for _, item_2_x_Supplier := range x.Supplier { - if item_2_x_Supplier != nil { - if item_2_x_Supplier.Reference != nil { - refVal := *item_2_x_Supplier.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "supplier") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("supplier", targetID), - "supplier", - projectJSON, - sourceType, - "supplier", - )) - } - backrefKey := getEdgeUUID(id, targetID, "supplier_substance_definition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("definition", id), - "supplier_substance_definition", - projectJSON, - sourceType, - "definition", - )) - } - } - } - } - } - } - } - if x.Code != nil { - for _, item_4_x_Code := range x.Code { - if item_4_x_Code != nil { - if item_4_x_Code.Source != nil { - for _, item_2_item_4_x_Code_Source := range item_4_x_Code.Source { - if item_2_item_4_x_Code_Source != nil { - if item_2_item_4_x_Code_Source.Reference != nil { - refVal := *item_2_item_4_x_Code_Source.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "code_source") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("source", targetID), - "code_source", - projectJSON, - sourceType, - "source", - )) - } - backrefKey := getEdgeUUID(id, targetID, "source_substance_definition_code") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("code", id), - "source_substance_definition_code", - projectJSON, - sourceType, - "code", - )) - } - } - } - } - } - } - } - } - } - } - if x.Name != nil { - for _, item_4_x_Name := range x.Name { - if item_4_x_Name != nil { - if item_4_x_Name.Source != nil { - for _, item_2_item_4_x_Name_Source := range item_4_x_Name.Source { - if item_2_item_4_x_Name_Source != nil { - if item_2_item_4_x_Name_Source.Reference != nil { - refVal := *item_2_item_4_x_Name_Source.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "name_source") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("source", targetID), - "name_source", - projectJSON, - sourceType, - "source", - )) - } - backrefKey := getEdgeUUID(id, targetID, "source_substance_definition_name") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("name", id), - "source_substance_definition_name", - projectJSON, - sourceType, - "name", - )) - } - } - } - } - } - } - } - } - } - } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "note_authorReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - } - } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "note_authorReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - } - } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "note_authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - } - } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "note_authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - } - } - if x.Relationship != nil { - for _, item_4_x_Relationship := range x.Relationship { - if item_4_x_Relationship != nil { - if item_4_x_Relationship.Source != nil { - for _, item_2_item_4_x_Relationship_Source := range item_4_x_Relationship.Source { - if item_2_item_4_x_Relationship_Source != nil { - if item_2_item_4_x_Relationship_Source.Reference != nil { - refVal := *item_2_item_4_x_Relationship_Source.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "relationship_source") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("source", targetID), - "relationship_source", - projectJSON, - sourceType, - "source", - )) - } - backrefKey := getEdgeUUID(id, targetID, "source_substance_definition_relationship") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("relationship", id), - "source_substance_definition_relationship", - projectJSON, - sourceType, - "relationship", - )) - } - } - } - } - } - } - } - } - } - } - if x.Relationship != nil { - for _, item_3_x_Relationship := range x.Relationship { - if item_3_x_Relationship != nil { - if item_3_x_Relationship.SubstanceDefinitionReference != nil { - if item_3_x_Relationship.SubstanceDefinitionReference.Reference != nil { - refVal := *item_3_x_Relationship.SubstanceDefinitionReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "relationship_substanceDefinitionReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("substanceDefinitionReference", targetID), - "relationship_substanceDefinitionReference", - projectJSON, - sourceType, - "substanceDefinitionReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "substance_definition_relationship") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("relationship", id), - "substance_definition_relationship", - projectJSON, - sourceType, - "relationship", - )) - } - } - } - } - } - } - } - } - if x.Structure != nil { - if x.Structure.SourceDocument != nil { - for _, item_2_x_Structure_SourceDocument := range x.Structure.SourceDocument { - if item_2_x_Structure_SourceDocument != nil { - if item_2_x_Structure_SourceDocument.Reference != nil { - refVal := *item_2_x_Structure_SourceDocument.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "structure_sourceDocument") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("sourceDocument", targetID), - "structure_sourceDocument", - projectJSON, - sourceType, - "sourceDocument", - )) - } - backrefKey := getEdgeUUID(id, targetID, "sourceDocument_substance_definition_structure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("structure", id), - "sourceDocument_substance_definition_structure", - projectJSON, - sourceType, - "structure", - )) - } - } - } - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from SubstanceDefinitionCharacterization. -func (x *SubstanceDefinitionCharacterization) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "SubstanceDefinitionCharacterization" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from SubstanceDefinitionCode. -func (x *SubstanceDefinitionCode) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "SubstanceDefinitionCode" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Source != nil { - for _, item_2_x_Source := range x.Source { - if item_2_x_Source != nil { - if item_2_x_Source.Reference != nil { - refVal := *item_2_x_Source.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "source") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("source", targetID), - "source", - projectJSON, - sourceType, - "source", - )) - } - backrefKey := getEdgeUUID(id, targetID, "source_substance_definition_code") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("code", id), - "source_substance_definition_code", - projectJSON, - sourceType, - "code", - )) - } - } - } - } - } - } - } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "note_authorReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - } - } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "note_authorReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - } - } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "note_authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - } - } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "note_authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from SubstanceDefinitionMoiety. -func (x *SubstanceDefinitionMoiety) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "SubstanceDefinitionMoiety" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from SubstanceDefinitionMolecularWeight. -func (x *SubstanceDefinitionMolecularWeight) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "SubstanceDefinitionMolecularWeight" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from SubstanceDefinitionName. -func (x *SubstanceDefinitionName) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "SubstanceDefinitionName" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Source != nil { - for _, item_2_x_Source := range x.Source { - if item_2_x_Source != nil { - if item_2_x_Source.Reference != nil { - refVal := *item_2_x_Source.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "source") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("source", targetID), - "source", - projectJSON, - sourceType, - "source", - )) - } - backrefKey := getEdgeUUID(id, targetID, "source_substance_definition_name") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("name", id), - "source_substance_definition_name", - projectJSON, - sourceType, - "name", - )) - } - } - } - } - } - } - } - if x.Synonym != nil { - for _, item_4_x_Synonym := range x.Synonym { - if item_4_x_Synonym != nil { - if item_4_x_Synonym.Source != nil { - for _, item_2_item_4_x_Synonym_Source := range item_4_x_Synonym.Source { - if item_2_item_4_x_Synonym_Source != nil { - if item_2_item_4_x_Synonym_Source.Reference != nil { - refVal := *item_2_item_4_x_Synonym_Source.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "synonym_source") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("source", targetID), - "synonym_source", - projectJSON, - sourceType, - "source", - )) - } - backrefKey := getEdgeUUID(id, targetID, "source_substance_definition_name") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("name", id), - "source_substance_definition_name", - projectJSON, - sourceType, - "name", - )) - } - } - } - } - } - } - } - } - } - } - if x.Translation != nil { - for _, item_4_x_Translation := range x.Translation { - if item_4_x_Translation != nil { - if item_4_x_Translation.Source != nil { - for _, item_2_item_4_x_Translation_Source := range item_4_x_Translation.Source { - if item_2_item_4_x_Translation_Source != nil { - if item_2_item_4_x_Translation_Source.Reference != nil { - refVal := *item_2_item_4_x_Translation_Source.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "translation_source") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("source", targetID), - "translation_source", - projectJSON, - sourceType, - "source", - )) - } - backrefKey := getEdgeUUID(id, targetID, "source_substance_definition_name") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("name", id), - "source_substance_definition_name", - projectJSON, - sourceType, - "name", - )) - } - } - } - } - } - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from SubstanceDefinitionNameOfficial. -func (x *SubstanceDefinitionNameOfficial) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "SubstanceDefinitionNameOfficial" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from SubstanceDefinitionProperty. -func (x *SubstanceDefinitionProperty) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "SubstanceDefinitionProperty" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from SubstanceDefinitionRelationship. -func (x *SubstanceDefinitionRelationship) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "SubstanceDefinitionRelationship" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Source != nil { - for _, item_2_x_Source := range x.Source { - if item_2_x_Source != nil { - if item_2_x_Source.Reference != nil { - refVal := *item_2_x_Source.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "source") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("source", targetID), - "source", - projectJSON, - sourceType, - "source", - )) - } - backrefKey := getEdgeUUID(id, targetID, "source_substance_definition_relationship") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("relationship", id), - "source_substance_definition_relationship", - projectJSON, - sourceType, - "relationship", - )) - } - } - } - } - } - } - } - if x.SubstanceDefinitionReference != nil { - if x.SubstanceDefinitionReference.Reference != nil { - refVal := *x.SubstanceDefinitionReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "substanceDefinitionReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("substanceDefinitionReference", targetID), - "substanceDefinitionReference", - projectJSON, - sourceType, - "substanceDefinitionReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "substance_definition_relationship") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("relationship", id), - "substance_definition_relationship", - projectJSON, - sourceType, - "relationship", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from SubstanceDefinitionSourceMaterial. -func (x *SubstanceDefinitionSourceMaterial) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "SubstanceDefinitionSourceMaterial" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from SubstanceDefinitionStructure. -func (x *SubstanceDefinitionStructure) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "SubstanceDefinitionStructure" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.SourceDocument != nil { - for _, item_2_x_SourceDocument := range x.SourceDocument { - if item_2_x_SourceDocument != nil { - if item_2_x_SourceDocument.Reference != nil { - refVal := *item_2_x_SourceDocument.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "sourceDocument") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("sourceDocument", targetID), - "sourceDocument", - projectJSON, - sourceType, - "sourceDocument", - )) - } - backrefKey := getEdgeUUID(id, targetID, "sourceDocument_substance_definition_structure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("structure", id), - "sourceDocument_substance_definition_structure", - projectJSON, - sourceType, - "structure", - )) - } - } - } - } - } - } - } - if x.Representation != nil { - for _, item_3_x_Representation := range x.Representation { - if item_3_x_Representation != nil { - if item_3_x_Representation.Document != nil { - if item_3_x_Representation.Document.Reference != nil { - refVal := *item_3_x_Representation.Document.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "representation_document") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("document", targetID), - "representation_document", - projectJSON, - sourceType, - "document", - )) - } - backrefKey := getEdgeUUID(id, targetID, "substance_definition_structure_representation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("representation", id), - "substance_definition_structure_representation", - projectJSON, - sourceType, - "representation", - )) - } - } - } - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from SubstanceDefinitionStructureRepresentation. -func (x *SubstanceDefinitionStructureRepresentation) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "SubstanceDefinitionStructureRepresentation" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Document != nil { - if x.Document.Reference != nil { - refVal := *x.Document.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "document") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("document", targetID), - "document", - projectJSON, - sourceType, - "document", - )) - } - backrefKey := getEdgeUUID(id, targetID, "substance_definition_structure_representation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("representation", id), - "substance_definition_structure_representation", - projectJSON, - sourceType, - "representation", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from SubstanceIngredient. -func (x *SubstanceIngredient) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "SubstanceIngredient" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.SubstanceReference != nil { - if x.SubstanceReference.Reference != nil { - refVal := *x.SubstanceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "substanceReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("substanceReference", targetID), - "substanceReference", - projectJSON, - sourceType, - "substanceReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "substance_ingredient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("ingredient", id), - "substance_ingredient", - projectJSON, - sourceType, - "ingredient", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from Task. -func (x *Task) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Task" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "basedOn_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "basedOn_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "basedOn_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "basedOn_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "basedOn_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "basedOn_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "basedOn_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "basedOn_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "basedOn_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "basedOn_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "basedOn_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "basedOn_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "basedOn_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "basedOn_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "basedOn_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "basedOn_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "basedOn_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "basedOn_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "basedOn_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "basedOn_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "basedOn_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "basedOn_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.BasedOn != nil { - for _, item_2_x_BasedOn := range x.BasedOn { - if item_2_x_BasedOn != nil { - if item_2_x_BasedOn.Reference != nil { - refVal := *item_2_x_BasedOn.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "basedOn_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "basedOn_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "basedOn_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "basedOn_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "focus_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "focus_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "focus_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "focus_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "focus_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "focus_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "focus_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "focus_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "focus_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "focus_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "focus_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "focus_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "focus_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "focus_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "focus_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "focus_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "focus_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "focus_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "focus_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "focus_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "focus_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "focus_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "focus_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "focus_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "focus_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "focus_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "focus_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "focus_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "focus_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "focus_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "focus_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "focus_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "focus_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "focus_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "focus_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "focus_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "focus_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "focus_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "focus_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "focus_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "focus_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "focus_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "focus_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "focus_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Focus != nil { - if x.Focus.Reference != nil { - refVal := *x.Focus.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "focus_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "focus_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "focus_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "focus_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "for_fhir_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "for_fhir_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "for_fhir_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "for_fhir_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "for_fhir_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "for_fhir_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "for_fhir_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "for_fhir_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "for_fhir_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "for_fhir_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "for_fhir_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "for_fhir_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "for_fhir_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "for_fhir_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "for_fhir_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "for_fhir_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "for_fhir_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "for_fhir_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "for_fhir_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "for_fhir_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "for_fhir_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "for_fhir_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.ForFhir != nil { - if x.ForFhir.Reference != nil { - refVal := *x.ForFhir.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "for_fhir_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "for_fhir_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "for_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "for_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Owner != nil { - if x.Owner.Reference != nil { - refVal := *x.Owner.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "owner_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "owner_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "owner_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "owner_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Owner != nil { - if x.Owner.Reference != nil { - refVal := *x.Owner.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "owner_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "owner_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "owner_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "owner_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Owner != nil { - if x.Owner.Reference != nil { - refVal := *x.Owner.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "owner_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "owner_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "owner_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "owner_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Owner != nil { - if x.Owner.Reference != nil { - refVal := *x.Owner.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "owner_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "owner_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "owner_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "owner_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.PartOf != nil { - for _, item_2_x_PartOf := range x.PartOf { - if item_2_x_PartOf != nil { - if item_2_x_PartOf.Reference != nil { - refVal := *item_2_x_PartOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "partOf") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("partOf", targetID), - "partOf", - projectJSON, - sourceType, - "partOf", - )) - } - backrefKey := getEdgeUUID(id, targetID, "partOf_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "partOf_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - } - } - if x.Requester != nil { - if x.Requester.Reference != nil { - refVal := *x.Requester.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "requester_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "requester_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "requester_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "requester_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Requester != nil { - if x.Requester.Reference != nil { - refVal := *x.Requester.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "requester_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "requester_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "requester_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "requester_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Requester != nil { - if x.Requester.Reference != nil { - refVal := *x.Requester.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "requester_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "requester_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "requester_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "requester_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Requester != nil { - if x.Requester.Reference != nil { - refVal := *x.Requester.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "requester_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "requester_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "requester_task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("task", id), - "requester_task", - projectJSON, - sourceType, - "task", - )) - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "input_valueReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "input_valueReference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "input_valueReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "input_valueReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "input_valueReference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "input_valueReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "input_valueReference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "input_valueReference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "input_valueReference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "input_valueReference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "input_valueReference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "input_valueReference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "input_valueReference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "input_valueReference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "input_valueReference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "input_valueReference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "input_valueReference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "input_valueReference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "input_valueReference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "input_valueReference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "input_valueReference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "input_valueReference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Input != nil { - for _, item_3_x_Input := range x.Input { - if item_3_x_Input != nil { - if item_3_x_Input.ValueReference != nil { - if item_3_x_Input.ValueReference.Reference != nil { - refVal := *item_3_x_Input.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "input_valueReference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "input_valueReference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - } - } - } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "note_authorReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - } - } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "note_authorReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - } - } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "note_authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - } - } - if x.Note != nil { - for _, item_3_x_Note := range x.Note { - if item_3_x_Note != nil { - if item_3_x_Note.AuthorReference != nil { - if item_3_x_Note.AuthorReference.Reference != nil { - refVal := *item_3_x_Note.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "note_authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "note_authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "output_valueReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "output_valueReference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "output_valueReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "output_valueReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "output_valueReference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "output_valueReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "output_valueReference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "output_valueReference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "output_valueReference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "output_valueReference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "output_valueReference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "output_valueReference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "output_valueReference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "output_valueReference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "output_valueReference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "output_valueReference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "output_valueReference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "output_valueReference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "output_valueReference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "output_valueReference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "output_valueReference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "output_valueReference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Output != nil { - for _, item_3_x_Output := range x.Output { - if item_3_x_Output != nil { - if item_3_x_Output.ValueReference != nil { - if item_3_x_Output.ValueReference.Reference != nil { - refVal := *item_3_x_Output.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "output_valueReference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "output_valueReference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - } - } - } - if x.Performer != nil { - for _, item_3_x_Performer := range x.Performer { - if item_3_x_Performer != nil { - if item_3_x_Performer.Actor != nil { - if item_3_x_Performer.Actor.Reference != nil { - refVal := *item_3_x_Performer.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "performer_actor_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "performer_actor_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "task_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - } - } - } - if x.Performer != nil { - for _, item_3_x_Performer := range x.Performer { - if item_3_x_Performer != nil { - if item_3_x_Performer.Actor != nil { - if item_3_x_Performer.Actor.Reference != nil { - refVal := *item_3_x_Performer.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "performer_actor_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "performer_actor_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "task_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - } - } - } - if x.Performer != nil { - for _, item_3_x_Performer := range x.Performer { - if item_3_x_Performer != nil { - if item_3_x_Performer.Actor != nil { - if item_3_x_Performer.Actor.Reference != nil { - refVal := *item_3_x_Performer.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "performer_actor_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "performer_actor_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "task_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - } - } - } - if x.Performer != nil { - for _, item_3_x_Performer := range x.Performer { - if item_3_x_Performer != nil { - if item_3_x_Performer.Actor != nil { - if item_3_x_Performer.Actor.Reference != nil { - refVal := *item_3_x_Performer.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "performer_actor_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "performer_actor_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "task_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "reason_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "reason_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "reason_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "reason_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "reason_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "reason_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "reason_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "reason_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "reason_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "reason_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "reason_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "reason_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "reason_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "reason_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "reason_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "reason_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "reason_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "reason_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "reason_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "reason_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "reason_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "reason_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Reason != nil { - for _, item_3_x_Reason := range x.Reason { - if item_3_x_Reason != nil { - if item_3_x_Reason.Reference != nil { - if item_3_x_Reason.Reference.Reference != nil { - refVal := *item_3_x_Reason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "reason_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "reason_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "requestedPerformer_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "requestedPerformer_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "requestedPerformer_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "requestedPerformer_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "requestedPerformer_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "requestedPerformer_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "requestedPerformer_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "requestedPerformer_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "requestedPerformer_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "requestedPerformer_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "requestedPerformer_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "requestedPerformer_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "requestedPerformer_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "requestedPerformer_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "requestedPerformer_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "requestedPerformer_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "requestedPerformer_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "requestedPerformer_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "requestedPerformer_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "requestedPerformer_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "requestedPerformer_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "requestedPerformer_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.RequestedPerformer != nil { - for _, item_3_x_RequestedPerformer := range x.RequestedPerformer { - if item_3_x_RequestedPerformer != nil { - if item_3_x_RequestedPerformer.Reference != nil { - if item_3_x_RequestedPerformer.Reference.Reference != nil { - refVal := *item_3_x_RequestedPerformer.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "requestedPerformer_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "requestedPerformer_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - } - } - if x.Restriction != nil { - if x.Restriction.Recipient != nil { - for _, item_2_x_Restriction_Recipient := range x.Restriction.Recipient { - if item_2_x_Restriction_Recipient != nil { - if item_2_x_Restriction_Recipient.Reference != nil { - refVal := *item_2_x_Restriction_Recipient.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "restriction_recipient_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "restriction_recipient_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "recipient_task_restriction") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("restriction", id), - "recipient_task_restriction", - projectJSON, - sourceType, - "restriction", - )) - } - } - } - } - } - } - } - } - if x.Restriction != nil { - if x.Restriction.Recipient != nil { - for _, item_2_x_Restriction_Recipient := range x.Restriction.Recipient { - if item_2_x_Restriction_Recipient != nil { - if item_2_x_Restriction_Recipient.Reference != nil { - refVal := *item_2_x_Restriction_Recipient.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "restriction_recipient_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "restriction_recipient_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "recipient_task_restriction") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("restriction", id), - "recipient_task_restriction", - projectJSON, - sourceType, - "restriction", - )) - } - } - } - } - } - } - } - } - if x.Restriction != nil { - if x.Restriction.Recipient != nil { - for _, item_2_x_Restriction_Recipient := range x.Restriction.Recipient { - if item_2_x_Restriction_Recipient != nil { - if item_2_x_Restriction_Recipient.Reference != nil { - refVal := *item_2_x_Restriction_Recipient.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "restriction_recipient_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "restriction_recipient_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "recipient_task_restriction") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("restriction", id), - "recipient_task_restriction", - projectJSON, - sourceType, - "restriction", - )) - } - } - } - } - } - } - } - } - if x.Restriction != nil { - if x.Restriction.Recipient != nil { - for _, item_2_x_Restriction_Recipient := range x.Restriction.Recipient { - if item_2_x_Restriction_Recipient != nil { - if item_2_x_Restriction_Recipient.Reference != nil { - refVal := *item_2_x_Restriction_Recipient.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "restriction_recipient_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "restriction_recipient_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "recipient_task_restriction") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("restriction", id), - "recipient_task_restriction", - projectJSON, - sourceType, - "restriction", - )) - } - } - } - } - } - } - } - } - if x.Restriction != nil { - if x.Restriction.Recipient != nil { - for _, item_2_x_Restriction_Recipient := range x.Restriction.Recipient { - if item_2_x_Restriction_Recipient != nil { - if item_2_x_Restriction_Recipient.Reference != nil { - refVal := *item_2_x_Restriction_Recipient.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "restriction_recipient_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "restriction_recipient_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "recipient_task_restriction") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("restriction", id), - "recipient_task_restriction", - projectJSON, - sourceType, - "restriction", - )) - } - } - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "statusReason_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "statusReason_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "statusReason_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "statusReason_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "statusReason_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "statusReason_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "statusReason_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "statusReason_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "statusReason_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "statusReason_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "statusReason_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "statusReason_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "statusReason_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "statusReason_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "statusReason_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "statusReason_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "statusReason_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "statusReason_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "statusReason_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "statusReason_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "statusReason_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "statusReason_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.StatusReason != nil { - if x.StatusReason.Reference != nil { - if x.StatusReason.Reference.Reference != nil { - refVal := *x.StatusReason.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "statusReason_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from TaskInput. -func (x *TaskInput) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "TaskInput" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "valueReference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "valueReference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "valueReference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "valueReference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "valueReference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "valueReference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "valueReference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "valueReference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "valueReference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "valueReference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "valueReference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "valueReference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "valueReference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "valueReference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "valueReference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "valueReference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "valueReference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "valueReference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "valueReference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_input") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("input", id), - "task_input", - projectJSON, - sourceType, - "input", - )) - } - } - } - } - } - if x.ValueAnnotation != nil { - if x.ValueAnnotation.AuthorReference != nil { - if x.ValueAnnotation.AuthorReference.Reference != nil { - refVal := *x.ValueAnnotation.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueAnnotation_authorReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueAnnotation_authorReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - if x.ValueAnnotation != nil { - if x.ValueAnnotation.AuthorReference != nil { - if x.ValueAnnotation.AuthorReference.Reference != nil { - refVal := *x.ValueAnnotation.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueAnnotation_authorReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueAnnotation_authorReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - if x.ValueAnnotation != nil { - if x.ValueAnnotation.AuthorReference != nil { - if x.ValueAnnotation.AuthorReference.Reference != nil { - refVal := *x.ValueAnnotation.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueAnnotation_authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueAnnotation_authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - if x.ValueAnnotation != nil { - if x.ValueAnnotation.AuthorReference != nil { - if x.ValueAnnotation.AuthorReference.Reference != nil { - refVal := *x.ValueAnnotation.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueAnnotation_authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueAnnotation_authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueCodeableReference_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "valueCodeableReference_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueCodeableReference_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueCodeableReference_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "valueCodeableReference_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueCodeableReference_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "valueCodeableReference_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "valueCodeableReference_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "valueCodeableReference_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "valueCodeableReference_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "valueCodeableReference_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "valueCodeableReference_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "valueCodeableReference_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "valueCodeableReference_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "valueCodeableReference_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "valueCodeableReference_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "valueCodeableReference_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "valueCodeableReference_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "valueCodeableReference_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "valueCodeableReference_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "valueCodeableReference_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "valueCodeableReference_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "valueCodeableReference_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueDataRequirement != nil { - if x.ValueDataRequirement.SubjectReference != nil { - if x.ValueDataRequirement.SubjectReference.Reference != nil { - refVal := *x.ValueDataRequirement.SubjectReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "valueDataRequirement_subjectReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("subjectReference", targetID), - "valueDataRequirement_subjectReference", - projectJSON, - sourceType, - "subjectReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "data_requirement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("requirement", id), - "data_requirement", - projectJSON, - sourceType, - "requirement", - )) - } - } - } - } - } - } - if x.ValueExtendedContactDetail != nil { - if x.ValueExtendedContactDetail.Organization != nil { - if x.ValueExtendedContactDetail.Organization.Reference != nil { - refVal := *x.ValueExtendedContactDetail.Organization.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueExtendedContactDetail_organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("organization", targetID), - "valueExtendedContactDetail_organization", - projectJSON, - sourceType, - "organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extended_contact_detail") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("detail", id), - "extended_contact_detail", - projectJSON, - sourceType, - "detail", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueRelatedArtifact_resourceReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "valueRelatedArtifact_resourceReference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueRelatedArtifact_resourceReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueRelatedArtifact_resourceReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "valueRelatedArtifact_resourceReference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueRelatedArtifact_resourceReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "valueRelatedArtifact_resourceReference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "valueRelatedArtifact_resourceReference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "valueRelatedArtifact_resourceReference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "valueRelatedArtifact_resourceReference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "valueRelatedArtifact_resourceReference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "valueRelatedArtifact_resourceReference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "valueRelatedArtifact_resourceReference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "valueRelatedArtifact_resourceReference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "valueRelatedArtifact_resourceReference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "valueRelatedArtifact_resourceReference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "valueRelatedArtifact_resourceReference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "valueRelatedArtifact_resourceReference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "valueRelatedArtifact_resourceReference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "valueRelatedArtifact_resourceReference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "valueRelatedArtifact_resourceReference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "valueRelatedArtifact_resourceReference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "valueRelatedArtifact_resourceReference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.OnBehalfOf != nil { - if x.ValueSignature.OnBehalfOf.Reference != nil { - refVal := *x.ValueSignature.OnBehalfOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_onBehalfOf_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueSignature_onBehalfOf_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "onBehalfOf_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.OnBehalfOf != nil { - if x.ValueSignature.OnBehalfOf.Reference != nil { - refVal := *x.ValueSignature.OnBehalfOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_onBehalfOf_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueSignature_onBehalfOf_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "onBehalfOf_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.OnBehalfOf != nil { - if x.ValueSignature.OnBehalfOf.Reference != nil { - refVal := *x.ValueSignature.OnBehalfOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_onBehalfOf_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueSignature_onBehalfOf_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "onBehalfOf_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.OnBehalfOf != nil { - if x.ValueSignature.OnBehalfOf.Reference != nil { - refVal := *x.ValueSignature.OnBehalfOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_onBehalfOf_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueSignature_onBehalfOf_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "onBehalfOf_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.Who != nil { - if x.ValueSignature.Who.Reference != nil { - refVal := *x.ValueSignature.Who.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_who_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueSignature_who_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "who_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "who_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.Who != nil { - if x.ValueSignature.Who.Reference != nil { - refVal := *x.ValueSignature.Who.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_who_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueSignature_who_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "who_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "who_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.Who != nil { - if x.ValueSignature.Who.Reference != nil { - refVal := *x.ValueSignature.Who.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_who_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueSignature_who_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "who_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "who_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.Who != nil { - if x.ValueSignature.Who.Reference != nil { - refVal := *x.ValueSignature.Who.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_who_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueSignature_who_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "who_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "who_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueUsageContext != nil { - if x.ValueUsageContext.ValueReference != nil { - if x.ValueUsageContext.ValueReference.Reference != nil { - refVal := *x.ValueUsageContext.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueUsageContext_valueReference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "valueUsageContext_valueReference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "usage_context") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("context", id), - "usage_context", - projectJSON, - sourceType, - "context", - )) - } - } - } - } - } - } - if x.ValueUsageContext != nil { - if x.ValueUsageContext.ValueReference != nil { - if x.ValueUsageContext.ValueReference.Reference != nil { - refVal := *x.ValueUsageContext.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "valueUsageContext_valueReference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "valueUsageContext_valueReference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "usage_context") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("context", id), - "usage_context", - projectJSON, - sourceType, - "context", - )) - } - } - } - } - } - } - if x.ValueUsageContext != nil { - if x.ValueUsageContext.ValueReference != nil { - if x.ValueUsageContext.ValueReference.Reference != nil { - refVal := *x.ValueUsageContext.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueUsageContext_valueReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueUsageContext_valueReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "usage_context") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("context", id), - "usage_context", - projectJSON, - sourceType, - "context", - )) - } - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from TaskOutput. -func (x *TaskOutput) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "TaskOutput" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "valueReference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "valueReference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "valueReference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "valueReference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "valueReference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "valueReference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "valueReference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "valueReference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "valueReference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "valueReference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "valueReference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "valueReference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "valueReference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "valueReference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "valueReference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "valueReference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "valueReference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "valueReference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "valueReference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_output") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("output", id), - "task_output", - projectJSON, - sourceType, - "output", - )) - } - } - } - } - } - if x.ValueAnnotation != nil { - if x.ValueAnnotation.AuthorReference != nil { - if x.ValueAnnotation.AuthorReference.Reference != nil { - refVal := *x.ValueAnnotation.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueAnnotation_authorReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueAnnotation_authorReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - if x.ValueAnnotation != nil { - if x.ValueAnnotation.AuthorReference != nil { - if x.ValueAnnotation.AuthorReference.Reference != nil { - refVal := *x.ValueAnnotation.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueAnnotation_authorReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueAnnotation_authorReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - if x.ValueAnnotation != nil { - if x.ValueAnnotation.AuthorReference != nil { - if x.ValueAnnotation.AuthorReference.Reference != nil { - refVal := *x.ValueAnnotation.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueAnnotation_authorReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueAnnotation_authorReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - if x.ValueAnnotation != nil { - if x.ValueAnnotation.AuthorReference != nil { - if x.ValueAnnotation.AuthorReference.Reference != nil { - refVal := *x.ValueAnnotation.AuthorReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueAnnotation_authorReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueAnnotation_authorReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "annotation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("annotation", id), - "annotation", - projectJSON, - sourceType, - "annotation", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueCodeableReference_reference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "valueCodeableReference_reference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueCodeableReference_reference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueCodeableReference_reference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "valueCodeableReference_reference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueCodeableReference_reference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "valueCodeableReference_reference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "valueCodeableReference_reference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "valueCodeableReference_reference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "valueCodeableReference_reference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "valueCodeableReference_reference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "valueCodeableReference_reference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "valueCodeableReference_reference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "valueCodeableReference_reference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "valueCodeableReference_reference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "valueCodeableReference_reference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "valueCodeableReference_reference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "valueCodeableReference_reference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "valueCodeableReference_reference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "valueCodeableReference_reference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "valueCodeableReference_reference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "valueCodeableReference_reference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueCodeableReference != nil { - if x.ValueCodeableReference.Reference != nil { - if x.ValueCodeableReference.Reference.Reference != nil { - refVal := *x.ValueCodeableReference.Reference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "valueCodeableReference_reference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "valueCodeableReference_reference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "codeable_reference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("reference", id), - "codeable_reference", - projectJSON, - sourceType, - "reference", - )) - } - } - } - } - } - } - if x.ValueDataRequirement != nil { - if x.ValueDataRequirement.SubjectReference != nil { - if x.ValueDataRequirement.SubjectReference.Reference != nil { - refVal := *x.ValueDataRequirement.SubjectReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "valueDataRequirement_subjectReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("subjectReference", targetID), - "valueDataRequirement_subjectReference", - projectJSON, - sourceType, - "subjectReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "data_requirement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("requirement", id), - "data_requirement", - projectJSON, - sourceType, - "requirement", - )) - } - } - } - } - } - } - if x.ValueExtendedContactDetail != nil { - if x.ValueExtendedContactDetail.Organization != nil { - if x.ValueExtendedContactDetail.Organization.Reference != nil { - refVal := *x.ValueExtendedContactDetail.Organization.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueExtendedContactDetail_organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("organization", targetID), - "valueExtendedContactDetail_organization", - projectJSON, - sourceType, - "organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "extended_contact_detail") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("detail", id), - "extended_contact_detail", - projectJSON, - sourceType, - "detail", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueRelatedArtifact_resourceReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "valueRelatedArtifact_resourceReference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueRelatedArtifact_resourceReference_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueRelatedArtifact_resourceReference_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "valueRelatedArtifact_resourceReference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueRelatedArtifact_resourceReference_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchSubject" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_ResearchSubject") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchSubject", targetID), - "valueRelatedArtifact_resourceReference_ResearchSubject", - projectJSON, - sourceType, - "ResearchSubject", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Substance" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Substance") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Substance", targetID), - "valueRelatedArtifact_resourceReference_Substance", - projectJSON, - sourceType, - "Substance", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "SubstanceDefinition" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_SubstanceDefinition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("SubstanceDefinition", targetID), - "valueRelatedArtifact_resourceReference_SubstanceDefinition", - projectJSON, - sourceType, - "SubstanceDefinition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Specimen" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Specimen") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Specimen", targetID), - "valueRelatedArtifact_resourceReference_Specimen", - projectJSON, - sourceType, - "Specimen", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Observation" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Observation") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Observation", targetID), - "valueRelatedArtifact_resourceReference_Observation", - projectJSON, - sourceType, - "Observation", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DiagnosticReport" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_DiagnosticReport") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DiagnosticReport", targetID), - "valueRelatedArtifact_resourceReference_DiagnosticReport", - projectJSON, - sourceType, - "DiagnosticReport", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Condition" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Condition") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Condition", targetID), - "valueRelatedArtifact_resourceReference_Condition", - projectJSON, - sourceType, - "Condition", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Medication" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Medication") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Medication", targetID), - "valueRelatedArtifact_resourceReference_Medication", - projectJSON, - sourceType, - "Medication", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationAdministration" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_MedicationAdministration") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationAdministration", targetID), - "valueRelatedArtifact_resourceReference_MedicationAdministration", - projectJSON, - sourceType, - "MedicationAdministration", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationStatement" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_MedicationStatement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationStatement", targetID), - "valueRelatedArtifact_resourceReference_MedicationStatement", - projectJSON, - sourceType, - "MedicationStatement", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "MedicationRequest" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_MedicationRequest") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("MedicationRequest", targetID), - "valueRelatedArtifact_resourceReference_MedicationRequest", - projectJSON, - sourceType, - "MedicationRequest", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Procedure" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Procedure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Procedure", targetID), - "valueRelatedArtifact_resourceReference_Procedure", - projectJSON, - sourceType, - "Procedure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "DocumentReference" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_DocumentReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("DocumentReference", targetID), - "valueRelatedArtifact_resourceReference_DocumentReference", - projectJSON, - sourceType, - "DocumentReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Task" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_Task") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Task", targetID), - "valueRelatedArtifact_resourceReference_Task", - projectJSON, - sourceType, - "Task", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ImagingStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_ImagingStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ImagingStudy", targetID), - "valueRelatedArtifact_resourceReference_ImagingStudy", - projectJSON, - sourceType, - "ImagingStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "FamilyMemberHistory" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_FamilyMemberHistory") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("FamilyMemberHistory", targetID), - "valueRelatedArtifact_resourceReference_FamilyMemberHistory", - projectJSON, - sourceType, - "FamilyMemberHistory", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueRelatedArtifact != nil { - if x.ValueRelatedArtifact.ResourceReference != nil { - if x.ValueRelatedArtifact.ResourceReference.Reference != nil { - refVal := *x.ValueRelatedArtifact.ResourceReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "BodyStructure" { - forwardKey := getEdgeUUID(targetID, id, "valueRelatedArtifact_resourceReference_BodyStructure") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("BodyStructure", targetID), - "valueRelatedArtifact_resourceReference_BodyStructure", - projectJSON, - sourceType, - "BodyStructure", - )) - } - backrefKey := getEdgeUUID(id, targetID, "related_artifact") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("artifact", id), - "related_artifact", - projectJSON, - sourceType, - "artifact", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.OnBehalfOf != nil { - if x.ValueSignature.OnBehalfOf.Reference != nil { - refVal := *x.ValueSignature.OnBehalfOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_onBehalfOf_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueSignature_onBehalfOf_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "onBehalfOf_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.OnBehalfOf != nil { - if x.ValueSignature.OnBehalfOf.Reference != nil { - refVal := *x.ValueSignature.OnBehalfOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_onBehalfOf_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueSignature_onBehalfOf_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "onBehalfOf_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.OnBehalfOf != nil { - if x.ValueSignature.OnBehalfOf.Reference != nil { - refVal := *x.ValueSignature.OnBehalfOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_onBehalfOf_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueSignature_onBehalfOf_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "onBehalfOf_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.OnBehalfOf != nil { - if x.ValueSignature.OnBehalfOf.Reference != nil { - refVal := *x.ValueSignature.OnBehalfOf.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_onBehalfOf_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueSignature_onBehalfOf_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "onBehalfOf_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "onBehalfOf_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.Who != nil { - if x.ValueSignature.Who.Reference != nil { - refVal := *x.ValueSignature.Who.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_who_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "valueSignature_who_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "who_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "who_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.Who != nil { - if x.ValueSignature.Who.Reference != nil { - refVal := *x.ValueSignature.Who.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_who_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "valueSignature_who_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "who_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "who_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.Who != nil { - if x.ValueSignature.Who.Reference != nil { - refVal := *x.ValueSignature.Who.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_who_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "valueSignature_who_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "who_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "who_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueSignature != nil { - if x.ValueSignature.Who != nil { - if x.ValueSignature.Who.Reference != nil { - refVal := *x.ValueSignature.Who.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueSignature_who_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueSignature_who_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "who_signature") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("signature", id), - "who_signature", - projectJSON, - sourceType, - "signature", - )) - } - } - } - } - } - } - if x.ValueUsageContext != nil { - if x.ValueUsageContext.ValueReference != nil { - if x.ValueUsageContext.ValueReference.Reference != nil { - refVal := *x.ValueUsageContext.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueUsageContext_valueReference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "valueUsageContext_valueReference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "usage_context") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("context", id), - "usage_context", - projectJSON, - sourceType, - "context", - )) - } - } - } - } - } - } - if x.ValueUsageContext != nil { - if x.ValueUsageContext.ValueReference != nil { - if x.ValueUsageContext.ValueReference.Reference != nil { - refVal := *x.ValueUsageContext.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "valueUsageContext_valueReference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "valueUsageContext_valueReference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "usage_context") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("context", id), - "usage_context", - projectJSON, - sourceType, - "context", - )) - } - } - } - } - } - } - if x.ValueUsageContext != nil { - if x.ValueUsageContext.ValueReference != nil { - if x.ValueUsageContext.ValueReference.Reference != nil { - refVal := *x.ValueUsageContext.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueUsageContext_valueReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueUsageContext_valueReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "usage_context") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("context", id), - "usage_context", - projectJSON, - sourceType, - "context", - )) - } - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from TaskPerformer. -func (x *TaskPerformer) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "TaskPerformer" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "actor_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "actor_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "task_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "actor_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "actor_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "task_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "actor_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "actor_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "task_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - if x.Actor != nil { - if x.Actor.Reference != nil { - refVal := *x.Actor.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "actor_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "actor_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "task_performer") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("performer", id), - "task_performer", - projectJSON, - sourceType, - "performer", - )) - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from TaskRestriction. -func (x *TaskRestriction) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "TaskRestriction" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Recipient != nil { - for _, item_2_x_Recipient := range x.Recipient { - if item_2_x_Recipient != nil { - if item_2_x_Recipient.Reference != nil { - refVal := *item_2_x_Recipient.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Patient" { - forwardKey := getEdgeUUID(targetID, id, "recipient_Patient") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Patient", targetID), - "recipient_Patient", - projectJSON, - sourceType, - "Patient", - )) - } - backrefKey := getEdgeUUID(id, targetID, "recipient_task_restriction") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("restriction", id), - "recipient_task_restriction", - projectJSON, - sourceType, - "restriction", - )) - } - } - } - } - } - } - } - if x.Recipient != nil { - for _, item_2_x_Recipient := range x.Recipient { - if item_2_x_Recipient != nil { - if item_2_x_Recipient.Reference != nil { - refVal := *item_2_x_Recipient.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Practitioner" { - forwardKey := getEdgeUUID(targetID, id, "recipient_Practitioner") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Practitioner", targetID), - "recipient_Practitioner", - projectJSON, - sourceType, - "Practitioner", - )) - } - backrefKey := getEdgeUUID(id, targetID, "recipient_task_restriction") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("restriction", id), - "recipient_task_restriction", - projectJSON, - sourceType, - "restriction", - )) - } - } - } - } - } - } - } - if x.Recipient != nil { - for _, item_2_x_Recipient := range x.Recipient { - if item_2_x_Recipient != nil { - if item_2_x_Recipient.Reference != nil { - refVal := *item_2_x_Recipient.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "PractitionerRole" { - forwardKey := getEdgeUUID(targetID, id, "recipient_PractitionerRole") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("PractitionerRole", targetID), - "recipient_PractitionerRole", - projectJSON, - sourceType, - "PractitionerRole", - )) - } - backrefKey := getEdgeUUID(id, targetID, "recipient_task_restriction") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("restriction", id), - "recipient_task_restriction", - projectJSON, - sourceType, - "restriction", - )) - } - } - } - } - } - } - } - if x.Recipient != nil { - for _, item_2_x_Recipient := range x.Recipient { - if item_2_x_Recipient != nil { - if item_2_x_Recipient.Reference != nil { - refVal := *item_2_x_Recipient.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "recipient_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "recipient_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "recipient_task_restriction") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("restriction", id), - "recipient_task_restriction", - projectJSON, - sourceType, - "restriction", - )) - } - } - } - } - } - } - } - if x.Recipient != nil { - for _, item_2_x_Recipient := range x.Recipient { - if item_2_x_Recipient != nil { - if item_2_x_Recipient.Reference != nil { - refVal := *item_2_x_Recipient.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "recipient_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "recipient_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "recipient_task_restriction") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("restriction", id), - "recipient_task_restriction", - projectJSON, - sourceType, - "restriction", - )) - } - } - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from Timing. -func (x *Timing) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "Timing" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from TimingRepeat. -func (x *TimingRepeat) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "TimingRepeat" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - return edges, nil -} - -// ExtractEdges extracts graph links from TriggerDefinition. -func (x *TriggerDefinition) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "TriggerDefinition" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.Data != nil { - for _, item_3_x_Data := range x.Data { - if item_3_x_Data != nil { - if item_3_x_Data.SubjectReference != nil { - if item_3_x_Data.SubjectReference.Reference != nil { - refVal := *item_3_x_Data.SubjectReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "data_subjectReference") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("subjectReference", targetID), - "data_subjectReference", - projectJSON, - sourceType, - "subjectReference", - )) - } - backrefKey := getEdgeUUID(id, targetID, "data_requirement") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("requirement", id), - "data_requirement", - projectJSON, - sourceType, - "requirement", - )) - } - } - } - } - } - } - } - } - return edges, nil -} - -// ExtractEdges extracts graph links from UsageContext. -func (x *UsageContext) ExtractEdges(project string) ([]json.RawMessage, error) { - var edges []json.RawMessage - if x == nil || x.ID == nil { - return edges, nil - } - id := *x.ID - sourceType := "UsageContext" - projectJSON := strconv.Quote(project) - _ = id - _ = sourceType - _ = projectJSON - var seen map[string]struct{} - _ = seen - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "ResearchStudy" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_ResearchStudy") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("ResearchStudy", targetID), - "valueReference_ResearchStudy", - projectJSON, - sourceType, - "ResearchStudy", - )) - } - backrefKey := getEdgeUUID(id, targetID, "usage_context") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("context", id), - "usage_context", - projectJSON, - sourceType, - "context", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Group" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Group") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Group", targetID), - "valueReference_Group", - projectJSON, - sourceType, - "Group", - )) - } - backrefKey := getEdgeUUID(id, targetID, "usage_context") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("context", id), - "usage_context", - projectJSON, - sourceType, - "context", - )) - } - } - } - } - } - if x.ValueReference != nil { - if x.ValueReference.Reference != nil { - refVal := *x.ValueReference.Reference - refType, targetID, ok := splitFHIRReference(refVal) - if ok { - if refType == "Organization" { - forwardKey := getEdgeUUID(targetID, id, "valueReference_Organization") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[forwardKey]; !exists { - seen[forwardKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - forwardKey, - collectionID(sourceType, id), - collectionID("Organization", targetID), - "valueReference_Organization", - projectJSON, - sourceType, - "Organization", - )) - } - backrefKey := getEdgeUUID(id, targetID, "usage_context") - if seen == nil { - seen = make(map[string]struct{}, 4) - } - if _, exists := seen[backrefKey]; !exists { - seen[backrefKey] = struct{}{} - edges = append(edges, buildEdgeRawJSON( - backrefKey, - collectionID(sourceType, targetID), - collectionID("context", id), - "usage_context", - projectJSON, - sourceType, - "context", - )) - } - } - } - } - } - return edges, nil -} - -// ValidateAndExtract parses, validates, and extracts edges for a FHIR resource. -func ValidateAndExtract(raw []byte, resourceType string, project string) (Result, error) { - switch resourceType { - case "Address": - var val Address - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Age": - var val Age - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Annotation": - var val Annotation - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Attachment": - var val Attachment - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Availability": - var val Availability - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "AvailabilityAvailableTime": - var val AvailabilityAvailableTime - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "AvailabilityNotAvailableTime": - var val AvailabilityNotAvailableTime - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "BodyStructure": - var val BodyStructure - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "BodyStructureIncludedStructure": - var val BodyStructureIncludedStructure - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "BodyStructureIncludedStructureBodyLandmarkOrientation": - var val BodyStructureIncludedStructureBodyLandmarkOrientation - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": - var val BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "CodeableConcept": - var val CodeableConcept - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "CodeableReference": - var val CodeableReference - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Coding": - var val Coding - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Condition": - var val Condition - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ConditionParticipant": - var val ConditionParticipant - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ConditionStage": - var val ConditionStage - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ContactDetail": - var val ContactDetail - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ContactPoint": - var val ContactPoint - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Count": - var val Count - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "DataRequirement": - var val DataRequirement - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "DataRequirementCodeFilter": - var val DataRequirementCodeFilter - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "DataRequirementDateFilter": - var val DataRequirementDateFilter - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "DataRequirementSort": - var val DataRequirementSort - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "DataRequirementValueFilter": - var val DataRequirementValueFilter - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "DiagnosticReport": - var val DiagnosticReport - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "DiagnosticReportMedia": - var val DiagnosticReportMedia - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "DiagnosticReportSupportingInfo": - var val DiagnosticReportSupportingInfo - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Directory": - var val Directory - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Distance": - var val Distance - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "DocumentReference": - var val DocumentReference - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "DocumentReferenceAttester": - var val DocumentReferenceAttester - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "DocumentReferenceContent": - var val DocumentReferenceContent - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "DocumentReferenceContentProfile": - var val DocumentReferenceContentProfile - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "DocumentReferenceRelatesTo": - var val DocumentReferenceRelatesTo - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Dosage": - var val Dosage - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "DosageDoseAndRate": - var val DosageDoseAndRate - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Duration": - var val Duration - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Expression": - var val Expression - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ExtendedContactDetail": - var val ExtendedContactDetail - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Extension": - var val Extension - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "FHIRPrimitiveExtension": - var val FHIRPrimitiveExtension - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "FamilyMemberHistory": - var val FamilyMemberHistory - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "FamilyMemberHistoryCondition": - var val FamilyMemberHistoryCondition - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "FamilyMemberHistoryParticipant": - var val FamilyMemberHistoryParticipant - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "FamilyMemberHistoryProcedure": - var val FamilyMemberHistoryProcedure - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Group": - var val Group - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "GroupCharacteristic": - var val GroupCharacteristic - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "GroupMember": - var val GroupMember - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "HumanName": - var val HumanName - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Identifier": - var val Identifier - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ImagingStudy": - var val ImagingStudy - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ImagingStudySeries": - var val ImagingStudySeries - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ImagingStudySeriesInstance": - var val ImagingStudySeriesInstance - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ImagingStudySeriesPerformer": - var val ImagingStudySeriesPerformer - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Medication": - var val Medication - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "MedicationAdministration": - var val MedicationAdministration - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "MedicationAdministrationDosage": - var val MedicationAdministrationDosage - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "MedicationAdministrationPerformer": - var val MedicationAdministrationPerformer - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "MedicationBatch": - var val MedicationBatch - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "MedicationIngredient": - var val MedicationIngredient - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "MedicationRequest": - var val MedicationRequest - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "MedicationRequestDispenseRequest": - var val MedicationRequestDispenseRequest - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "MedicationRequestDispenseRequestInitialFill": - var val MedicationRequestDispenseRequestInitialFill - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "MedicationRequestSubstitution": - var val MedicationRequestSubstitution - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "MedicationStatement": - var val MedicationStatement - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "MedicationStatementAdherence": - var val MedicationStatementAdherence - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Meta": - var val Meta - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Money": - var val Money - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Narrative": - var val Narrative - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Observation": - var val Observation - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ObservationComponent": - var val ObservationComponent - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ObservationReferenceRange": - var val ObservationReferenceRange - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ObservationTriggeredBy": - var val ObservationTriggeredBy - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Organization": - var val Organization - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "OrganizationQualification": - var val OrganizationQualification - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ParameterDefinition": - var val ParameterDefinition - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Patient": - var val Patient - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "PatientCommunication": - var val PatientCommunication - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "PatientContact": - var val PatientContact - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "PatientLink": - var val PatientLink - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Period": - var val Period - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Practitioner": - var val Practitioner - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "PractitionerCommunication": - var val PractitionerCommunication - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "PractitionerQualification": - var val PractitionerQualification - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "PractitionerRole": - var val PractitionerRole - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Procedure": - var val Procedure - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ProcedureFocalDevice": - var val ProcedureFocalDevice - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ProcedurePerformer": - var val ProcedurePerformer - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Quantity": - var val Quantity - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Range": - var val Range - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Ratio": - var val Ratio - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "RatioRange": - var val RatioRange - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Reference": - var val Reference - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "RelatedArtifact": - var val RelatedArtifact - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ResearchStudy": - var val ResearchStudy - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ResearchStudyAssociatedParty": - var val ResearchStudyAssociatedParty - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ResearchStudyComparisonGroup": - var val ResearchStudyComparisonGroup - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ResearchStudyLabel": - var val ResearchStudyLabel - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ResearchStudyObjective": - var val ResearchStudyObjective - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ResearchStudyOutcomeMeasure": - var val ResearchStudyOutcomeMeasure - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ResearchStudyProgressStatus": - var val ResearchStudyProgressStatus - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ResearchStudyRecruitment": - var val ResearchStudyRecruitment - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ResearchSubject": - var val ResearchSubject - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "ResearchSubjectProgress": - var val ResearchSubjectProgress - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Resource": - var val Resource - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "SampledData": - var val SampledData - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Signature": - var val Signature - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Specimen": - var val Specimen - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "SpecimenCollection": - var val SpecimenCollection - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) - } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) - } - var objectID string - if val.ID != nil { - objectID = *val.ID - } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "SpecimenContainer": - var val SpecimenContainer - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) - } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) + } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Condition" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Condition") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_Condition", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) + } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Medication" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Medication") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_Medication", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } } - var objectID string - if val.ID != nil { - objectID = *val.ID + } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationAdministration" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_MedicationAdministration") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_MedicationAdministration", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "SpecimenFeature": - var val SpecimenFeature - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) + } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationStatement" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_MedicationStatement") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_MedicationStatement", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) + } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "MedicationRequest" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_MedicationRequest") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_MedicationRequest", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) + } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Procedure" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Procedure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_Procedure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } } - var objectID string - if val.ID != nil { - objectID = *val.ID + } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "DocumentReference" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_DocumentReference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_DocumentReference", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "SpecimenProcessing": - var val SpecimenProcessing - if err := sonic.Unmarshal(raw, &val); err != nil { - return Result{}, fmt.Errorf("decode error: %w", err) + } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "Task" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_Task") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_Task", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } } - if err := val.Validate(); err != nil { - return Result{}, fmt.Errorf("validation error: %w", err) + } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "ImagingStudy" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_ImagingStudy") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_ImagingStudy", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } } - edges, err := val.ExtractEdges(project) - if err != nil { - return Result{}, fmt.Errorf("extraction error: %w", err) + } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "FamilyMemberHistory" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_FamilyMemberHistory") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_FamilyMemberHistory", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } } - var objectID string - if val.ID != nil { - objectID = *val.ID + } + if x.StatusReason != nil { + if x.StatusReason.Reference != nil { + if x.StatusReason.Reference.Reference != nil { + refVal := *x.StatusReason.Reference.Reference + refType, targetID, ok := splitFHIRReference(refVal) + if ok { + refType, ok = fhirschema.ConcreteResourceType(refType) + if ok { + if refType == "BodyStructure" { + forwardKey := getEdgeUUID(targetID, id, "statusReason_reference_BodyStructure") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[forwardKey]; !exists { + seen[forwardKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + forwardKey, + collectionID(sourceType, id), + collectionID(refType, targetID), + "statusReason_reference_BodyStructure", + projectJSON, + sourceType, + refType, + )) + } + backrefKey := getEdgeUUID(id, targetID, "codeable_reference") + if seen == nil { + seen = make(map[string]struct{}, 4) + } + if _, exists := seen[backrefKey]; !exists { + seen[backrefKey] = struct{}{} + edges = append(edges, buildEdgeRawJSON( + backrefKey, + collectionID(refType, targetID), + collectionID(sourceType, id), + "codeable_reference", + projectJSON, + refType, + sourceType, + )) + } + } + } + } + } } - return Result{ - ObjectID: objectID, - ResourceType: resourceType, - Vertex: json.RawMessage(raw), - Edges: edges, - }, nil - case "Substance": - var val Substance + } + return edges, nil +} + +// ValidateAndExtract parses, validates, and extracts edges for a FHIR resource. +func ValidateAndExtract(raw []byte, resourceType string, project string) (Result, error) { + switch resourceType { + case "BodyStructure": + var val BodyStructure if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -79683,8 +53316,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "SubstanceDefinition": - var val SubstanceDefinition + case "Condition": + var val Condition if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -79705,8 +53338,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "SubstanceDefinitionCharacterization": - var val SubstanceDefinitionCharacterization + case "DiagnosticReport": + var val DiagnosticReport if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -79727,8 +53360,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "SubstanceDefinitionCode": - var val SubstanceDefinitionCode + case "DocumentReference": + var val DocumentReference if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -79749,8 +53382,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "SubstanceDefinitionMoiety": - var val SubstanceDefinitionMoiety + case "FamilyMemberHistory": + var val FamilyMemberHistory if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -79771,8 +53404,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "SubstanceDefinitionMolecularWeight": - var val SubstanceDefinitionMolecularWeight + case "Group": + var val Group if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -79793,8 +53426,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "SubstanceDefinitionName": - var val SubstanceDefinitionName + case "ImagingStudy": + var val ImagingStudy if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -79815,8 +53448,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "SubstanceDefinitionNameOfficial": - var val SubstanceDefinitionNameOfficial + case "Medication": + var val Medication if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -79837,8 +53470,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "SubstanceDefinitionProperty": - var val SubstanceDefinitionProperty + case "MedicationAdministration": + var val MedicationAdministration if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -79859,8 +53492,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "SubstanceDefinitionRelationship": - var val SubstanceDefinitionRelationship + case "MedicationRequest": + var val MedicationRequest if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -79881,8 +53514,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "SubstanceDefinitionSourceMaterial": - var val SubstanceDefinitionSourceMaterial + case "MedicationStatement": + var val MedicationStatement if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -79903,8 +53536,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "SubstanceDefinitionStructure": - var val SubstanceDefinitionStructure + case "Observation": + var val Observation if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -79925,8 +53558,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "SubstanceDefinitionStructureRepresentation": - var val SubstanceDefinitionStructureRepresentation + case "Organization": + var val Organization if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -79947,8 +53580,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "SubstanceIngredient": - var val SubstanceIngredient + case "Patient": + var val Patient if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -79969,8 +53602,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "Task": - var val Task + case "Practitioner": + var val Practitioner if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -79991,8 +53624,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "TaskInput": - var val TaskInput + case "PractitionerRole": + var val PractitionerRole if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -80013,8 +53646,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "TaskOutput": - var val TaskOutput + case "Procedure": + var val Procedure if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -80035,8 +53668,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "TaskPerformer": - var val TaskPerformer + case "ResearchStudy": + var val ResearchStudy if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -80057,8 +53690,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "TaskRestriction": - var val TaskRestriction + case "ResearchSubject": + var val ResearchSubject if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -80079,8 +53712,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "Timing": - var val Timing + case "Specimen": + var val Specimen if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -80101,8 +53734,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "TimingRepeat": - var val TimingRepeat + case "Substance": + var val Substance if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -80123,8 +53756,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "TriggerDefinition": - var val TriggerDefinition + case "SubstanceDefinition": + var val SubstanceDefinition if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } @@ -80145,8 +53778,8 @@ func ValidateAndExtract(raw []byte, resourceType string, project string) (Result Vertex: json.RawMessage(raw), Edges: edges, }, nil - case "UsageContext": - var val UsageContext + case "Task": + var val Task if err := sonic.Unmarshal(raw, &val); err != nil { return Result{}, fmt.Errorf("decode error: %w", err) } diff --git a/generated/fhirschema/generated.go b/generated/fhirschema/generated.go index 4dd9c2ea..824ed52d 100644 --- a/generated/fhirschema/generated.go +++ b/generated/fhirschema/generated.go @@ -12996,77 +12996,9 @@ var Definitions = map[string]Definition{ } var Traversals = map[string]Traversal{ - "Annotation|authorReference_Practitioner|Practitioner": { - FromType: "Annotation", - EdgeLabel: "authorReference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|authorReference_Practitioner|Annotation": { - FromType: "Practitioner", - EdgeLabel: "authorReference_Practitioner", - ToType: "Annotation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Annotation|authorReference_PractitionerRole|PractitionerRole": { - FromType: "Annotation", - EdgeLabel: "authorReference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|authorReference_PractitionerRole|Annotation": { - FromType: "PractitionerRole", - EdgeLabel: "authorReference_PractitionerRole", - ToType: "Annotation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Annotation|authorReference_Patient|Patient": { - FromType: "Annotation", - EdgeLabel: "authorReference_Patient", + "BodyStructure|patient|Patient": { + FromType: "BodyStructure", + EdgeLabel: "patient", ToType: "Patient", Direction: []string{ "outbound", @@ -13075,16 +13007,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "body_structure", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|authorReference_Patient|Annotation": { + "Patient|patient|BodyStructure": { FromType: "Patient", - EdgeLabel: "authorReference_Patient", - ToType: "Annotation", + EdgeLabel: "patient", + ToType: "BodyStructure", Direction: []string{ "outbound", }, @@ -13092,16 +13024,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "body_structure", }, RegexMatch: []string{ "Patient/*", }, }, - "Annotation|authorReference_Organization|Organization": { - FromType: "Annotation", - EdgeLabel: "authorReference_Organization", - ToType: "Organization", + "Condition|subject_Patient|Patient": { + FromType: "Condition", + EdgeLabel: "subject_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -13109,16 +13041,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "condition", }, RegexMatch: []string{ - "Organization/*", + "Patient/*", }, }, - "Organization|authorReference_Organization|Annotation": { - FromType: "Organization", - EdgeLabel: "authorReference_Organization", - ToType: "Annotation", + "Patient|subject_Patient|Condition": { + FromType: "Patient", + EdgeLabel: "subject_Patient", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13126,16 +13058,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "condition", }, RegexMatch: []string{ - "Organization/*", + "Patient/*", }, }, - "BodyStructure|patient|Patient": { - FromType: "BodyStructure", - EdgeLabel: "patient", - ToType: "Patient", + "Condition|subject_Group|Group": { + FromType: "Condition", + EdgeLabel: "subject_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -13143,16 +13075,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "body_structure", + "condition", }, RegexMatch: []string{ - "Patient/*", + "Group/*", }, }, - "Patient|patient|BodyStructure": { - FromType: "Patient", - EdgeLabel: "patient", - ToType: "BodyStructure", + "Group|subject_Group|Condition": { + FromType: "Group", + EdgeLabel: "subject_Group", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13160,15 +13092,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "body_structure", + "condition", }, RegexMatch: []string{ - "Patient/*", + "Group/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_Organization|Organization": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_Organization", + "Condition|evidence_reference_Organization|Organization": { + FromType: "Condition", + EdgeLabel: "evidence_reference_Organization", ToType: "Organization", Direction: []string{ "outbound", @@ -13183,10 +13115,10 @@ var Traversals = map[string]Traversal{ "Organization/*", }, }, - "Organization|device_reference_Organization|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "Organization|evidence_reference_Organization|Condition": { FromType: "Organization", - EdgeLabel: "device_reference_Organization", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_Organization", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13200,9 +13132,9 @@ var Traversals = map[string]Traversal{ "Organization/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_Group|Group": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_Group", + "Condition|evidence_reference_Group|Group": { + FromType: "Condition", + EdgeLabel: "evidence_reference_Group", ToType: "Group", Direction: []string{ "outbound", @@ -13217,10 +13149,10 @@ var Traversals = map[string]Traversal{ "Group/*", }, }, - "Group|device_reference_Group|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "Group|evidence_reference_Group|Condition": { FromType: "Group", - EdgeLabel: "device_reference_Group", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_Group", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13234,9 +13166,9 @@ var Traversals = map[string]Traversal{ "Group/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_Practitioner|Practitioner": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_Practitioner", + "Condition|evidence_reference_Practitioner|Practitioner": { + FromType: "Condition", + EdgeLabel: "evidence_reference_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", @@ -13251,10 +13183,10 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "Practitioner|device_reference_Practitioner|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "Practitioner|evidence_reference_Practitioner|Condition": { FromType: "Practitioner", - EdgeLabel: "device_reference_Practitioner", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_Practitioner", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13268,9 +13200,9 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_PractitionerRole|PractitionerRole": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_PractitionerRole", + "Condition|evidence_reference_PractitionerRole|PractitionerRole": { + FromType: "Condition", + EdgeLabel: "evidence_reference_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", @@ -13285,10 +13217,10 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "PractitionerRole|device_reference_PractitionerRole|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "PractitionerRole|evidence_reference_PractitionerRole|Condition": { FromType: "PractitionerRole", - EdgeLabel: "device_reference_PractitionerRole", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_PractitionerRole", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13302,9 +13234,9 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_ResearchStudy|ResearchStudy": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_ResearchStudy", + "Condition|evidence_reference_ResearchStudy|ResearchStudy": { + FromType: "Condition", + EdgeLabel: "evidence_reference_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -13319,10 +13251,10 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "ResearchStudy|device_reference_ResearchStudy|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "ResearchStudy|evidence_reference_ResearchStudy|Condition": { FromType: "ResearchStudy", - EdgeLabel: "device_reference_ResearchStudy", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_ResearchStudy", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13336,9 +13268,9 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_Patient|Patient": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_Patient", + "Condition|evidence_reference_Patient|Patient": { + FromType: "Condition", + EdgeLabel: "evidence_reference_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -13353,10 +13285,10 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "Patient|device_reference_Patient|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "Patient|evidence_reference_Patient|Condition": { FromType: "Patient", - EdgeLabel: "device_reference_Patient", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_Patient", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13370,9 +13302,9 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_ResearchSubject|ResearchSubject": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_ResearchSubject", + "Condition|evidence_reference_ResearchSubject|ResearchSubject": { + FromType: "Condition", + EdgeLabel: "evidence_reference_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -13387,10 +13319,10 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "ResearchSubject|device_reference_ResearchSubject|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "ResearchSubject|evidence_reference_ResearchSubject|Condition": { FromType: "ResearchSubject", - EdgeLabel: "device_reference_ResearchSubject", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_ResearchSubject", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13404,9 +13336,9 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_Substance|Substance": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_Substance", + "Condition|evidence_reference_Substance|Substance": { + FromType: "Condition", + EdgeLabel: "evidence_reference_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -13421,10 +13353,10 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "Substance|device_reference_Substance|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "Substance|evidence_reference_Substance|Condition": { FromType: "Substance", - EdgeLabel: "device_reference_Substance", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_Substance", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13438,9 +13370,9 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_SubstanceDefinition", + "Condition|evidence_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "Condition", + EdgeLabel: "evidence_reference_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -13455,10 +13387,10 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|device_reference_SubstanceDefinition|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "SubstanceDefinition|evidence_reference_SubstanceDefinition|Condition": { FromType: "SubstanceDefinition", - EdgeLabel: "device_reference_SubstanceDefinition", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_SubstanceDefinition", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13472,9 +13404,9 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_Specimen|Specimen": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_Specimen", + "Condition|evidence_reference_Specimen|Specimen": { + FromType: "Condition", + EdgeLabel: "evidence_reference_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -13489,10 +13421,10 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "Specimen|device_reference_Specimen|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "Specimen|evidence_reference_Specimen|Condition": { FromType: "Specimen", - EdgeLabel: "device_reference_Specimen", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_Specimen", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13506,9 +13438,9 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_Observation|Observation": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_Observation", + "Condition|evidence_reference_Observation|Observation": { + FromType: "Condition", + EdgeLabel: "evidence_reference_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -13523,10 +13455,10 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "Observation|device_reference_Observation|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "Observation|evidence_reference_Observation|Condition": { FromType: "Observation", - EdgeLabel: "device_reference_Observation", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_Observation", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13540,9 +13472,9 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_DiagnosticReport|DiagnosticReport": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_DiagnosticReport", + "Condition|evidence_reference_DiagnosticReport|DiagnosticReport": { + FromType: "Condition", + EdgeLabel: "evidence_reference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -13557,10 +13489,10 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "DiagnosticReport|device_reference_DiagnosticReport|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "DiagnosticReport|evidence_reference_DiagnosticReport|Condition": { FromType: "DiagnosticReport", - EdgeLabel: "device_reference_DiagnosticReport", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_DiagnosticReport", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13574,9 +13506,9 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_Condition|Condition": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_Condition", + "Condition|evidence_reference_Condition|Condition": { + FromType: "Condition", + EdgeLabel: "evidence_reference_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -13591,26 +13523,9 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "Condition|device_reference_Condition|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "Condition|evidence_reference_Medication|Medication": { FromType: "Condition", - EdgeLabel: "device_reference_Condition", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_Medication|Medication": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_Medication", + EdgeLabel: "evidence_reference_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -13625,10 +13540,10 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "Medication|device_reference_Medication|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "Medication|evidence_reference_Medication|Condition": { FromType: "Medication", - EdgeLabel: "device_reference_Medication", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_Medication", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13642,9 +13557,9 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_MedicationAdministration|MedicationAdministration": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_MedicationAdministration", + "Condition|evidence_reference_MedicationAdministration|MedicationAdministration": { + FromType: "Condition", + EdgeLabel: "evidence_reference_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -13659,10 +13574,10 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "MedicationAdministration|device_reference_MedicationAdministration|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "MedicationAdministration|evidence_reference_MedicationAdministration|Condition": { FromType: "MedicationAdministration", - EdgeLabel: "device_reference_MedicationAdministration", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_MedicationAdministration", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13676,9 +13591,9 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_MedicationStatement|MedicationStatement": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_MedicationStatement", + "Condition|evidence_reference_MedicationStatement|MedicationStatement": { + FromType: "Condition", + EdgeLabel: "evidence_reference_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -13693,10 +13608,10 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "MedicationStatement|device_reference_MedicationStatement|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "MedicationStatement|evidence_reference_MedicationStatement|Condition": { FromType: "MedicationStatement", - EdgeLabel: "device_reference_MedicationStatement", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_MedicationStatement", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13710,9 +13625,9 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_MedicationRequest|MedicationRequest": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_MedicationRequest", + "Condition|evidence_reference_MedicationRequest|MedicationRequest": { + FromType: "Condition", + EdgeLabel: "evidence_reference_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -13727,10 +13642,10 @@ var Traversals = map[string]Traversal{ "MedicationRequest/*", }, }, - "MedicationRequest|device_reference_MedicationRequest|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "MedicationRequest|evidence_reference_MedicationRequest|Condition": { FromType: "MedicationRequest", - EdgeLabel: "device_reference_MedicationRequest", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_MedicationRequest", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13744,9 +13659,9 @@ var Traversals = map[string]Traversal{ "MedicationRequest/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_Procedure|Procedure": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_Procedure", + "Condition|evidence_reference_Procedure|Procedure": { + FromType: "Condition", + EdgeLabel: "evidence_reference_Procedure", ToType: "Procedure", Direction: []string{ "outbound", @@ -13761,10 +13676,10 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "Procedure|device_reference_Procedure|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "Procedure|evidence_reference_Procedure|Condition": { FromType: "Procedure", - EdgeLabel: "device_reference_Procedure", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_Procedure", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13778,9 +13693,9 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_DocumentReference|DocumentReference": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_DocumentReference", + "Condition|evidence_reference_DocumentReference|DocumentReference": { + FromType: "Condition", + EdgeLabel: "evidence_reference_DocumentReference", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -13795,10 +13710,10 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "DocumentReference|device_reference_DocumentReference|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "DocumentReference|evidence_reference_DocumentReference|Condition": { FromType: "DocumentReference", - EdgeLabel: "device_reference_DocumentReference", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_DocumentReference", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13812,9 +13727,9 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_Task|Task": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_Task", + "Condition|evidence_reference_Task|Task": { + FromType: "Condition", + EdgeLabel: "evidence_reference_Task", ToType: "Task", Direction: []string{ "outbound", @@ -13829,10 +13744,10 @@ var Traversals = map[string]Traversal{ "Task/*", }, }, - "Task|device_reference_Task|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "Task|evidence_reference_Task|Condition": { FromType: "Task", - EdgeLabel: "device_reference_Task", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_Task", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13846,9 +13761,9 @@ var Traversals = map[string]Traversal{ "Task/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_ImagingStudy|ImagingStudy": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_ImagingStudy", + "Condition|evidence_reference_ImagingStudy|ImagingStudy": { + FromType: "Condition", + EdgeLabel: "evidence_reference_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", @@ -13863,10 +13778,10 @@ var Traversals = map[string]Traversal{ "ImagingStudy/*", }, }, - "ImagingStudy|device_reference_ImagingStudy|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "ImagingStudy|evidence_reference_ImagingStudy|Condition": { FromType: "ImagingStudy", - EdgeLabel: "device_reference_ImagingStudy", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_ImagingStudy", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13880,9 +13795,9 @@ var Traversals = map[string]Traversal{ "ImagingStudy/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_FamilyMemberHistory", + "Condition|evidence_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "Condition", + EdgeLabel: "evidence_reference_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -13897,10 +13812,10 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|device_reference_FamilyMemberHistory|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "FamilyMemberHistory|evidence_reference_FamilyMemberHistory|Condition": { FromType: "FamilyMemberHistory", - EdgeLabel: "device_reference_FamilyMemberHistory", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_FamilyMemberHistory", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13914,9 +13829,9 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark|device_reference_BodyStructure|BodyStructure": { - FromType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", - EdgeLabel: "device_reference_BodyStructure", + "Condition|evidence_reference_BodyStructure|BodyStructure": { + FromType: "Condition", + EdgeLabel: "evidence_reference_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", @@ -13931,10 +13846,10 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "BodyStructure|device_reference_BodyStructure|BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark": { + "BodyStructure|evidence_reference_BodyStructure|Condition": { FromType: "BodyStructure", - EdgeLabel: "device_reference_BodyStructure", - ToType: "BodyStructureIncludedStructureBodyLandmarkOrientationDistanceFromLandmark", + EdgeLabel: "evidence_reference_BodyStructure", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13948,10 +13863,10 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "CodeableReference|reference_Organization|Organization": { - FromType: "CodeableReference", - EdgeLabel: "reference_Organization", - ToType: "Organization", + "Condition|note_authorReference_Practitioner|Practitioner": { + FromType: "Condition", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -13959,16 +13874,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Organization/*", + "Practitioner/*", }, }, - "Organization|reference_Organization|CodeableReference": { - FromType: "Organization", - EdgeLabel: "reference_Organization", - ToType: "CodeableReference", + "Practitioner|note_authorReference_Practitioner|Condition": { + FromType: "Practitioner", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -13976,16 +13891,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Organization/*", + "Practitioner/*", }, }, - "CodeableReference|reference_Group|Group": { - FromType: "CodeableReference", - EdgeLabel: "reference_Group", - ToType: "Group", + "Condition|note_authorReference_PractitionerRole|PractitionerRole": { + FromType: "Condition", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -13993,16 +13908,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Group/*", + "PractitionerRole/*", }, }, - "Group|reference_Group|CodeableReference": { - FromType: "Group", - EdgeLabel: "reference_Group", - ToType: "CodeableReference", + "PractitionerRole|note_authorReference_PractitionerRole|Condition": { + FromType: "PractitionerRole", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -14010,16 +13925,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Group/*", + "PractitionerRole/*", }, }, - "CodeableReference|reference_Practitioner|Practitioner": { - FromType: "CodeableReference", - EdgeLabel: "reference_Practitioner", - ToType: "Practitioner", + "Condition|note_authorReference_Patient|Patient": { + FromType: "Condition", + EdgeLabel: "note_authorReference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -14027,16 +13942,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Practitioner/*", + "Patient/*", }, }, - "Practitioner|reference_Practitioner|CodeableReference": { - FromType: "Practitioner", - EdgeLabel: "reference_Practitioner", - ToType: "CodeableReference", + "Patient|note_authorReference_Patient|Condition": { + FromType: "Patient", + EdgeLabel: "note_authorReference_Patient", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -14044,16 +13959,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Practitioner/*", + "Patient/*", }, }, - "CodeableReference|reference_PractitionerRole|PractitionerRole": { - FromType: "CodeableReference", - EdgeLabel: "reference_PractitionerRole", - ToType: "PractitionerRole", + "Condition|note_authorReference_Organization|Organization": { + FromType: "Condition", + EdgeLabel: "note_authorReference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -14061,16 +13976,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "PractitionerRole/*", + "Organization/*", }, }, - "PractitionerRole|reference_PractitionerRole|CodeableReference": { - FromType: "PractitionerRole", - EdgeLabel: "reference_PractitionerRole", - ToType: "CodeableReference", + "Organization|note_authorReference_Organization|Condition": { + FromType: "Organization", + EdgeLabel: "note_authorReference_Organization", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -14078,16 +13993,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "PractitionerRole/*", + "Organization/*", }, }, - "CodeableReference|reference_ResearchStudy|ResearchStudy": { - FromType: "CodeableReference", - EdgeLabel: "reference_ResearchStudy", - ToType: "ResearchStudy", + "Condition|participant_actor_Practitioner|Practitioner": { + FromType: "Condition", + EdgeLabel: "participant_actor_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -14095,16 +14010,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "condition_participant", }, RegexMatch: []string{ - "ResearchStudy/*", + "Practitioner/*", }, }, - "ResearchStudy|reference_ResearchStudy|CodeableReference": { - FromType: "ResearchStudy", - EdgeLabel: "reference_ResearchStudy", - ToType: "CodeableReference", + "Practitioner|participant_actor_Practitioner|Condition": { + FromType: "Practitioner", + EdgeLabel: "participant_actor_Practitioner", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -14112,16 +14027,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "condition_participant", }, RegexMatch: []string{ - "ResearchStudy/*", + "Practitioner/*", }, }, - "CodeableReference|reference_Patient|Patient": { - FromType: "CodeableReference", - EdgeLabel: "reference_Patient", - ToType: "Patient", + "Condition|participant_actor_PractitionerRole|PractitionerRole": { + FromType: "Condition", + EdgeLabel: "participant_actor_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -14129,16 +14044,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "condition_participant", }, RegexMatch: []string{ - "Patient/*", + "PractitionerRole/*", }, }, - "Patient|reference_Patient|CodeableReference": { - FromType: "Patient", - EdgeLabel: "reference_Patient", - ToType: "CodeableReference", + "PractitionerRole|participant_actor_PractitionerRole|Condition": { + FromType: "PractitionerRole", + EdgeLabel: "participant_actor_PractitionerRole", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -14146,16 +14061,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "condition_participant", }, RegexMatch: []string{ - "Patient/*", + "PractitionerRole/*", }, }, - "CodeableReference|reference_ResearchSubject|ResearchSubject": { - FromType: "CodeableReference", - EdgeLabel: "reference_ResearchSubject", - ToType: "ResearchSubject", + "Condition|participant_actor_Patient|Patient": { + FromType: "Condition", + EdgeLabel: "participant_actor_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -14163,16 +14078,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "condition_participant", }, RegexMatch: []string{ - "ResearchSubject/*", + "Patient/*", }, }, - "ResearchSubject|reference_ResearchSubject|CodeableReference": { - FromType: "ResearchSubject", - EdgeLabel: "reference_ResearchSubject", - ToType: "CodeableReference", + "Patient|participant_actor_Patient|Condition": { + FromType: "Patient", + EdgeLabel: "participant_actor_Patient", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -14180,16 +14095,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "condition_participant", }, RegexMatch: []string{ - "ResearchSubject/*", + "Patient/*", }, }, - "CodeableReference|reference_Substance|Substance": { - FromType: "CodeableReference", - EdgeLabel: "reference_Substance", - ToType: "Substance", + "Condition|participant_actor_Organization|Organization": { + FromType: "Condition", + EdgeLabel: "participant_actor_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -14197,16 +14112,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "condition_participant", }, RegexMatch: []string{ - "Substance/*", + "Organization/*", }, }, - "Substance|reference_Substance|CodeableReference": { - FromType: "Substance", - EdgeLabel: "reference_Substance", - ToType: "CodeableReference", + "Organization|participant_actor_Organization|Condition": { + FromType: "Organization", + EdgeLabel: "participant_actor_Organization", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -14214,424 +14129,424 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "condition_participant", }, RegexMatch: []string{ - "Substance/*", + "Organization/*", }, }, - "CodeableReference|reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "CodeableReference", - EdgeLabel: "reference_SubstanceDefinition", - ToType: "SubstanceDefinition", + "Condition|stage_assessment_DiagnosticReport|DiagnosticReport": { + FromType: "Condition", + EdgeLabel: "stage_assessment_DiagnosticReport", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "assessment_condition_stage", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "DiagnosticReport/*", }, }, - "SubstanceDefinition|reference_SubstanceDefinition|CodeableReference": { - FromType: "SubstanceDefinition", - EdgeLabel: "reference_SubstanceDefinition", - ToType: "CodeableReference", + "DiagnosticReport|stage_assessment_DiagnosticReport|Condition": { + FromType: "DiagnosticReport", + EdgeLabel: "stage_assessment_DiagnosticReport", + ToType: "Condition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "assessment_condition_stage", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "DiagnosticReport/*", }, }, - "CodeableReference|reference_Specimen|Specimen": { - FromType: "CodeableReference", - EdgeLabel: "reference_Specimen", - ToType: "Specimen", + "Condition|stage_assessment_Observation|Observation": { + FromType: "Condition", + EdgeLabel: "stage_assessment_Observation", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "assessment_condition_stage", }, RegexMatch: []string{ - "Specimen/*", + "Observation/*", }, }, - "Specimen|reference_Specimen|CodeableReference": { - FromType: "Specimen", - EdgeLabel: "reference_Specimen", - ToType: "CodeableReference", + "Observation|stage_assessment_Observation|Condition": { + FromType: "Observation", + EdgeLabel: "stage_assessment_Observation", + ToType: "Condition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "assessment_condition_stage", }, RegexMatch: []string{ - "Specimen/*", + "Observation/*", }, }, - "CodeableReference|reference_Observation|Observation": { - FromType: "CodeableReference", - EdgeLabel: "reference_Observation", - ToType: "Observation", + "DiagnosticReport|basedOn_MedicationRequest|MedicationRequest": { + FromType: "DiagnosticReport", + EdgeLabel: "basedOn_MedicationRequest", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_diagnostic_report", }, RegexMatch: []string{ - "Observation/*", + "MedicationRequest/*", }, }, - "Observation|reference_Observation|CodeableReference": { - FromType: "Observation", - EdgeLabel: "reference_Observation", - ToType: "CodeableReference", + "MedicationRequest|basedOn_MedicationRequest|DiagnosticReport": { + FromType: "MedicationRequest", + EdgeLabel: "basedOn_MedicationRequest", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_diagnostic_report", }, RegexMatch: []string{ - "Observation/*", + "MedicationRequest/*", }, }, - "CodeableReference|reference_DiagnosticReport|DiagnosticReport": { - FromType: "CodeableReference", - EdgeLabel: "reference_DiagnosticReport", - ToType: "DiagnosticReport", + "DiagnosticReport|performer_Practitioner|Practitioner": { + FromType: "DiagnosticReport", + EdgeLabel: "performer_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "performer_diagnostic_report", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Practitioner/*", }, }, - "DiagnosticReport|reference_DiagnosticReport|CodeableReference": { - FromType: "DiagnosticReport", - EdgeLabel: "reference_DiagnosticReport", - ToType: "CodeableReference", + "Practitioner|performer_Practitioner|DiagnosticReport": { + FromType: "Practitioner", + EdgeLabel: "performer_Practitioner", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "performer_diagnostic_report", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Practitioner/*", }, }, - "CodeableReference|reference_Condition|Condition": { - FromType: "CodeableReference", - EdgeLabel: "reference_Condition", - ToType: "Condition", + "DiagnosticReport|performer_PractitionerRole|PractitionerRole": { + FromType: "DiagnosticReport", + EdgeLabel: "performer_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "performer_diagnostic_report", }, RegexMatch: []string{ - "Condition/*", + "PractitionerRole/*", }, }, - "Condition|reference_Condition|CodeableReference": { - FromType: "Condition", - EdgeLabel: "reference_Condition", - ToType: "CodeableReference", + "PractitionerRole|performer_PractitionerRole|DiagnosticReport": { + FromType: "PractitionerRole", + EdgeLabel: "performer_PractitionerRole", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "performer_diagnostic_report", }, RegexMatch: []string{ - "Condition/*", + "PractitionerRole/*", }, }, - "CodeableReference|reference_Medication|Medication": { - FromType: "CodeableReference", - EdgeLabel: "reference_Medication", - ToType: "Medication", + "DiagnosticReport|performer_Organization|Organization": { + FromType: "DiagnosticReport", + EdgeLabel: "performer_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "performer_diagnostic_report", }, RegexMatch: []string{ - "Medication/*", + "Organization/*", }, }, - "Medication|reference_Medication|CodeableReference": { - FromType: "Medication", - EdgeLabel: "reference_Medication", - ToType: "CodeableReference", + "Organization|performer_Organization|DiagnosticReport": { + FromType: "Organization", + EdgeLabel: "performer_Organization", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "performer_diagnostic_report", }, RegexMatch: []string{ - "Medication/*", + "Organization/*", }, }, - "CodeableReference|reference_MedicationAdministration|MedicationAdministration": { - FromType: "CodeableReference", - EdgeLabel: "reference_MedicationAdministration", - ToType: "MedicationAdministration", + "DiagnosticReport|result|Observation": { + FromType: "DiagnosticReport", + EdgeLabel: "result", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "result_diagnostic_report", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Observation/*", }, }, - "MedicationAdministration|reference_MedicationAdministration|CodeableReference": { - FromType: "MedicationAdministration", - EdgeLabel: "reference_MedicationAdministration", - ToType: "CodeableReference", + "Observation|result|DiagnosticReport": { + FromType: "Observation", + EdgeLabel: "result", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "result_diagnostic_report", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Observation/*", }, }, - "CodeableReference|reference_MedicationStatement|MedicationStatement": { - FromType: "CodeableReference", - EdgeLabel: "reference_MedicationStatement", - ToType: "MedicationStatement", + "DiagnosticReport|resultsInterpreter_Practitioner|Practitioner": { + FromType: "DiagnosticReport", + EdgeLabel: "resultsInterpreter_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "resultsInterpreter_diagnostic_report", }, RegexMatch: []string{ - "MedicationStatement/*", + "Practitioner/*", }, }, - "MedicationStatement|reference_MedicationStatement|CodeableReference": { - FromType: "MedicationStatement", - EdgeLabel: "reference_MedicationStatement", - ToType: "CodeableReference", + "Practitioner|resultsInterpreter_Practitioner|DiagnosticReport": { + FromType: "Practitioner", + EdgeLabel: "resultsInterpreter_Practitioner", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "resultsInterpreter_diagnostic_report", }, RegexMatch: []string{ - "MedicationStatement/*", + "Practitioner/*", }, }, - "CodeableReference|reference_MedicationRequest|MedicationRequest": { - FromType: "CodeableReference", - EdgeLabel: "reference_MedicationRequest", - ToType: "MedicationRequest", + "DiagnosticReport|resultsInterpreter_PractitionerRole|PractitionerRole": { + FromType: "DiagnosticReport", + EdgeLabel: "resultsInterpreter_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "resultsInterpreter_diagnostic_report", }, RegexMatch: []string{ - "MedicationRequest/*", + "PractitionerRole/*", }, }, - "MedicationRequest|reference_MedicationRequest|CodeableReference": { - FromType: "MedicationRequest", - EdgeLabel: "reference_MedicationRequest", - ToType: "CodeableReference", + "PractitionerRole|resultsInterpreter_PractitionerRole|DiagnosticReport": { + FromType: "PractitionerRole", + EdgeLabel: "resultsInterpreter_PractitionerRole", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "resultsInterpreter_diagnostic_report", }, RegexMatch: []string{ - "MedicationRequest/*", + "PractitionerRole/*", }, }, - "CodeableReference|reference_Procedure|Procedure": { - FromType: "CodeableReference", - EdgeLabel: "reference_Procedure", - ToType: "Procedure", + "DiagnosticReport|resultsInterpreter_Organization|Organization": { + FromType: "DiagnosticReport", + EdgeLabel: "resultsInterpreter_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "resultsInterpreter_diagnostic_report", }, RegexMatch: []string{ - "Procedure/*", + "Organization/*", }, }, - "Procedure|reference_Procedure|CodeableReference": { - FromType: "Procedure", - EdgeLabel: "reference_Procedure", - ToType: "CodeableReference", + "Organization|resultsInterpreter_Organization|DiagnosticReport": { + FromType: "Organization", + EdgeLabel: "resultsInterpreter_Organization", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "resultsInterpreter_diagnostic_report", }, RegexMatch: []string{ - "Procedure/*", + "Organization/*", }, }, - "CodeableReference|reference_DocumentReference|DocumentReference": { - FromType: "CodeableReference", - EdgeLabel: "reference_DocumentReference", - ToType: "DocumentReference", + "DiagnosticReport|specimen|Specimen": { + FromType: "DiagnosticReport", + EdgeLabel: "specimen", + ToType: "Specimen", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "specimen_diagnostic_report", }, RegexMatch: []string{ - "DocumentReference/*", + "Specimen/*", }, }, - "DocumentReference|reference_DocumentReference|CodeableReference": { - FromType: "DocumentReference", - EdgeLabel: "reference_DocumentReference", - ToType: "CodeableReference", + "Specimen|specimen|DiagnosticReport": { + FromType: "Specimen", + EdgeLabel: "specimen", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "specimen_diagnostic_report", }, RegexMatch: []string{ - "DocumentReference/*", + "Specimen/*", }, }, - "CodeableReference|reference_Task|Task": { - FromType: "CodeableReference", - EdgeLabel: "reference_Task", - ToType: "Task", + "DiagnosticReport|study_ImagingStudy|ImagingStudy": { + FromType: "DiagnosticReport", + EdgeLabel: "study_ImagingStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "study_diagnostic_report", }, RegexMatch: []string{ - "Task/*", + "ImagingStudy/*", }, }, - "Task|reference_Task|CodeableReference": { - FromType: "Task", - EdgeLabel: "reference_Task", - ToType: "CodeableReference", + "ImagingStudy|study_ImagingStudy|DiagnosticReport": { + FromType: "ImagingStudy", + EdgeLabel: "study_ImagingStudy", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "study_diagnostic_report", }, RegexMatch: []string{ - "Task/*", + "ImagingStudy/*", }, }, - "CodeableReference|reference_ImagingStudy|ImagingStudy": { - FromType: "CodeableReference", - EdgeLabel: "reference_ImagingStudy", - ToType: "ImagingStudy", + "DiagnosticReport|subject_Patient|Patient": { + FromType: "DiagnosticReport", + EdgeLabel: "subject_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -14639,16 +14554,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_diagnostic_report", }, RegexMatch: []string{ - "ImagingStudy/*", + "Patient/*", }, }, - "ImagingStudy|reference_ImagingStudy|CodeableReference": { - FromType: "ImagingStudy", - EdgeLabel: "reference_ImagingStudy", - ToType: "CodeableReference", + "Patient|subject_Patient|DiagnosticReport": { + FromType: "Patient", + EdgeLabel: "subject_Patient", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -14656,16 +14571,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_diagnostic_report", }, RegexMatch: []string{ - "ImagingStudy/*", + "Patient/*", }, }, - "CodeableReference|reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "CodeableReference", - EdgeLabel: "reference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", + "DiagnosticReport|subject_Group|Group": { + FromType: "DiagnosticReport", + EdgeLabel: "subject_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -14673,16 +14588,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_diagnostic_report", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Group/*", }, }, - "FamilyMemberHistory|reference_FamilyMemberHistory|CodeableReference": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reference_FamilyMemberHistory", - ToType: "CodeableReference", + "Group|subject_Group|DiagnosticReport": { + FromType: "Group", + EdgeLabel: "subject_Group", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -14690,16 +14605,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_diagnostic_report", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Group/*", }, }, - "CodeableReference|reference_BodyStructure|BodyStructure": { - FromType: "CodeableReference", - EdgeLabel: "reference_BodyStructure", - ToType: "BodyStructure", + "DiagnosticReport|subject_Organization|Organization": { + FromType: "DiagnosticReport", + EdgeLabel: "subject_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -14707,16 +14622,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_diagnostic_report", }, RegexMatch: []string{ - "BodyStructure/*", + "Organization/*", }, }, - "BodyStructure|reference_BodyStructure|CodeableReference": { - FromType: "BodyStructure", - EdgeLabel: "reference_BodyStructure", - ToType: "CodeableReference", + "Organization|subject_Organization|DiagnosticReport": { + FromType: "Organization", + EdgeLabel: "subject_Organization", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -14724,16 +14639,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_diagnostic_report", }, RegexMatch: []string{ - "BodyStructure/*", + "Organization/*", }, }, - "Condition|subject_Patient|Patient": { - FromType: "Condition", - EdgeLabel: "subject_Patient", - ToType: "Patient", + "DiagnosticReport|subject_Practitioner|Practitioner": { + FromType: "DiagnosticReport", + EdgeLabel: "subject_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -14741,16 +14656,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition", + "subject_diagnostic_report", }, RegexMatch: []string{ - "Patient/*", + "Practitioner/*", }, }, - "Patient|subject_Patient|Condition": { - FromType: "Patient", - EdgeLabel: "subject_Patient", - ToType: "Condition", + "Practitioner|subject_Practitioner|DiagnosticReport": { + FromType: "Practitioner", + EdgeLabel: "subject_Practitioner", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -14758,16 +14673,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition", + "subject_diagnostic_report", }, RegexMatch: []string{ - "Patient/*", + "Practitioner/*", }, }, - "Condition|subject_Group|Group": { - FromType: "Condition", - EdgeLabel: "subject_Group", - ToType: "Group", + "DiagnosticReport|subject_Medication|Medication": { + FromType: "DiagnosticReport", + EdgeLabel: "subject_Medication", + ToType: "Medication", Direction: []string{ "outbound", }, @@ -14775,16 +14690,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition", + "subject_diagnostic_report", }, RegexMatch: []string{ - "Group/*", + "Medication/*", }, }, - "Group|subject_Group|Condition": { - FromType: "Group", - EdgeLabel: "subject_Group", - ToType: "Condition", + "Medication|subject_Medication|DiagnosticReport": { + FromType: "Medication", + EdgeLabel: "subject_Medication", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -14792,16 +14707,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition", + "subject_diagnostic_report", }, RegexMatch: []string{ - "Group/*", + "Medication/*", }, }, - "Condition|evidence_reference_Organization|Organization": { - FromType: "Condition", - EdgeLabel: "evidence_reference_Organization", - ToType: "Organization", + "DiagnosticReport|subject_Substance|Substance": { + FromType: "DiagnosticReport", + EdgeLabel: "subject_Substance", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -14809,16 +14724,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_diagnostic_report", }, RegexMatch: []string{ - "Organization/*", + "Substance/*", }, }, - "Organization|evidence_reference_Organization|Condition": { - FromType: "Organization", - EdgeLabel: "evidence_reference_Organization", - ToType: "Condition", + "Substance|subject_Substance|DiagnosticReport": { + FromType: "Substance", + EdgeLabel: "subject_Substance", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -14826,16 +14741,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_diagnostic_report", }, RegexMatch: []string{ - "Organization/*", + "Substance/*", }, }, - "Condition|evidence_reference_Group|Group": { - FromType: "Condition", - EdgeLabel: "evidence_reference_Group", - ToType: "Group", + "DiagnosticReport|media_link|DocumentReference": { + FromType: "DiagnosticReport", + EdgeLabel: "media_link", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -14843,16 +14758,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "diagnostic_report_media", }, RegexMatch: []string{ - "Group/*", + "DocumentReference/*", }, }, - "Group|evidence_reference_Group|Condition": { - FromType: "Group", - EdgeLabel: "evidence_reference_Group", - ToType: "Condition", + "DocumentReference|media_link|DiagnosticReport": { + FromType: "DocumentReference", + EdgeLabel: "media_link", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -14860,15 +14775,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "diagnostic_report_media", }, RegexMatch: []string{ - "Group/*", + "DocumentReference/*", }, }, - "Condition|evidence_reference_Practitioner|Practitioner": { - FromType: "Condition", - EdgeLabel: "evidence_reference_Practitioner", + "DiagnosticReport|note_authorReference_Practitioner|Practitioner": { + FromType: "DiagnosticReport", + EdgeLabel: "note_authorReference_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", @@ -14877,16 +14792,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Practitioner|evidence_reference_Practitioner|Condition": { + "Practitioner|note_authorReference_Practitioner|DiagnosticReport": { FromType: "Practitioner", - EdgeLabel: "evidence_reference_Practitioner", - ToType: "Condition", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -14894,15 +14809,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Condition|evidence_reference_PractitionerRole|PractitionerRole": { - FromType: "Condition", - EdgeLabel: "evidence_reference_PractitionerRole", + "DiagnosticReport|note_authorReference_PractitionerRole|PractitionerRole": { + FromType: "DiagnosticReport", + EdgeLabel: "note_authorReference_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", @@ -14911,16 +14826,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "PractitionerRole|evidence_reference_PractitionerRole|Condition": { + "PractitionerRole|note_authorReference_PractitionerRole|DiagnosticReport": { FromType: "PractitionerRole", - EdgeLabel: "evidence_reference_PractitionerRole", - ToType: "Condition", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -14928,16 +14843,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "Condition|evidence_reference_ResearchStudy|ResearchStudy": { - FromType: "Condition", - EdgeLabel: "evidence_reference_ResearchStudy", - ToType: "ResearchStudy", + "DiagnosticReport|note_authorReference_Patient|Patient": { + FromType: "DiagnosticReport", + EdgeLabel: "note_authorReference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -14945,16 +14860,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "ResearchStudy/*", + "Patient/*", }, }, - "ResearchStudy|evidence_reference_ResearchStudy|Condition": { - FromType: "ResearchStudy", - EdgeLabel: "evidence_reference_ResearchStudy", - ToType: "Condition", + "Patient|note_authorReference_Patient|DiagnosticReport": { + FromType: "Patient", + EdgeLabel: "note_authorReference_Patient", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -14962,16 +14877,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "ResearchStudy/*", + "Patient/*", }, }, - "Condition|evidence_reference_Patient|Patient": { - FromType: "Condition", - EdgeLabel: "evidence_reference_Patient", - ToType: "Patient", + "DiagnosticReport|note_authorReference_Organization|Organization": { + FromType: "DiagnosticReport", + EdgeLabel: "note_authorReference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -14979,16 +14894,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Patient/*", + "Organization/*", }, }, - "Patient|evidence_reference_Patient|Condition": { - FromType: "Patient", - EdgeLabel: "evidence_reference_Patient", - ToType: "Condition", + "Organization|note_authorReference_Organization|DiagnosticReport": { + FromType: "Organization", + EdgeLabel: "note_authorReference_Organization", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -14996,16 +14911,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Patient/*", + "Organization/*", }, }, - "Condition|evidence_reference_ResearchSubject|ResearchSubject": { - FromType: "Condition", - EdgeLabel: "evidence_reference_ResearchSubject", - ToType: "ResearchSubject", + "DiagnosticReport|supportingInfo_reference_Procedure|Procedure": { + FromType: "DiagnosticReport", + EdgeLabel: "supportingInfo_reference_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -15013,16 +14928,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "diagnostic_report_supporting_info", }, RegexMatch: []string{ - "ResearchSubject/*", + "Procedure/*", }, }, - "ResearchSubject|evidence_reference_ResearchSubject|Condition": { - FromType: "ResearchSubject", - EdgeLabel: "evidence_reference_ResearchSubject", - ToType: "Condition", + "Procedure|supportingInfo_reference_Procedure|DiagnosticReport": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_reference_Procedure", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -15030,16 +14945,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "diagnostic_report_supporting_info", }, RegexMatch: []string{ - "ResearchSubject/*", + "Procedure/*", }, }, - "Condition|evidence_reference_Substance|Substance": { - FromType: "Condition", - EdgeLabel: "evidence_reference_Substance", - ToType: "Substance", + "DiagnosticReport|supportingInfo_reference_Observation|Observation": { + FromType: "DiagnosticReport", + EdgeLabel: "supportingInfo_reference_Observation", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -15047,16 +14962,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "diagnostic_report_supporting_info", }, RegexMatch: []string{ - "Substance/*", + "Observation/*", }, }, - "Substance|evidence_reference_Substance|Condition": { - FromType: "Substance", - EdgeLabel: "evidence_reference_Substance", - ToType: "Condition", + "Observation|supportingInfo_reference_Observation|DiagnosticReport": { + FromType: "Observation", + EdgeLabel: "supportingInfo_reference_Observation", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -15064,16 +14979,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "diagnostic_report_supporting_info", }, RegexMatch: []string{ - "Substance/*", + "Observation/*", }, }, - "Condition|evidence_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "Condition", - EdgeLabel: "evidence_reference_SubstanceDefinition", - ToType: "SubstanceDefinition", + "DiagnosticReport|supportingInfo_reference_DiagnosticReport|DiagnosticReport": { + FromType: "DiagnosticReport", + EdgeLabel: "supportingInfo_reference_DiagnosticReport", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -15081,186 +14996,186 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "diagnostic_report_supporting_info", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "DiagnosticReport/*", }, }, - "SubstanceDefinition|evidence_reference_SubstanceDefinition|Condition": { - FromType: "SubstanceDefinition", - EdgeLabel: "evidence_reference_SubstanceDefinition", - ToType: "Condition", + "DocumentReference|author_Practitioner|Practitioner": { + FromType: "DocumentReference", + EdgeLabel: "author_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "author_document_reference", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "Practitioner/*", }, }, - "Condition|evidence_reference_Specimen|Specimen": { - FromType: "Condition", - EdgeLabel: "evidence_reference_Specimen", - ToType: "Specimen", + "Practitioner|author_Practitioner|DocumentReference": { + FromType: "Practitioner", + EdgeLabel: "author_Practitioner", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "author_document_reference", }, RegexMatch: []string{ - "Specimen/*", + "Practitioner/*", }, }, - "Specimen|evidence_reference_Specimen|Condition": { - FromType: "Specimen", - EdgeLabel: "evidence_reference_Specimen", - ToType: "Condition", + "DocumentReference|author_PractitionerRole|PractitionerRole": { + FromType: "DocumentReference", + EdgeLabel: "author_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "author_document_reference", }, RegexMatch: []string{ - "Specimen/*", + "PractitionerRole/*", }, }, - "Condition|evidence_reference_Observation|Observation": { - FromType: "Condition", - EdgeLabel: "evidence_reference_Observation", - ToType: "Observation", + "PractitionerRole|author_PractitionerRole|DocumentReference": { + FromType: "PractitionerRole", + EdgeLabel: "author_PractitionerRole", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "author_document_reference", }, RegexMatch: []string{ - "Observation/*", + "PractitionerRole/*", }, }, - "Observation|evidence_reference_Observation|Condition": { - FromType: "Observation", - EdgeLabel: "evidence_reference_Observation", - ToType: "Condition", + "DocumentReference|author_Organization|Organization": { + FromType: "DocumentReference", + EdgeLabel: "author_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "author_document_reference", }, RegexMatch: []string{ - "Observation/*", + "Organization/*", }, }, - "Condition|evidence_reference_DiagnosticReport|DiagnosticReport": { - FromType: "Condition", - EdgeLabel: "evidence_reference_DiagnosticReport", - ToType: "DiagnosticReport", + "Organization|author_Organization|DocumentReference": { + FromType: "Organization", + EdgeLabel: "author_Organization", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "author_document_reference", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Organization/*", }, }, - "DiagnosticReport|evidence_reference_DiagnosticReport|Condition": { - FromType: "DiagnosticReport", - EdgeLabel: "evidence_reference_DiagnosticReport", - ToType: "Condition", + "DocumentReference|author_Patient|Patient": { + FromType: "DocumentReference", + EdgeLabel: "author_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "author_document_reference", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Patient/*", }, }, - "Condition|evidence_reference_Condition|Condition": { - FromType: "Condition", - EdgeLabel: "evidence_reference_Condition", - ToType: "Condition", + "Patient|author_Patient|DocumentReference": { + FromType: "Patient", + EdgeLabel: "author_Patient", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "author_document_reference", }, RegexMatch: []string{ - "Condition/*", + "Patient/*", }, }, - "Condition|evidence_reference_Medication|Medication": { - FromType: "Condition", - EdgeLabel: "evidence_reference_Medication", - ToType: "Medication", + "DocumentReference|basedOn_MedicationRequest|MedicationRequest": { + FromType: "DocumentReference", + EdgeLabel: "basedOn_MedicationRequest", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_document_reference", }, RegexMatch: []string{ - "Medication/*", + "MedicationRequest/*", }, }, - "Medication|evidence_reference_Medication|Condition": { - FromType: "Medication", - EdgeLabel: "evidence_reference_Medication", - ToType: "Condition", + "MedicationRequest|basedOn_MedicationRequest|DocumentReference": { + FromType: "MedicationRequest", + EdgeLabel: "basedOn_MedicationRequest", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_document_reference", }, RegexMatch: []string{ - "Medication/*", + "MedicationRequest/*", }, }, - "Condition|evidence_reference_MedicationAdministration|MedicationAdministration": { - FromType: "Condition", - EdgeLabel: "evidence_reference_MedicationAdministration", - ToType: "MedicationAdministration", + "DocumentReference|custodian|Organization": { + FromType: "DocumentReference", + EdgeLabel: "custodian", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -15268,16 +15183,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "custodian_document_reference", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Organization/*", }, }, - "MedicationAdministration|evidence_reference_MedicationAdministration|Condition": { - FromType: "MedicationAdministration", - EdgeLabel: "evidence_reference_MedicationAdministration", - ToType: "Condition", + "Organization|custodian|DocumentReference": { + FromType: "Organization", + EdgeLabel: "custodian", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15285,16 +15200,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "custodian_document_reference", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Organization/*", }, }, - "Condition|evidence_reference_MedicationStatement|MedicationStatement": { - FromType: "Condition", - EdgeLabel: "evidence_reference_MedicationStatement", - ToType: "MedicationStatement", + "DocumentReference|subject_Organization|Organization": { + FromType: "DocumentReference", + EdgeLabel: "subject_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -15302,16 +15217,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "document_reference", }, RegexMatch: []string{ - "MedicationStatement/*", + "Organization/*", }, }, - "MedicationStatement|evidence_reference_MedicationStatement|Condition": { - FromType: "MedicationStatement", - EdgeLabel: "evidence_reference_MedicationStatement", - ToType: "Condition", + "Organization|subject_Organization|DocumentReference": { + FromType: "Organization", + EdgeLabel: "subject_Organization", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15319,16 +15234,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "document_reference", }, RegexMatch: []string{ - "MedicationStatement/*", + "Organization/*", }, }, - "Condition|evidence_reference_MedicationRequest|MedicationRequest": { - FromType: "Condition", - EdgeLabel: "evidence_reference_MedicationRequest", - ToType: "MedicationRequest", + "DocumentReference|subject_Group|Group": { + FromType: "DocumentReference", + EdgeLabel: "subject_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -15336,16 +15251,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "document_reference", }, RegexMatch: []string{ - "MedicationRequest/*", + "Group/*", }, }, - "MedicationRequest|evidence_reference_MedicationRequest|Condition": { - FromType: "MedicationRequest", - EdgeLabel: "evidence_reference_MedicationRequest", - ToType: "Condition", + "Group|subject_Group|DocumentReference": { + FromType: "Group", + EdgeLabel: "subject_Group", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15353,16 +15268,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "document_reference", }, RegexMatch: []string{ - "MedicationRequest/*", + "Group/*", }, }, - "Condition|evidence_reference_Procedure|Procedure": { - FromType: "Condition", - EdgeLabel: "evidence_reference_Procedure", - ToType: "Procedure", + "DocumentReference|subject_Practitioner|Practitioner": { + FromType: "DocumentReference", + EdgeLabel: "subject_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -15370,16 +15285,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "document_reference", }, RegexMatch: []string{ - "Procedure/*", + "Practitioner/*", }, }, - "Procedure|evidence_reference_Procedure|Condition": { - FromType: "Procedure", - EdgeLabel: "evidence_reference_Procedure", - ToType: "Condition", + "Practitioner|subject_Practitioner|DocumentReference": { + FromType: "Practitioner", + EdgeLabel: "subject_Practitioner", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15387,16 +15302,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "document_reference", }, RegexMatch: []string{ - "Procedure/*", + "Practitioner/*", }, }, - "Condition|evidence_reference_DocumentReference|DocumentReference": { - FromType: "Condition", - EdgeLabel: "evidence_reference_DocumentReference", - ToType: "DocumentReference", + "DocumentReference|subject_PractitionerRole|PractitionerRole": { + FromType: "DocumentReference", + EdgeLabel: "subject_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -15404,16 +15319,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "document_reference", }, RegexMatch: []string{ - "DocumentReference/*", + "PractitionerRole/*", }, }, - "DocumentReference|evidence_reference_DocumentReference|Condition": { - FromType: "DocumentReference", - EdgeLabel: "evidence_reference_DocumentReference", - ToType: "Condition", + "PractitionerRole|subject_PractitionerRole|DocumentReference": { + FromType: "PractitionerRole", + EdgeLabel: "subject_PractitionerRole", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15421,16 +15336,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "document_reference", }, RegexMatch: []string{ - "DocumentReference/*", + "PractitionerRole/*", }, }, - "Condition|evidence_reference_Task|Task": { - FromType: "Condition", - EdgeLabel: "evidence_reference_Task", - ToType: "Task", + "DocumentReference|subject_ResearchStudy|ResearchStudy": { + FromType: "DocumentReference", + EdgeLabel: "subject_ResearchStudy", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -15438,16 +15353,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "document_reference", }, RegexMatch: []string{ - "Task/*", + "ResearchStudy/*", }, }, - "Task|evidence_reference_Task|Condition": { - FromType: "Task", - EdgeLabel: "evidence_reference_Task", - ToType: "Condition", + "ResearchStudy|subject_ResearchStudy|DocumentReference": { + FromType: "ResearchStudy", + EdgeLabel: "subject_ResearchStudy", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15455,16 +15370,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "document_reference", }, RegexMatch: []string{ - "Task/*", + "ResearchStudy/*", }, }, - "Condition|evidence_reference_ImagingStudy|ImagingStudy": { - FromType: "Condition", - EdgeLabel: "evidence_reference_ImagingStudy", - ToType: "ImagingStudy", + "DocumentReference|subject_Patient|Patient": { + FromType: "DocumentReference", + EdgeLabel: "subject_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -15472,16 +15387,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "document_reference", }, RegexMatch: []string{ - "ImagingStudy/*", + "Patient/*", }, }, - "ImagingStudy|evidence_reference_ImagingStudy|Condition": { - FromType: "ImagingStudy", - EdgeLabel: "evidence_reference_ImagingStudy", - ToType: "Condition", + "Patient|subject_Patient|DocumentReference": { + FromType: "Patient", + EdgeLabel: "subject_Patient", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15489,16 +15404,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "document_reference", }, RegexMatch: []string{ - "ImagingStudy/*", + "Patient/*", }, }, - "Condition|evidence_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "Condition", - EdgeLabel: "evidence_reference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", + "DocumentReference|subject_ResearchSubject|ResearchSubject": { + FromType: "DocumentReference", + EdgeLabel: "subject_ResearchSubject", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, @@ -15506,16 +15421,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "document_reference", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "ResearchSubject/*", }, }, - "FamilyMemberHistory|evidence_reference_FamilyMemberHistory|Condition": { - FromType: "FamilyMemberHistory", - EdgeLabel: "evidence_reference_FamilyMemberHistory", - ToType: "Condition", + "ResearchSubject|subject_ResearchSubject|DocumentReference": { + FromType: "ResearchSubject", + EdgeLabel: "subject_ResearchSubject", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15523,16 +15438,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "document_reference", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "ResearchSubject/*", }, }, - "Condition|evidence_reference_BodyStructure|BodyStructure": { - FromType: "Condition", - EdgeLabel: "evidence_reference_BodyStructure", - ToType: "BodyStructure", + "DocumentReference|subject_Substance|Substance": { + FromType: "DocumentReference", + EdgeLabel: "subject_Substance", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -15540,16 +15455,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "document_reference", }, RegexMatch: []string{ - "BodyStructure/*", + "Substance/*", }, }, - "BodyStructure|evidence_reference_BodyStructure|Condition": { - FromType: "BodyStructure", - EdgeLabel: "evidence_reference_BodyStructure", - ToType: "Condition", + "Substance|subject_Substance|DocumentReference": { + FromType: "Substance", + EdgeLabel: "subject_Substance", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15557,16 +15472,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "document_reference", }, RegexMatch: []string{ - "BodyStructure/*", + "Substance/*", }, }, - "Condition|note_authorReference_Practitioner|Practitioner": { - FromType: "Condition", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "Practitioner", + "DocumentReference|subject_SubstanceDefinition|SubstanceDefinition": { + FromType: "DocumentReference", + EdgeLabel: "subject_SubstanceDefinition", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, @@ -15574,16 +15489,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "document_reference", }, RegexMatch: []string{ - "Practitioner/*", + "SubstanceDefinition/*", }, }, - "Practitioner|note_authorReference_Practitioner|Condition": { - FromType: "Practitioner", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "Condition", + "SubstanceDefinition|subject_SubstanceDefinition|DocumentReference": { + FromType: "SubstanceDefinition", + EdgeLabel: "subject_SubstanceDefinition", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15591,16 +15506,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "document_reference", }, RegexMatch: []string{ - "Practitioner/*", + "SubstanceDefinition/*", }, }, - "Condition|note_authorReference_PractitionerRole|PractitionerRole": { - FromType: "Condition", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "PractitionerRole", + "DocumentReference|subject_Specimen|Specimen": { + FromType: "DocumentReference", + EdgeLabel: "subject_Specimen", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -15608,16 +15523,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "document_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Specimen/*", }, }, - "PractitionerRole|note_authorReference_PractitionerRole|Condition": { - FromType: "PractitionerRole", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "Condition", + "Specimen|subject_Specimen|DocumentReference": { + FromType: "Specimen", + EdgeLabel: "subject_Specimen", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15625,16 +15540,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "document_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Specimen/*", }, }, - "Condition|note_authorReference_Patient|Patient": { - FromType: "Condition", - EdgeLabel: "note_authorReference_Patient", - ToType: "Patient", + "DocumentReference|subject_Observation|Observation": { + FromType: "DocumentReference", + EdgeLabel: "subject_Observation", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -15642,16 +15557,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "document_reference", }, RegexMatch: []string{ - "Patient/*", + "Observation/*", }, }, - "Patient|note_authorReference_Patient|Condition": { - FromType: "Patient", - EdgeLabel: "note_authorReference_Patient", - ToType: "Condition", + "Observation|subject_Observation|DocumentReference": { + FromType: "Observation", + EdgeLabel: "subject_Observation", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15659,16 +15574,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "document_reference", }, RegexMatch: []string{ - "Patient/*", + "Observation/*", }, }, - "Condition|note_authorReference_Organization|Organization": { - FromType: "Condition", - EdgeLabel: "note_authorReference_Organization", - ToType: "Organization", + "DocumentReference|subject_DiagnosticReport|DiagnosticReport": { + FromType: "DocumentReference", + EdgeLabel: "subject_DiagnosticReport", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -15676,16 +15591,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "document_reference", }, RegexMatch: []string{ - "Organization/*", + "DiagnosticReport/*", }, }, - "Organization|note_authorReference_Organization|Condition": { - FromType: "Organization", - EdgeLabel: "note_authorReference_Organization", - ToType: "Condition", + "DiagnosticReport|subject_DiagnosticReport|DocumentReference": { + FromType: "DiagnosticReport", + EdgeLabel: "subject_DiagnosticReport", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15693,16 +15608,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "document_reference", }, RegexMatch: []string{ - "Organization/*", + "DiagnosticReport/*", }, }, - "Condition|participant_actor_Practitioner|Practitioner": { - FromType: "Condition", - EdgeLabel: "participant_actor_Practitioner", - ToType: "Practitioner", + "DocumentReference|subject_Condition|Condition": { + FromType: "DocumentReference", + EdgeLabel: "subject_Condition", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -15710,16 +15625,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition_participant", + "document_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Condition/*", }, }, - "Practitioner|participant_actor_Practitioner|Condition": { - FromType: "Practitioner", - EdgeLabel: "participant_actor_Practitioner", - ToType: "Condition", + "Condition|subject_Condition|DocumentReference": { + FromType: "Condition", + EdgeLabel: "subject_Condition", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15727,16 +15642,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition_participant", + "document_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Condition/*", }, }, - "Condition|participant_actor_PractitionerRole|PractitionerRole": { - FromType: "Condition", - EdgeLabel: "participant_actor_PractitionerRole", - ToType: "PractitionerRole", + "DocumentReference|subject_Medication|Medication": { + FromType: "DocumentReference", + EdgeLabel: "subject_Medication", + ToType: "Medication", Direction: []string{ "outbound", }, @@ -15744,16 +15659,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition_participant", + "document_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Medication/*", }, }, - "PractitionerRole|participant_actor_PractitionerRole|Condition": { - FromType: "PractitionerRole", - EdgeLabel: "participant_actor_PractitionerRole", - ToType: "Condition", + "Medication|subject_Medication|DocumentReference": { + FromType: "Medication", + EdgeLabel: "subject_Medication", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15761,16 +15676,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition_participant", + "document_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Medication/*", }, }, - "Condition|participant_actor_Patient|Patient": { - FromType: "Condition", - EdgeLabel: "participant_actor_Patient", - ToType: "Patient", + "DocumentReference|subject_MedicationAdministration|MedicationAdministration": { + FromType: "DocumentReference", + EdgeLabel: "subject_MedicationAdministration", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -15778,16 +15693,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition_participant", + "document_reference", }, RegexMatch: []string{ - "Patient/*", + "MedicationAdministration/*", }, }, - "Patient|participant_actor_Patient|Condition": { - FromType: "Patient", - EdgeLabel: "participant_actor_Patient", - ToType: "Condition", + "MedicationAdministration|subject_MedicationAdministration|DocumentReference": { + FromType: "MedicationAdministration", + EdgeLabel: "subject_MedicationAdministration", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15795,16 +15710,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition_participant", + "document_reference", }, RegexMatch: []string{ - "Patient/*", + "MedicationAdministration/*", }, }, - "Condition|participant_actor_Organization|Organization": { - FromType: "Condition", - EdgeLabel: "participant_actor_Organization", - ToType: "Organization", + "DocumentReference|subject_MedicationStatement|MedicationStatement": { + FromType: "DocumentReference", + EdgeLabel: "subject_MedicationStatement", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -15812,16 +15727,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition_participant", + "document_reference", }, RegexMatch: []string{ - "Organization/*", + "MedicationStatement/*", }, }, - "Organization|participant_actor_Organization|Condition": { - FromType: "Organization", - EdgeLabel: "participant_actor_Organization", - ToType: "Condition", + "MedicationStatement|subject_MedicationStatement|DocumentReference": { + FromType: "MedicationStatement", + EdgeLabel: "subject_MedicationStatement", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15829,84 +15744,84 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition_participant", + "document_reference", }, RegexMatch: []string{ - "Organization/*", + "MedicationStatement/*", }, }, - "Condition|stage_assessment_DiagnosticReport|DiagnosticReport": { - FromType: "Condition", - EdgeLabel: "stage_assessment_DiagnosticReport", - ToType: "DiagnosticReport", + "DocumentReference|subject_MedicationRequest|MedicationRequest": { + FromType: "DocumentReference", + EdgeLabel: "subject_MedicationRequest", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "assessment_condition_stage", + "document_reference", }, RegexMatch: []string{ - "DiagnosticReport/*", + "MedicationRequest/*", }, }, - "DiagnosticReport|stage_assessment_DiagnosticReport|Condition": { - FromType: "DiagnosticReport", - EdgeLabel: "stage_assessment_DiagnosticReport", - ToType: "Condition", + "MedicationRequest|subject_MedicationRequest|DocumentReference": { + FromType: "MedicationRequest", + EdgeLabel: "subject_MedicationRequest", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "assessment_condition_stage", + "document_reference", }, RegexMatch: []string{ - "DiagnosticReport/*", + "MedicationRequest/*", }, }, - "Condition|stage_assessment_Observation|Observation": { - FromType: "Condition", - EdgeLabel: "stage_assessment_Observation", - ToType: "Observation", + "DocumentReference|subject_Procedure|Procedure": { + FromType: "DocumentReference", + EdgeLabel: "subject_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "assessment_condition_stage", + "document_reference", }, RegexMatch: []string{ - "Observation/*", + "Procedure/*", }, }, - "Observation|stage_assessment_Observation|Condition": { - FromType: "Observation", - EdgeLabel: "stage_assessment_Observation", - ToType: "Condition", + "Procedure|subject_Procedure|DocumentReference": { + FromType: "Procedure", + EdgeLabel: "subject_Procedure", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "assessment_condition_stage", + "document_reference", }, RegexMatch: []string{ - "Observation/*", + "Procedure/*", }, }, - "ConditionParticipant|actor_Practitioner|Practitioner": { - FromType: "ConditionParticipant", - EdgeLabel: "actor_Practitioner", - ToType: "Practitioner", + "DocumentReference|subject_DocumentReference|DocumentReference": { + FromType: "DocumentReference", + EdgeLabel: "subject_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15914,16 +15829,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition_participant", + "document_reference", }, RegexMatch: []string{ - "Practitioner/*", + "DocumentReference/*", }, }, - "Practitioner|actor_Practitioner|ConditionParticipant": { - FromType: "Practitioner", - EdgeLabel: "actor_Practitioner", - ToType: "ConditionParticipant", + "DocumentReference|subject_Task|Task": { + FromType: "DocumentReference", + EdgeLabel: "subject_Task", + ToType: "Task", Direction: []string{ "outbound", }, @@ -15931,16 +15846,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition_participant", + "document_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Task/*", }, }, - "ConditionParticipant|actor_PractitionerRole|PractitionerRole": { - FromType: "ConditionParticipant", - EdgeLabel: "actor_PractitionerRole", - ToType: "PractitionerRole", + "Task|subject_Task|DocumentReference": { + FromType: "Task", + EdgeLabel: "subject_Task", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15948,16 +15863,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition_participant", + "document_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Task/*", }, }, - "PractitionerRole|actor_PractitionerRole|ConditionParticipant": { - FromType: "PractitionerRole", - EdgeLabel: "actor_PractitionerRole", - ToType: "ConditionParticipant", + "DocumentReference|subject_ImagingStudy|ImagingStudy": { + FromType: "DocumentReference", + EdgeLabel: "subject_ImagingStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -15965,16 +15880,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition_participant", + "document_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "ImagingStudy/*", }, }, - "ConditionParticipant|actor_Patient|Patient": { - FromType: "ConditionParticipant", - EdgeLabel: "actor_Patient", - ToType: "Patient", + "ImagingStudy|subject_ImagingStudy|DocumentReference": { + FromType: "ImagingStudy", + EdgeLabel: "subject_ImagingStudy", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -15982,16 +15897,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition_participant", + "document_reference", }, RegexMatch: []string{ - "Patient/*", + "ImagingStudy/*", }, }, - "Patient|actor_Patient|ConditionParticipant": { - FromType: "Patient", - EdgeLabel: "actor_Patient", - ToType: "ConditionParticipant", + "DocumentReference|subject_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "DocumentReference", + EdgeLabel: "subject_FamilyMemberHistory", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -15999,16 +15914,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition_participant", + "document_reference", }, RegexMatch: []string{ - "Patient/*", + "FamilyMemberHistory/*", }, }, - "ConditionParticipant|actor_Organization|Organization": { - FromType: "ConditionParticipant", - EdgeLabel: "actor_Organization", - ToType: "Organization", + "FamilyMemberHistory|subject_FamilyMemberHistory|DocumentReference": { + FromType: "FamilyMemberHistory", + EdgeLabel: "subject_FamilyMemberHistory", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -16016,16 +15931,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition_participant", + "document_reference", }, RegexMatch: []string{ - "Organization/*", + "FamilyMemberHistory/*", }, }, - "Organization|actor_Organization|ConditionParticipant": { - FromType: "Organization", - EdgeLabel: "actor_Organization", - ToType: "ConditionParticipant", + "DocumentReference|subject_BodyStructure|BodyStructure": { + FromType: "DocumentReference", + EdgeLabel: "subject_BodyStructure", + ToType: "BodyStructure", Direction: []string{ "outbound", }, @@ -16033,84 +15948,84 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "condition_participant", + "document_reference", }, RegexMatch: []string{ - "Organization/*", + "BodyStructure/*", }, }, - "ConditionStage|assessment_DiagnosticReport|DiagnosticReport": { - FromType: "ConditionStage", - EdgeLabel: "assessment_DiagnosticReport", - ToType: "DiagnosticReport", + "BodyStructure|subject_BodyStructure|DocumentReference": { + FromType: "BodyStructure", + EdgeLabel: "subject_BodyStructure", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "assessment_condition_stage", + "document_reference", }, RegexMatch: []string{ - "DiagnosticReport/*", + "BodyStructure/*", }, }, - "DiagnosticReport|assessment_DiagnosticReport|ConditionStage": { - FromType: "DiagnosticReport", - EdgeLabel: "assessment_DiagnosticReport", - ToType: "ConditionStage", + "DocumentReference|attester_party_Patient|Patient": { + FromType: "DocumentReference", + EdgeLabel: "attester_party_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "assessment_condition_stage", + "document_reference_attester", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Patient/*", }, }, - "ConditionStage|assessment_Observation|Observation": { - FromType: "ConditionStage", - EdgeLabel: "assessment_Observation", - ToType: "Observation", + "Patient|attester_party_Patient|DocumentReference": { + FromType: "Patient", + EdgeLabel: "attester_party_Patient", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "assessment_condition_stage", + "document_reference_attester", }, RegexMatch: []string{ - "Observation/*", + "Patient/*", }, }, - "Observation|assessment_Observation|ConditionStage": { - FromType: "Observation", - EdgeLabel: "assessment_Observation", - ToType: "ConditionStage", + "DocumentReference|attester_party_Practitioner|Practitioner": { + FromType: "DocumentReference", + EdgeLabel: "attester_party_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "assessment_condition_stage", + "document_reference_attester", }, RegexMatch: []string{ - "Observation/*", + "Practitioner/*", }, }, - "DataRequirement|subjectReference|Group": { - FromType: "DataRequirement", - EdgeLabel: "subjectReference", - ToType: "Group", + "Practitioner|attester_party_Practitioner|DocumentReference": { + FromType: "Practitioner", + EdgeLabel: "attester_party_Practitioner", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -16118,16 +16033,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "data_requirement", + "document_reference_attester", }, RegexMatch: []string{ - "Group/*", + "Practitioner/*", }, }, - "Group|subjectReference|DataRequirement": { - FromType: "Group", - EdgeLabel: "subjectReference", - ToType: "DataRequirement", + "DocumentReference|attester_party_PractitionerRole|PractitionerRole": { + FromType: "DocumentReference", + EdgeLabel: "attester_party_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -16135,356 +16050,356 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "data_requirement", + "document_reference_attester", }, RegexMatch: []string{ - "Group/*", + "PractitionerRole/*", }, }, - "DiagnosticReport|basedOn_MedicationRequest|MedicationRequest": { - FromType: "DiagnosticReport", - EdgeLabel: "basedOn_MedicationRequest", - ToType: "MedicationRequest", + "PractitionerRole|attester_party_PractitionerRole|DocumentReference": { + FromType: "PractitionerRole", + EdgeLabel: "attester_party_PractitionerRole", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_diagnostic_report", + "document_reference_attester", }, RegexMatch: []string{ - "MedicationRequest/*", + "PractitionerRole/*", }, }, - "MedicationRequest|basedOn_MedicationRequest|DiagnosticReport": { - FromType: "MedicationRequest", - EdgeLabel: "basedOn_MedicationRequest", - ToType: "DiagnosticReport", + "DocumentReference|attester_party_Organization|Organization": { + FromType: "DocumentReference", + EdgeLabel: "attester_party_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_diagnostic_report", + "document_reference_attester", }, RegexMatch: []string{ - "MedicationRequest/*", + "Organization/*", }, }, - "DiagnosticReport|performer_Practitioner|Practitioner": { - FromType: "DiagnosticReport", - EdgeLabel: "performer_Practitioner", - ToType: "Practitioner", + "Organization|attester_party_Organization|DocumentReference": { + FromType: "Organization", + EdgeLabel: "attester_party_Organization", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "performer_diagnostic_report", + "document_reference_attester", }, RegexMatch: []string{ - "Practitioner/*", + "Organization/*", }, }, - "Practitioner|performer_Practitioner|DiagnosticReport": { - FromType: "Practitioner", - EdgeLabel: "performer_Practitioner", - ToType: "DiagnosticReport", + "DocumentReference|bodySite_reference_Organization|Organization": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "performer_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Organization/*", }, }, - "DiagnosticReport|performer_PractitionerRole|PractitionerRole": { - FromType: "DiagnosticReport", - EdgeLabel: "performer_PractitionerRole", - ToType: "PractitionerRole", + "Organization|bodySite_reference_Organization|DocumentReference": { + FromType: "Organization", + EdgeLabel: "bodySite_reference_Organization", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "performer_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Organization/*", }, }, - "PractitionerRole|performer_PractitionerRole|DiagnosticReport": { - FromType: "PractitionerRole", - EdgeLabel: "performer_PractitionerRole", - ToType: "DiagnosticReport", + "DocumentReference|bodySite_reference_Group|Group": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_Group", + ToType: "Group", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "performer_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Group/*", }, }, - "DiagnosticReport|performer_Organization|Organization": { - FromType: "DiagnosticReport", - EdgeLabel: "performer_Organization", - ToType: "Organization", + "Group|bodySite_reference_Group|DocumentReference": { + FromType: "Group", + EdgeLabel: "bodySite_reference_Group", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "performer_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Group/*", }, }, - "Organization|performer_Organization|DiagnosticReport": { - FromType: "Organization", - EdgeLabel: "performer_Organization", - ToType: "DiagnosticReport", + "DocumentReference|bodySite_reference_Practitioner|Practitioner": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "performer_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Practitioner/*", }, }, - "DiagnosticReport|result|Observation": { - FromType: "DiagnosticReport", - EdgeLabel: "result", - ToType: "Observation", + "Practitioner|bodySite_reference_Practitioner|DocumentReference": { + FromType: "Practitioner", + EdgeLabel: "bodySite_reference_Practitioner", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "result_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Observation/*", + "Practitioner/*", }, }, - "Observation|result|DiagnosticReport": { - FromType: "Observation", - EdgeLabel: "result", - ToType: "DiagnosticReport", + "DocumentReference|bodySite_reference_PractitionerRole|PractitionerRole": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "result_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Observation/*", + "PractitionerRole/*", }, }, - "DiagnosticReport|resultsInterpreter_Practitioner|Practitioner": { - FromType: "DiagnosticReport", - EdgeLabel: "resultsInterpreter_Practitioner", - ToType: "Practitioner", + "PractitionerRole|bodySite_reference_PractitionerRole|DocumentReference": { + FromType: "PractitionerRole", + EdgeLabel: "bodySite_reference_PractitionerRole", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "resultsInterpreter_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "PractitionerRole/*", }, }, - "Practitioner|resultsInterpreter_Practitioner|DiagnosticReport": { - FromType: "Practitioner", - EdgeLabel: "resultsInterpreter_Practitioner", - ToType: "DiagnosticReport", + "DocumentReference|bodySite_reference_ResearchStudy|ResearchStudy": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_ResearchStudy", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "resultsInterpreter_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "ResearchStudy/*", }, }, - "DiagnosticReport|resultsInterpreter_PractitionerRole|PractitionerRole": { - FromType: "DiagnosticReport", - EdgeLabel: "resultsInterpreter_PractitionerRole", - ToType: "PractitionerRole", + "ResearchStudy|bodySite_reference_ResearchStudy|DocumentReference": { + FromType: "ResearchStudy", + EdgeLabel: "bodySite_reference_ResearchStudy", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "resultsInterpreter_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "ResearchStudy/*", }, }, - "PractitionerRole|resultsInterpreter_PractitionerRole|DiagnosticReport": { - FromType: "PractitionerRole", - EdgeLabel: "resultsInterpreter_PractitionerRole", - ToType: "DiagnosticReport", + "DocumentReference|bodySite_reference_Patient|Patient": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "resultsInterpreter_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Patient/*", }, }, - "DiagnosticReport|resultsInterpreter_Organization|Organization": { - FromType: "DiagnosticReport", - EdgeLabel: "resultsInterpreter_Organization", - ToType: "Organization", + "Patient|bodySite_reference_Patient|DocumentReference": { + FromType: "Patient", + EdgeLabel: "bodySite_reference_Patient", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "resultsInterpreter_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Patient/*", }, }, - "Organization|resultsInterpreter_Organization|DiagnosticReport": { - FromType: "Organization", - EdgeLabel: "resultsInterpreter_Organization", - ToType: "DiagnosticReport", + "DocumentReference|bodySite_reference_ResearchSubject|ResearchSubject": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_ResearchSubject", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "resultsInterpreter_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "ResearchSubject/*", }, }, - "DiagnosticReport|specimen|Specimen": { - FromType: "DiagnosticReport", - EdgeLabel: "specimen", - ToType: "Specimen", + "ResearchSubject|bodySite_reference_ResearchSubject|DocumentReference": { + FromType: "ResearchSubject", + EdgeLabel: "bodySite_reference_ResearchSubject", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "specimen_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Specimen/*", + "ResearchSubject/*", }, }, - "Specimen|specimen|DiagnosticReport": { - FromType: "Specimen", - EdgeLabel: "specimen", - ToType: "DiagnosticReport", + "DocumentReference|bodySite_reference_Substance|Substance": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_Substance", + ToType: "Substance", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "specimen_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Specimen/*", + "Substance/*", }, }, - "DiagnosticReport|study_ImagingStudy|ImagingStudy": { - FromType: "DiagnosticReport", - EdgeLabel: "study_ImagingStudy", - ToType: "ImagingStudy", + "Substance|bodySite_reference_Substance|DocumentReference": { + FromType: "Substance", + EdgeLabel: "bodySite_reference_Substance", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "study_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "ImagingStudy/*", + "Substance/*", }, }, - "ImagingStudy|study_ImagingStudy|DiagnosticReport": { - FromType: "ImagingStudy", - EdgeLabel: "study_ImagingStudy", - ToType: "DiagnosticReport", + "DocumentReference|bodySite_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_SubstanceDefinition", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "study_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "ImagingStudy/*", + "SubstanceDefinition/*", }, }, - "DiagnosticReport|subject_Patient|Patient": { - FromType: "DiagnosticReport", - EdgeLabel: "subject_Patient", - ToType: "Patient", + "SubstanceDefinition|bodySite_reference_SubstanceDefinition|DocumentReference": { + FromType: "SubstanceDefinition", + EdgeLabel: "bodySite_reference_SubstanceDefinition", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -16492,16 +16407,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "subject_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "SubstanceDefinition/*", }, }, - "Patient|subject_Patient|DiagnosticReport": { - FromType: "Patient", - EdgeLabel: "subject_Patient", - ToType: "DiagnosticReport", + "DocumentReference|bodySite_reference_Specimen|Specimen": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_Specimen", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -16509,16 +16424,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "subject_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "Specimen/*", }, }, - "DiagnosticReport|subject_Group|Group": { - FromType: "DiagnosticReport", - EdgeLabel: "subject_Group", - ToType: "Group", + "Specimen|bodySite_reference_Specimen|DocumentReference": { + FromType: "Specimen", + EdgeLabel: "bodySite_reference_Specimen", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -16526,16 +16441,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "subject_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "Specimen/*", }, }, - "Group|subject_Group|DiagnosticReport": { - FromType: "Group", - EdgeLabel: "subject_Group", - ToType: "DiagnosticReport", + "DocumentReference|bodySite_reference_Observation|Observation": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_Observation", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -16543,16 +16458,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "subject_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "Observation/*", }, }, - "DiagnosticReport|subject_Organization|Organization": { - FromType: "DiagnosticReport", - EdgeLabel: "subject_Organization", - ToType: "Organization", + "Observation|bodySite_reference_Observation|DocumentReference": { + FromType: "Observation", + EdgeLabel: "bodySite_reference_Observation", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -16560,15 +16475,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "subject_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Observation/*", }, }, - "Organization|subject_Organization|DiagnosticReport": { - FromType: "Organization", - EdgeLabel: "subject_Organization", + "DocumentReference|bodySite_reference_DiagnosticReport|DiagnosticReport": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -16577,16 +16492,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "subject_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "DiagnosticReport/*", }, }, - "DiagnosticReport|subject_Practitioner|Practitioner": { + "DiagnosticReport|bodySite_reference_DiagnosticReport|DocumentReference": { FromType: "DiagnosticReport", - EdgeLabel: "subject_Practitioner", - ToType: "Practitioner", + EdgeLabel: "bodySite_reference_DiagnosticReport", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -16594,16 +16509,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "subject_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "DiagnosticReport/*", }, }, - "Practitioner|subject_Practitioner|DiagnosticReport": { - FromType: "Practitioner", - EdgeLabel: "subject_Practitioner", - ToType: "DiagnosticReport", + "DocumentReference|bodySite_reference_Condition|Condition": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_Condition", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -16611,16 +16526,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "subject_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Condition/*", }, }, - "DiagnosticReport|subject_Medication|Medication": { - FromType: "DiagnosticReport", - EdgeLabel: "subject_Medication", - ToType: "Medication", + "Condition|bodySite_reference_Condition|DocumentReference": { + FromType: "Condition", + EdgeLabel: "bodySite_reference_Condition", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -16628,16 +16543,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "subject_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Medication/*", + "Condition/*", }, }, - "Medication|subject_Medication|DiagnosticReport": { - FromType: "Medication", - EdgeLabel: "subject_Medication", - ToType: "DiagnosticReport", + "DocumentReference|bodySite_reference_Medication|Medication": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_Medication", + ToType: "Medication", Direction: []string{ "outbound", }, @@ -16645,16 +16560,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "subject_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ "Medication/*", }, }, - "DiagnosticReport|subject_Substance|Substance": { - FromType: "DiagnosticReport", - EdgeLabel: "subject_Substance", - ToType: "Substance", + "Medication|bodySite_reference_Medication|DocumentReference": { + FromType: "Medication", + EdgeLabel: "bodySite_reference_Medication", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -16662,16 +16577,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "subject_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Substance/*", + "Medication/*", }, }, - "Substance|subject_Substance|DiagnosticReport": { - FromType: "Substance", - EdgeLabel: "subject_Substance", - ToType: "DiagnosticReport", + "DocumentReference|bodySite_reference_MedicationAdministration|MedicationAdministration": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_MedicationAdministration", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -16679,15 +16594,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "subject_diagnostic_report", + "codeable_reference", }, RegexMatch: []string{ - "Substance/*", + "MedicationAdministration/*", }, }, - "DiagnosticReport|media_link|DocumentReference": { - FromType: "DiagnosticReport", - EdgeLabel: "media_link", + "MedicationAdministration|bodySite_reference_MedicationAdministration|DocumentReference": { + FromType: "MedicationAdministration", + EdgeLabel: "bodySite_reference_MedicationAdministration", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -16696,16 +16611,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "diagnostic_report_media", + "codeable_reference", }, RegexMatch: []string{ - "DocumentReference/*", + "MedicationAdministration/*", }, }, - "DocumentReference|media_link|DiagnosticReport": { + "DocumentReference|bodySite_reference_MedicationStatement|MedicationStatement": { FromType: "DocumentReference", - EdgeLabel: "media_link", - ToType: "DiagnosticReport", + EdgeLabel: "bodySite_reference_MedicationStatement", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -16713,16 +16628,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "diagnostic_report_media", + "codeable_reference", }, RegexMatch: []string{ - "DocumentReference/*", + "MedicationStatement/*", }, }, - "DiagnosticReport|note_authorReference_Practitioner|Practitioner": { - FromType: "DiagnosticReport", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "Practitioner", + "MedicationStatement|bodySite_reference_MedicationStatement|DocumentReference": { + FromType: "MedicationStatement", + EdgeLabel: "bodySite_reference_MedicationStatement", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -16730,16 +16645,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "MedicationStatement/*", }, }, - "Practitioner|note_authorReference_Practitioner|DiagnosticReport": { - FromType: "Practitioner", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "DiagnosticReport", + "DocumentReference|bodySite_reference_MedicationRequest|MedicationRequest": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_MedicationRequest", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -16747,16 +16662,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "MedicationRequest/*", }, }, - "DiagnosticReport|note_authorReference_PractitionerRole|PractitionerRole": { - FromType: "DiagnosticReport", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "PractitionerRole", + "MedicationRequest|bodySite_reference_MedicationRequest|DocumentReference": { + FromType: "MedicationRequest", + EdgeLabel: "bodySite_reference_MedicationRequest", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -16764,16 +16679,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "MedicationRequest/*", }, }, - "PractitionerRole|note_authorReference_PractitionerRole|DiagnosticReport": { - FromType: "PractitionerRole", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "DiagnosticReport", + "DocumentReference|bodySite_reference_Procedure|Procedure": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -16781,16 +16696,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Procedure/*", }, }, - "DiagnosticReport|note_authorReference_Patient|Patient": { - FromType: "DiagnosticReport", - EdgeLabel: "note_authorReference_Patient", - ToType: "Patient", + "Procedure|bodySite_reference_Procedure|DocumentReference": { + FromType: "Procedure", + EdgeLabel: "bodySite_reference_Procedure", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -16798,16 +16713,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "Procedure/*", }, }, - "Patient|note_authorReference_Patient|DiagnosticReport": { - FromType: "Patient", - EdgeLabel: "note_authorReference_Patient", - ToType: "DiagnosticReport", + "DocumentReference|bodySite_reference_DocumentReference|DocumentReference": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -16815,16 +16730,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "DocumentReference/*", }, }, - "DiagnosticReport|note_authorReference_Organization|Organization": { - FromType: "DiagnosticReport", - EdgeLabel: "note_authorReference_Organization", - ToType: "Organization", + "DocumentReference|bodySite_reference_Task|Task": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_Task", + ToType: "Task", Direction: []string{ "outbound", }, @@ -16832,16 +16747,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Task/*", }, }, - "Organization|note_authorReference_Organization|DiagnosticReport": { - FromType: "Organization", - EdgeLabel: "note_authorReference_Organization", - ToType: "DiagnosticReport", + "Task|bodySite_reference_Task|DocumentReference": { + FromType: "Task", + EdgeLabel: "bodySite_reference_Task", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -16849,16 +16764,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Task/*", }, }, - "DiagnosticReport|supportingInfo_reference_Procedure|Procedure": { - FromType: "DiagnosticReport", - EdgeLabel: "supportingInfo_reference_Procedure", - ToType: "Procedure", + "DocumentReference|bodySite_reference_ImagingStudy|ImagingStudy": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_ImagingStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -16866,16 +16781,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "diagnostic_report_supporting_info", + "codeable_reference", }, RegexMatch: []string{ - "Procedure/*", + "ImagingStudy/*", }, }, - "Procedure|supportingInfo_reference_Procedure|DiagnosticReport": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_reference_Procedure", - ToType: "DiagnosticReport", + "ImagingStudy|bodySite_reference_ImagingStudy|DocumentReference": { + FromType: "ImagingStudy", + EdgeLabel: "bodySite_reference_ImagingStudy", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -16883,16 +16798,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "diagnostic_report_supporting_info", + "codeable_reference", }, RegexMatch: []string{ - "Procedure/*", + "ImagingStudy/*", }, }, - "DiagnosticReport|supportingInfo_reference_Observation|Observation": { - FromType: "DiagnosticReport", - EdgeLabel: "supportingInfo_reference_Observation", - ToType: "Observation", + "DocumentReference|bodySite_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_FamilyMemberHistory", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -16900,16 +16815,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "diagnostic_report_supporting_info", + "codeable_reference", }, RegexMatch: []string{ - "Observation/*", + "FamilyMemberHistory/*", }, }, - "Observation|supportingInfo_reference_Observation|DiagnosticReport": { - FromType: "Observation", - EdgeLabel: "supportingInfo_reference_Observation", - ToType: "DiagnosticReport", + "FamilyMemberHistory|bodySite_reference_FamilyMemberHistory|DocumentReference": { + FromType: "FamilyMemberHistory", + EdgeLabel: "bodySite_reference_FamilyMemberHistory", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -16917,16 +16832,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "diagnostic_report_supporting_info", + "codeable_reference", }, RegexMatch: []string{ - "Observation/*", + "FamilyMemberHistory/*", }, }, - "DiagnosticReport|supportingInfo_reference_DiagnosticReport|DiagnosticReport": { - FromType: "DiagnosticReport", - EdgeLabel: "supportingInfo_reference_DiagnosticReport", - ToType: "DiagnosticReport", + "DocumentReference|bodySite_reference_BodyStructure|BodyStructure": { + FromType: "DocumentReference", + EdgeLabel: "bodySite_reference_BodyStructure", + ToType: "BodyStructure", Direction: []string{ "outbound", }, @@ -16934,15 +16849,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "diagnostic_report_supporting_info", + "codeable_reference", }, RegexMatch: []string{ - "DiagnosticReport/*", + "BodyStructure/*", }, }, - "DiagnosticReportMedia|link|DocumentReference": { - FromType: "DiagnosticReportMedia", - EdgeLabel: "link", + "BodyStructure|bodySite_reference_BodyStructure|DocumentReference": { + FromType: "BodyStructure", + EdgeLabel: "bodySite_reference_BodyStructure", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -16951,16 +16866,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "diagnostic_report_media", + "codeable_reference", }, RegexMatch: []string{ - "DocumentReference/*", + "BodyStructure/*", }, }, - "DocumentReference|link|DiagnosticReportMedia": { + "DocumentReference|event_reference_Organization|Organization": { FromType: "DocumentReference", - EdgeLabel: "link", - ToType: "DiagnosticReportMedia", + EdgeLabel: "event_reference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -16968,16 +16883,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "diagnostic_report_media", + "codeable_reference", }, RegexMatch: []string{ - "DocumentReference/*", + "Organization/*", }, }, - "DiagnosticReportSupportingInfo|reference_Procedure|Procedure": { - FromType: "DiagnosticReportSupportingInfo", - EdgeLabel: "reference_Procedure", - ToType: "Procedure", + "Organization|event_reference_Organization|DocumentReference": { + FromType: "Organization", + EdgeLabel: "event_reference_Organization", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -16985,16 +16900,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "diagnostic_report_supporting_info", + "codeable_reference", }, RegexMatch: []string{ - "Procedure/*", + "Organization/*", }, }, - "Procedure|reference_Procedure|DiagnosticReportSupportingInfo": { - FromType: "Procedure", - EdgeLabel: "reference_Procedure", - ToType: "DiagnosticReportSupportingInfo", + "DocumentReference|event_reference_Group|Group": { + FromType: "DocumentReference", + EdgeLabel: "event_reference_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -17002,16 +16917,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "diagnostic_report_supporting_info", + "codeable_reference", }, RegexMatch: []string{ - "Procedure/*", + "Group/*", }, }, - "DiagnosticReportSupportingInfo|reference_Observation|Observation": { - FromType: "DiagnosticReportSupportingInfo", - EdgeLabel: "reference_Observation", - ToType: "Observation", + "Group|event_reference_Group|DocumentReference": { + FromType: "Group", + EdgeLabel: "event_reference_Group", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -17019,16 +16934,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "diagnostic_report_supporting_info", + "codeable_reference", }, RegexMatch: []string{ - "Observation/*", + "Group/*", }, }, - "Observation|reference_Observation|DiagnosticReportSupportingInfo": { - FromType: "Observation", - EdgeLabel: "reference_Observation", - ToType: "DiagnosticReportSupportingInfo", + "DocumentReference|event_reference_Practitioner|Practitioner": { + FromType: "DocumentReference", + EdgeLabel: "event_reference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -17036,16 +16951,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "diagnostic_report_supporting_info", + "codeable_reference", }, RegexMatch: []string{ - "Observation/*", + "Practitioner/*", }, }, - "DiagnosticReportSupportingInfo|reference_DiagnosticReport|DiagnosticReport": { - FromType: "DiagnosticReportSupportingInfo", - EdgeLabel: "reference_DiagnosticReport", - ToType: "DiagnosticReport", + "Practitioner|event_reference_Practitioner|DocumentReference": { + FromType: "Practitioner", + EdgeLabel: "event_reference_Practitioner", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -17053,16 +16968,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "diagnostic_report_supporting_info", + "codeable_reference", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Practitioner/*", }, }, - "DiagnosticReport|reference_DiagnosticReport|DiagnosticReportSupportingInfo": { - FromType: "DiagnosticReport", - EdgeLabel: "reference_DiagnosticReport", - ToType: "DiagnosticReportSupportingInfo", + "DocumentReference|event_reference_PractitionerRole|PractitionerRole": { + FromType: "DocumentReference", + EdgeLabel: "event_reference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -17070,231 +16985,237 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "diagnostic_report_supporting_info", + "codeable_reference", }, RegexMatch: []string{ - "DiagnosticReport/*", + "PractitionerRole/*", }, }, - "Directory|child_Directory|Directory": { - FromType: "Directory", - EdgeLabel: "child_Directory", - ToType: "Directory", + "PractitionerRole|event_reference_PractitionerRole|DocumentReference": { + FromType: "PractitionerRole", + EdgeLabel: "event_reference_PractitionerRole", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", + }, + Backref: []string{ + "codeable_reference", }, - Backref: []string{}, RegexMatch: []string{ - "Directory/*", + "PractitionerRole/*", }, }, - "Directory|child_DocumentReference|DocumentReference": { - FromType: "Directory", - EdgeLabel: "child_DocumentReference", - ToType: "DocumentReference", + "DocumentReference|event_reference_ResearchStudy|ResearchStudy": { + FromType: "DocumentReference", + EdgeLabel: "event_reference_ResearchStudy", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", + }, + Backref: []string{ + "codeable_reference", }, - Backref: []string{}, RegexMatch: []string{ - "DocumentReference/*", + "ResearchStudy/*", }, }, - "DocumentReference|child_DocumentReference|Directory": { - FromType: "DocumentReference", - EdgeLabel: "child_DocumentReference", - ToType: "Directory", + "ResearchStudy|event_reference_ResearchStudy|DocumentReference": { + FromType: "ResearchStudy", + EdgeLabel: "event_reference_ResearchStudy", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", + }, + Backref: []string{ + "codeable_reference", }, - Backref: []string{}, RegexMatch: []string{ - "DocumentReference/*", + "ResearchStudy/*", }, }, - "DocumentReference|author_Practitioner|Practitioner": { + "DocumentReference|event_reference_Patient|Patient": { FromType: "DocumentReference", - EdgeLabel: "author_Practitioner", - ToType: "Practitioner", + EdgeLabel: "event_reference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "author_document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Patient/*", }, }, - "Practitioner|author_Practitioner|DocumentReference": { - FromType: "Practitioner", - EdgeLabel: "author_Practitioner", + "Patient|event_reference_Patient|DocumentReference": { + FromType: "Patient", + EdgeLabel: "event_reference_Patient", ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "author_document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Patient/*", }, }, - "DocumentReference|author_PractitionerRole|PractitionerRole": { + "DocumentReference|event_reference_ResearchSubject|ResearchSubject": { FromType: "DocumentReference", - EdgeLabel: "author_PractitionerRole", - ToType: "PractitionerRole", + EdgeLabel: "event_reference_ResearchSubject", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "author_document_reference", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "ResearchSubject/*", }, }, - "PractitionerRole|author_PractitionerRole|DocumentReference": { - FromType: "PractitionerRole", - EdgeLabel: "author_PractitionerRole", + "ResearchSubject|event_reference_ResearchSubject|DocumentReference": { + FromType: "ResearchSubject", + EdgeLabel: "event_reference_ResearchSubject", ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "author_document_reference", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "ResearchSubject/*", }, }, - "DocumentReference|author_Organization|Organization": { + "DocumentReference|event_reference_Substance|Substance": { FromType: "DocumentReference", - EdgeLabel: "author_Organization", - ToType: "Organization", + EdgeLabel: "event_reference_Substance", + ToType: "Substance", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "author_document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Substance/*", }, }, - "Organization|author_Organization|DocumentReference": { - FromType: "Organization", - EdgeLabel: "author_Organization", + "Substance|event_reference_Substance|DocumentReference": { + FromType: "Substance", + EdgeLabel: "event_reference_Substance", ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "author_document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Substance/*", }, }, - "DocumentReference|author_Patient|Patient": { + "DocumentReference|event_reference_SubstanceDefinition|SubstanceDefinition": { FromType: "DocumentReference", - EdgeLabel: "author_Patient", - ToType: "Patient", + EdgeLabel: "event_reference_SubstanceDefinition", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "author_document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "SubstanceDefinition/*", }, }, - "Patient|author_Patient|DocumentReference": { - FromType: "Patient", - EdgeLabel: "author_Patient", + "SubstanceDefinition|event_reference_SubstanceDefinition|DocumentReference": { + FromType: "SubstanceDefinition", + EdgeLabel: "event_reference_SubstanceDefinition", ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "author_document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "SubstanceDefinition/*", }, }, - "DocumentReference|basedOn_MedicationRequest|MedicationRequest": { + "DocumentReference|event_reference_Specimen|Specimen": { FromType: "DocumentReference", - EdgeLabel: "basedOn_MedicationRequest", - ToType: "MedicationRequest", + EdgeLabel: "event_reference_Specimen", + ToType: "Specimen", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_document_reference", + "codeable_reference", }, RegexMatch: []string{ - "MedicationRequest/*", + "Specimen/*", }, }, - "MedicationRequest|basedOn_MedicationRequest|DocumentReference": { - FromType: "MedicationRequest", - EdgeLabel: "basedOn_MedicationRequest", + "Specimen|event_reference_Specimen|DocumentReference": { + FromType: "Specimen", + EdgeLabel: "event_reference_Specimen", ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_document_reference", + "codeable_reference", }, RegexMatch: []string{ - "MedicationRequest/*", + "Specimen/*", }, }, - "DocumentReference|custodian|Organization": { + "DocumentReference|event_reference_Observation|Observation": { FromType: "DocumentReference", - EdgeLabel: "custodian", - ToType: "Organization", + EdgeLabel: "event_reference_Observation", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -17302,15 +17223,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "custodian_document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Observation/*", }, }, - "Organization|custodian|DocumentReference": { - FromType: "Organization", - EdgeLabel: "custodian", + "Observation|event_reference_Observation|DocumentReference": { + FromType: "Observation", + EdgeLabel: "event_reference_Observation", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -17319,16 +17240,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "custodian_document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Observation/*", }, }, - "DocumentReference|subject_Organization|Organization": { + "DocumentReference|event_reference_DiagnosticReport|DiagnosticReport": { FromType: "DocumentReference", - EdgeLabel: "subject_Organization", - ToType: "Organization", + EdgeLabel: "event_reference_DiagnosticReport", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -17336,15 +17257,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "DiagnosticReport/*", }, }, - "Organization|subject_Organization|DocumentReference": { - FromType: "Organization", - EdgeLabel: "subject_Organization", + "DiagnosticReport|event_reference_DiagnosticReport|DocumentReference": { + FromType: "DiagnosticReport", + EdgeLabel: "event_reference_DiagnosticReport", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -17353,16 +17274,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "DiagnosticReport/*", }, }, - "DocumentReference|subject_Group|Group": { + "DocumentReference|event_reference_Condition|Condition": { FromType: "DocumentReference", - EdgeLabel: "subject_Group", - ToType: "Group", + EdgeLabel: "event_reference_Condition", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -17370,15 +17291,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "Condition/*", }, }, - "Group|subject_Group|DocumentReference": { - FromType: "Group", - EdgeLabel: "subject_Group", + "Condition|event_reference_Condition|DocumentReference": { + FromType: "Condition", + EdgeLabel: "event_reference_Condition", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -17387,16 +17308,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "Condition/*", }, }, - "DocumentReference|subject_Practitioner|Practitioner": { + "DocumentReference|event_reference_Medication|Medication": { FromType: "DocumentReference", - EdgeLabel: "subject_Practitioner", - ToType: "Practitioner", + EdgeLabel: "event_reference_Medication", + ToType: "Medication", Direction: []string{ "outbound", }, @@ -17404,15 +17325,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Medication/*", }, }, - "Practitioner|subject_Practitioner|DocumentReference": { - FromType: "Practitioner", - EdgeLabel: "subject_Practitioner", + "Medication|event_reference_Medication|DocumentReference": { + FromType: "Medication", + EdgeLabel: "event_reference_Medication", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -17421,16 +17342,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Medication/*", }, }, - "DocumentReference|subject_PractitionerRole|PractitionerRole": { + "DocumentReference|event_reference_MedicationAdministration|MedicationAdministration": { FromType: "DocumentReference", - EdgeLabel: "subject_PractitionerRole", - ToType: "PractitionerRole", + EdgeLabel: "event_reference_MedicationAdministration", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -17438,15 +17359,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "MedicationAdministration/*", }, }, - "PractitionerRole|subject_PractitionerRole|DocumentReference": { - FromType: "PractitionerRole", - EdgeLabel: "subject_PractitionerRole", + "MedicationAdministration|event_reference_MedicationAdministration|DocumentReference": { + FromType: "MedicationAdministration", + EdgeLabel: "event_reference_MedicationAdministration", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -17455,16 +17376,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "MedicationAdministration/*", }, }, - "DocumentReference|subject_ResearchStudy|ResearchStudy": { + "DocumentReference|event_reference_MedicationStatement|MedicationStatement": { FromType: "DocumentReference", - EdgeLabel: "subject_ResearchStudy", - ToType: "ResearchStudy", + EdgeLabel: "event_reference_MedicationStatement", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -17472,15 +17393,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "ResearchStudy/*", + "MedicationStatement/*", }, }, - "ResearchStudy|subject_ResearchStudy|DocumentReference": { - FromType: "ResearchStudy", - EdgeLabel: "subject_ResearchStudy", + "MedicationStatement|event_reference_MedicationStatement|DocumentReference": { + FromType: "MedicationStatement", + EdgeLabel: "event_reference_MedicationStatement", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -17489,16 +17410,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "ResearchStudy/*", + "MedicationStatement/*", }, }, - "DocumentReference|subject_Patient|Patient": { + "DocumentReference|event_reference_MedicationRequest|MedicationRequest": { FromType: "DocumentReference", - EdgeLabel: "subject_Patient", - ToType: "Patient", + EdgeLabel: "event_reference_MedicationRequest", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -17506,15 +17427,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "MedicationRequest/*", }, }, - "Patient|subject_Patient|DocumentReference": { - FromType: "Patient", - EdgeLabel: "subject_Patient", + "MedicationRequest|event_reference_MedicationRequest|DocumentReference": { + FromType: "MedicationRequest", + EdgeLabel: "event_reference_MedicationRequest", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -17523,16 +17444,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "MedicationRequest/*", }, }, - "DocumentReference|subject_ResearchSubject|ResearchSubject": { + "DocumentReference|event_reference_Procedure|Procedure": { FromType: "DocumentReference", - EdgeLabel: "subject_ResearchSubject", - ToType: "ResearchSubject", + EdgeLabel: "event_reference_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -17540,15 +17461,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "ResearchSubject/*", + "Procedure/*", }, }, - "ResearchSubject|subject_ResearchSubject|DocumentReference": { - FromType: "ResearchSubject", - EdgeLabel: "subject_ResearchSubject", + "Procedure|event_reference_Procedure|DocumentReference": { + FromType: "Procedure", + EdgeLabel: "event_reference_Procedure", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -17557,32 +17478,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "ResearchSubject/*", + "Procedure/*", }, }, - "DocumentReference|subject_Substance|Substance": { + "DocumentReference|event_reference_DocumentReference|DocumentReference": { FromType: "DocumentReference", - EdgeLabel: "subject_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "document_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|subject_Substance|DocumentReference": { - FromType: "Substance", - EdgeLabel: "subject_Substance", + EdgeLabel: "event_reference_DocumentReference", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -17591,16 +17495,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Substance/*", + "DocumentReference/*", }, }, - "DocumentReference|subject_SubstanceDefinition|SubstanceDefinition": { + "DocumentReference|event_reference_Task|Task": { FromType: "DocumentReference", - EdgeLabel: "subject_SubstanceDefinition", - ToType: "SubstanceDefinition", + EdgeLabel: "event_reference_Task", + ToType: "Task", Direction: []string{ "outbound", }, @@ -17608,15 +17512,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "Task/*", }, }, - "SubstanceDefinition|subject_SubstanceDefinition|DocumentReference": { - FromType: "SubstanceDefinition", - EdgeLabel: "subject_SubstanceDefinition", + "Task|event_reference_Task|DocumentReference": { + FromType: "Task", + EdgeLabel: "event_reference_Task", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -17625,16 +17529,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "Task/*", }, }, - "DocumentReference|subject_Specimen|Specimen": { + "DocumentReference|event_reference_ImagingStudy|ImagingStudy": { FromType: "DocumentReference", - EdgeLabel: "subject_Specimen", - ToType: "Specimen", + EdgeLabel: "event_reference_ImagingStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -17642,15 +17546,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Specimen/*", + "ImagingStudy/*", }, }, - "Specimen|subject_Specimen|DocumentReference": { - FromType: "Specimen", - EdgeLabel: "subject_Specimen", + "ImagingStudy|event_reference_ImagingStudy|DocumentReference": { + FromType: "ImagingStudy", + EdgeLabel: "event_reference_ImagingStudy", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -17659,16 +17563,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Specimen/*", + "ImagingStudy/*", }, }, - "DocumentReference|subject_Observation|Observation": { + "DocumentReference|event_reference_FamilyMemberHistory|FamilyMemberHistory": { FromType: "DocumentReference", - EdgeLabel: "subject_Observation", - ToType: "Observation", + EdgeLabel: "event_reference_FamilyMemberHistory", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -17676,15 +17580,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Observation/*", + "FamilyMemberHistory/*", }, }, - "Observation|subject_Observation|DocumentReference": { - FromType: "Observation", - EdgeLabel: "subject_Observation", + "FamilyMemberHistory|event_reference_FamilyMemberHistory|DocumentReference": { + FromType: "FamilyMemberHistory", + EdgeLabel: "event_reference_FamilyMemberHistory", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -17693,16 +17597,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "Observation/*", + "FamilyMemberHistory/*", }, }, - "DocumentReference|subject_DiagnosticReport|DiagnosticReport": { + "DocumentReference|event_reference_BodyStructure|BodyStructure": { FromType: "DocumentReference", - EdgeLabel: "subject_DiagnosticReport", - ToType: "DiagnosticReport", + EdgeLabel: "event_reference_BodyStructure", + ToType: "BodyStructure", Direction: []string{ "outbound", }, @@ -17710,15 +17614,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "DiagnosticReport/*", + "BodyStructure/*", }, }, - "DiagnosticReport|subject_DiagnosticReport|DocumentReference": { - FromType: "DiagnosticReport", - EdgeLabel: "subject_DiagnosticReport", + "BodyStructure|event_reference_BodyStructure|DocumentReference": { + FromType: "BodyStructure", + EdgeLabel: "event_reference_BodyStructure", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -17727,16 +17631,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "DiagnosticReport/*", + "BodyStructure/*", }, }, - "DocumentReference|subject_Condition|Condition": { + "DocumentReference|relatesTo_target|DocumentReference": { FromType: "DocumentReference", - EdgeLabel: "subject_Condition", - ToType: "Condition", + EdgeLabel: "relatesTo_target", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -17744,16 +17648,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "document_reference_relates_to", }, RegexMatch: []string{ - "Condition/*", + "DocumentReference/*", }, }, - "Condition|subject_Condition|DocumentReference": { - FromType: "Condition", - EdgeLabel: "subject_Condition", - ToType: "DocumentReference", + "FamilyMemberHistory|patient|Patient": { + FromType: "FamilyMemberHistory", + EdgeLabel: "patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -17761,16 +17665,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "family_member_history", }, RegexMatch: []string{ - "Condition/*", + "Patient/*", }, }, - "DocumentReference|subject_Medication|Medication": { - FromType: "DocumentReference", - EdgeLabel: "subject_Medication", - ToType: "Medication", + "Patient|patient|FamilyMemberHistory": { + FromType: "Patient", + EdgeLabel: "patient", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -17778,16 +17682,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "family_member_history", }, RegexMatch: []string{ - "Medication/*", + "Patient/*", }, }, - "Medication|subject_Medication|DocumentReference": { - FromType: "Medication", - EdgeLabel: "subject_Medication", - ToType: "DocumentReference", + "FamilyMemberHistory|note_authorReference_Practitioner|Practitioner": { + FromType: "FamilyMemberHistory", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -17795,16 +17699,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "annotation", }, RegexMatch: []string{ - "Medication/*", + "Practitioner/*", }, }, - "DocumentReference|subject_MedicationAdministration|MedicationAdministration": { - FromType: "DocumentReference", - EdgeLabel: "subject_MedicationAdministration", - ToType: "MedicationAdministration", + "Practitioner|note_authorReference_Practitioner|FamilyMemberHistory": { + FromType: "Practitioner", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -17812,16 +17716,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "annotation", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Practitioner/*", }, }, - "MedicationAdministration|subject_MedicationAdministration|DocumentReference": { - FromType: "MedicationAdministration", - EdgeLabel: "subject_MedicationAdministration", - ToType: "DocumentReference", + "FamilyMemberHistory|note_authorReference_PractitionerRole|PractitionerRole": { + FromType: "FamilyMemberHistory", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -17829,16 +17733,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "annotation", }, RegexMatch: []string{ - "MedicationAdministration/*", + "PractitionerRole/*", }, }, - "DocumentReference|subject_MedicationStatement|MedicationStatement": { - FromType: "DocumentReference", - EdgeLabel: "subject_MedicationStatement", - ToType: "MedicationStatement", + "PractitionerRole|note_authorReference_PractitionerRole|FamilyMemberHistory": { + FromType: "PractitionerRole", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -17846,16 +17750,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "annotation", }, RegexMatch: []string{ - "MedicationStatement/*", + "PractitionerRole/*", }, }, - "MedicationStatement|subject_MedicationStatement|DocumentReference": { - FromType: "MedicationStatement", - EdgeLabel: "subject_MedicationStatement", - ToType: "DocumentReference", + "FamilyMemberHistory|note_authorReference_Patient|Patient": { + FromType: "FamilyMemberHistory", + EdgeLabel: "note_authorReference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -17863,16 +17767,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "annotation", }, RegexMatch: []string{ - "MedicationStatement/*", + "Patient/*", }, }, - "DocumentReference|subject_MedicationRequest|MedicationRequest": { - FromType: "DocumentReference", - EdgeLabel: "subject_MedicationRequest", - ToType: "MedicationRequest", + "Patient|note_authorReference_Patient|FamilyMemberHistory": { + FromType: "Patient", + EdgeLabel: "note_authorReference_Patient", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -17880,16 +17784,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "annotation", }, RegexMatch: []string{ - "MedicationRequest/*", + "Patient/*", }, }, - "MedicationRequest|subject_MedicationRequest|DocumentReference": { - FromType: "MedicationRequest", - EdgeLabel: "subject_MedicationRequest", - ToType: "DocumentReference", + "FamilyMemberHistory|note_authorReference_Organization|Organization": { + FromType: "FamilyMemberHistory", + EdgeLabel: "note_authorReference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -17897,16 +17801,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "annotation", }, RegexMatch: []string{ - "MedicationRequest/*", + "Organization/*", }, }, - "DocumentReference|subject_Procedure|Procedure": { - FromType: "DocumentReference", - EdgeLabel: "subject_Procedure", - ToType: "Procedure", + "Organization|note_authorReference_Organization|FamilyMemberHistory": { + FromType: "Organization", + EdgeLabel: "note_authorReference_Organization", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -17914,16 +17818,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "annotation", }, RegexMatch: []string{ - "Procedure/*", + "Organization/*", }, }, - "Procedure|subject_Procedure|DocumentReference": { - FromType: "Procedure", - EdgeLabel: "subject_Procedure", - ToType: "DocumentReference", + "FamilyMemberHistory|participant_actor_Practitioner|Practitioner": { + FromType: "FamilyMemberHistory", + EdgeLabel: "participant_actor_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -17931,16 +17835,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "family_member_history_participant", }, RegexMatch: []string{ - "Procedure/*", + "Practitioner/*", }, }, - "DocumentReference|subject_DocumentReference|DocumentReference": { - FromType: "DocumentReference", - EdgeLabel: "subject_DocumentReference", - ToType: "DocumentReference", + "Practitioner|participant_actor_Practitioner|FamilyMemberHistory": { + FromType: "Practitioner", + EdgeLabel: "participant_actor_Practitioner", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -17948,16 +17852,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "family_member_history_participant", }, RegexMatch: []string{ - "DocumentReference/*", + "Practitioner/*", }, }, - "DocumentReference|subject_Task|Task": { - FromType: "DocumentReference", - EdgeLabel: "subject_Task", - ToType: "Task", + "FamilyMemberHistory|participant_actor_PractitionerRole|PractitionerRole": { + FromType: "FamilyMemberHistory", + EdgeLabel: "participant_actor_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -17965,16 +17869,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "family_member_history_participant", }, RegexMatch: []string{ - "Task/*", + "PractitionerRole/*", }, }, - "Task|subject_Task|DocumentReference": { - FromType: "Task", - EdgeLabel: "subject_Task", - ToType: "DocumentReference", + "PractitionerRole|participant_actor_PractitionerRole|FamilyMemberHistory": { + FromType: "PractitionerRole", + EdgeLabel: "participant_actor_PractitionerRole", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -17982,16 +17886,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "family_member_history_participant", }, RegexMatch: []string{ - "Task/*", + "PractitionerRole/*", }, }, - "DocumentReference|subject_ImagingStudy|ImagingStudy": { - FromType: "DocumentReference", - EdgeLabel: "subject_ImagingStudy", - ToType: "ImagingStudy", + "FamilyMemberHistory|participant_actor_Patient|Patient": { + FromType: "FamilyMemberHistory", + EdgeLabel: "participant_actor_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -17999,16 +17903,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "family_member_history_participant", }, RegexMatch: []string{ - "ImagingStudy/*", + "Patient/*", }, }, - "ImagingStudy|subject_ImagingStudy|DocumentReference": { - FromType: "ImagingStudy", - EdgeLabel: "subject_ImagingStudy", - ToType: "DocumentReference", + "Patient|participant_actor_Patient|FamilyMemberHistory": { + FromType: "Patient", + EdgeLabel: "participant_actor_Patient", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18016,16 +17920,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "family_member_history_participant", }, RegexMatch: []string{ - "ImagingStudy/*", + "Patient/*", }, }, - "DocumentReference|subject_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "DocumentReference", - EdgeLabel: "subject_FamilyMemberHistory", - ToType: "FamilyMemberHistory", + "FamilyMemberHistory|participant_actor_Organization|Organization": { + FromType: "FamilyMemberHistory", + EdgeLabel: "participant_actor_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -18033,16 +17937,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "family_member_history_participant", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Organization/*", }, }, - "FamilyMemberHistory|subject_FamilyMemberHistory|DocumentReference": { - FromType: "FamilyMemberHistory", - EdgeLabel: "subject_FamilyMemberHistory", - ToType: "DocumentReference", + "Organization|participant_actor_Organization|FamilyMemberHistory": { + FromType: "Organization", + EdgeLabel: "participant_actor_Organization", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18050,16 +17954,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "family_member_history_participant", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Organization/*", }, }, - "DocumentReference|subject_BodyStructure|BodyStructure": { - FromType: "DocumentReference", - EdgeLabel: "subject_BodyStructure", - ToType: "BodyStructure", + "FamilyMemberHistory|reason_reference_Organization|Organization": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -18067,16 +17971,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "BodyStructure/*", + "Organization/*", }, }, - "BodyStructure|subject_BodyStructure|DocumentReference": { - FromType: "BodyStructure", - EdgeLabel: "subject_BodyStructure", - ToType: "DocumentReference", + "Organization|reason_reference_Organization|FamilyMemberHistory": { + FromType: "Organization", + EdgeLabel: "reason_reference_Organization", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18084,185 +17988,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference", + "codeable_reference", }, RegexMatch: []string{ - "BodyStructure/*", + "Organization/*", }, }, - "DocumentReference|attester_party_Patient|Patient": { - FromType: "DocumentReference", - EdgeLabel: "attester_party_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "document_reference_attester", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|attester_party_Patient|DocumentReference": { - FromType: "Patient", - EdgeLabel: "attester_party_Patient", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "document_reference_attester", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "DocumentReference|attester_party_Practitioner|Practitioner": { - FromType: "DocumentReference", - EdgeLabel: "attester_party_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "document_reference_attester", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|attester_party_Practitioner|DocumentReference": { - FromType: "Practitioner", - EdgeLabel: "attester_party_Practitioner", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "document_reference_attester", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "DocumentReference|attester_party_PractitionerRole|PractitionerRole": { - FromType: "DocumentReference", - EdgeLabel: "attester_party_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "document_reference_attester", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|attester_party_PractitionerRole|DocumentReference": { - FromType: "PractitionerRole", - EdgeLabel: "attester_party_PractitionerRole", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "document_reference_attester", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "DocumentReference|attester_party_Organization|Organization": { - FromType: "DocumentReference", - EdgeLabel: "attester_party_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "document_reference_attester", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|attester_party_Organization|DocumentReference": { - FromType: "Organization", - EdgeLabel: "attester_party_Organization", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "document_reference_attester", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "DocumentReference|bodySite_reference_Organization|Organization": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|bodySite_reference_Organization|DocumentReference": { - FromType: "Organization", - EdgeLabel: "bodySite_reference_Organization", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "DocumentReference|bodySite_reference_Group|Group": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_Group", + "FamilyMemberHistory|reason_reference_Group|Group": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_Group", ToType: "Group", Direction: []string{ "outbound", @@ -18277,10 +18011,10 @@ var Traversals = map[string]Traversal{ "Group/*", }, }, - "Group|bodySite_reference_Group|DocumentReference": { + "Group|reason_reference_Group|FamilyMemberHistory": { FromType: "Group", - EdgeLabel: "bodySite_reference_Group", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_Group", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18294,9 +18028,9 @@ var Traversals = map[string]Traversal{ "Group/*", }, }, - "DocumentReference|bodySite_reference_Practitioner|Practitioner": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_Practitioner", + "FamilyMemberHistory|reason_reference_Practitioner|Practitioner": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", @@ -18311,10 +18045,10 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "Practitioner|bodySite_reference_Practitioner|DocumentReference": { + "Practitioner|reason_reference_Practitioner|FamilyMemberHistory": { FromType: "Practitioner", - EdgeLabel: "bodySite_reference_Practitioner", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_Practitioner", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18328,9 +18062,9 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "DocumentReference|bodySite_reference_PractitionerRole|PractitionerRole": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_PractitionerRole", + "FamilyMemberHistory|reason_reference_PractitionerRole|PractitionerRole": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", @@ -18345,10 +18079,10 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "PractitionerRole|bodySite_reference_PractitionerRole|DocumentReference": { + "PractitionerRole|reason_reference_PractitionerRole|FamilyMemberHistory": { FromType: "PractitionerRole", - EdgeLabel: "bodySite_reference_PractitionerRole", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_PractitionerRole", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18362,9 +18096,9 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "DocumentReference|bodySite_reference_ResearchStudy|ResearchStudy": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_ResearchStudy", + "FamilyMemberHistory|reason_reference_ResearchStudy|ResearchStudy": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -18379,10 +18113,10 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "ResearchStudy|bodySite_reference_ResearchStudy|DocumentReference": { + "ResearchStudy|reason_reference_ResearchStudy|FamilyMemberHistory": { FromType: "ResearchStudy", - EdgeLabel: "bodySite_reference_ResearchStudy", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_ResearchStudy", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18396,9 +18130,9 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "DocumentReference|bodySite_reference_Patient|Patient": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_Patient", + "FamilyMemberHistory|reason_reference_Patient|Patient": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -18413,10 +18147,10 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "Patient|bodySite_reference_Patient|DocumentReference": { + "Patient|reason_reference_Patient|FamilyMemberHistory": { FromType: "Patient", - EdgeLabel: "bodySite_reference_Patient", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_Patient", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18430,9 +18164,9 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "DocumentReference|bodySite_reference_ResearchSubject|ResearchSubject": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_ResearchSubject", + "FamilyMemberHistory|reason_reference_ResearchSubject|ResearchSubject": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -18447,10 +18181,10 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "ResearchSubject|bodySite_reference_ResearchSubject|DocumentReference": { + "ResearchSubject|reason_reference_ResearchSubject|FamilyMemberHistory": { FromType: "ResearchSubject", - EdgeLabel: "bodySite_reference_ResearchSubject", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_ResearchSubject", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18464,9 +18198,9 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "DocumentReference|bodySite_reference_Substance|Substance": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_Substance", + "FamilyMemberHistory|reason_reference_Substance|Substance": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -18481,10 +18215,10 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "Substance|bodySite_reference_Substance|DocumentReference": { + "Substance|reason_reference_Substance|FamilyMemberHistory": { FromType: "Substance", - EdgeLabel: "bodySite_reference_Substance", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_Substance", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18498,9 +18232,9 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "DocumentReference|bodySite_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_SubstanceDefinition", + "FamilyMemberHistory|reason_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -18515,10 +18249,10 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|bodySite_reference_SubstanceDefinition|DocumentReference": { + "SubstanceDefinition|reason_reference_SubstanceDefinition|FamilyMemberHistory": { FromType: "SubstanceDefinition", - EdgeLabel: "bodySite_reference_SubstanceDefinition", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_SubstanceDefinition", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18532,9 +18266,9 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "DocumentReference|bodySite_reference_Specimen|Specimen": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_Specimen", + "FamilyMemberHistory|reason_reference_Specimen|Specimen": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -18549,10 +18283,10 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "Specimen|bodySite_reference_Specimen|DocumentReference": { + "Specimen|reason_reference_Specimen|FamilyMemberHistory": { FromType: "Specimen", - EdgeLabel: "bodySite_reference_Specimen", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_Specimen", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18566,9 +18300,9 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "DocumentReference|bodySite_reference_Observation|Observation": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_Observation", + "FamilyMemberHistory|reason_reference_Observation|Observation": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -18583,10 +18317,10 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "Observation|bodySite_reference_Observation|DocumentReference": { + "Observation|reason_reference_Observation|FamilyMemberHistory": { FromType: "Observation", - EdgeLabel: "bodySite_reference_Observation", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_Observation", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18600,9 +18334,9 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "DocumentReference|bodySite_reference_DiagnosticReport|DiagnosticReport": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_DiagnosticReport", + "FamilyMemberHistory|reason_reference_DiagnosticReport|DiagnosticReport": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -18617,10 +18351,10 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "DiagnosticReport|bodySite_reference_DiagnosticReport|DocumentReference": { + "DiagnosticReport|reason_reference_DiagnosticReport|FamilyMemberHistory": { FromType: "DiagnosticReport", - EdgeLabel: "bodySite_reference_DiagnosticReport", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_DiagnosticReport", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18634,9 +18368,9 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "DocumentReference|bodySite_reference_Condition|Condition": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_Condition", + "FamilyMemberHistory|reason_reference_Condition|Condition": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -18651,10 +18385,10 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "Condition|bodySite_reference_Condition|DocumentReference": { + "Condition|reason_reference_Condition|FamilyMemberHistory": { FromType: "Condition", - EdgeLabel: "bodySite_reference_Condition", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_Condition", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18668,9 +18402,9 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "DocumentReference|bodySite_reference_Medication|Medication": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_Medication", + "FamilyMemberHistory|reason_reference_Medication|Medication": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -18685,10 +18419,10 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "Medication|bodySite_reference_Medication|DocumentReference": { + "Medication|reason_reference_Medication|FamilyMemberHistory": { FromType: "Medication", - EdgeLabel: "bodySite_reference_Medication", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_Medication", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18702,9 +18436,9 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "DocumentReference|bodySite_reference_MedicationAdministration|MedicationAdministration": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_MedicationAdministration", + "FamilyMemberHistory|reason_reference_MedicationAdministration|MedicationAdministration": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -18719,10 +18453,10 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "MedicationAdministration|bodySite_reference_MedicationAdministration|DocumentReference": { + "MedicationAdministration|reason_reference_MedicationAdministration|FamilyMemberHistory": { FromType: "MedicationAdministration", - EdgeLabel: "bodySite_reference_MedicationAdministration", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_MedicationAdministration", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18736,9 +18470,9 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "DocumentReference|bodySite_reference_MedicationStatement|MedicationStatement": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_MedicationStatement", + "FamilyMemberHistory|reason_reference_MedicationStatement|MedicationStatement": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -18753,10 +18487,10 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "MedicationStatement|bodySite_reference_MedicationStatement|DocumentReference": { + "MedicationStatement|reason_reference_MedicationStatement|FamilyMemberHistory": { FromType: "MedicationStatement", - EdgeLabel: "bodySite_reference_MedicationStatement", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_MedicationStatement", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18770,9 +18504,9 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "DocumentReference|bodySite_reference_MedicationRequest|MedicationRequest": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_MedicationRequest", + "FamilyMemberHistory|reason_reference_MedicationRequest|MedicationRequest": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -18787,10 +18521,10 @@ var Traversals = map[string]Traversal{ "MedicationRequest/*", }, }, - "MedicationRequest|bodySite_reference_MedicationRequest|DocumentReference": { + "MedicationRequest|reason_reference_MedicationRequest|FamilyMemberHistory": { FromType: "MedicationRequest", - EdgeLabel: "bodySite_reference_MedicationRequest", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_MedicationRequest", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18804,9 +18538,9 @@ var Traversals = map[string]Traversal{ "MedicationRequest/*", }, }, - "DocumentReference|bodySite_reference_Procedure|Procedure": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_Procedure", + "FamilyMemberHistory|reason_reference_Procedure|Procedure": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_Procedure", ToType: "Procedure", Direction: []string{ "outbound", @@ -18821,10 +18555,10 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "Procedure|bodySite_reference_Procedure|DocumentReference": { + "Procedure|reason_reference_Procedure|FamilyMemberHistory": { FromType: "Procedure", - EdgeLabel: "bodySite_reference_Procedure", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_Procedure", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18838,9 +18572,9 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "DocumentReference|bodySite_reference_DocumentReference|DocumentReference": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_DocumentReference", + "FamilyMemberHistory|reason_reference_DocumentReference|DocumentReference": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_DocumentReference", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -18855,10 +18589,10 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "DocumentReference|bodySite_reference_Task|Task": { + "DocumentReference|reason_reference_DocumentReference|FamilyMemberHistory": { FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_Task", - ToType: "Task", + EdgeLabel: "reason_reference_DocumentReference", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18869,13 +18603,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Task/*", + "DocumentReference/*", }, }, - "Task|bodySite_reference_Task|DocumentReference": { - FromType: "Task", - EdgeLabel: "bodySite_reference_Task", - ToType: "DocumentReference", + "FamilyMemberHistory|reason_reference_Task|Task": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_Task", + ToType: "Task", Direction: []string{ "outbound", }, @@ -18889,10 +18623,10 @@ var Traversals = map[string]Traversal{ "Task/*", }, }, - "DocumentReference|bodySite_reference_ImagingStudy|ImagingStudy": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_ImagingStudy", - ToType: "ImagingStudy", + "Task|reason_reference_Task|FamilyMemberHistory": { + FromType: "Task", + EdgeLabel: "reason_reference_Task", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18903,13 +18637,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "ImagingStudy/*", + "Task/*", }, }, - "ImagingStudy|bodySite_reference_ImagingStudy|DocumentReference": { - FromType: "ImagingStudy", - EdgeLabel: "bodySite_reference_ImagingStudy", - ToType: "DocumentReference", + "FamilyMemberHistory|reason_reference_ImagingStudy|ImagingStudy": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_ImagingStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -18923,9 +18657,9 @@ var Traversals = map[string]Traversal{ "ImagingStudy/*", }, }, - "DocumentReference|bodySite_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_FamilyMemberHistory", + "ImagingStudy|reason_reference_ImagingStudy|FamilyMemberHistory": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_ImagingStudy", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -18937,13 +18671,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "ImagingStudy/*", }, }, - "FamilyMemberHistory|bodySite_reference_FamilyMemberHistory|DocumentReference": { + "FamilyMemberHistory|reason_reference_FamilyMemberHistory|FamilyMemberHistory": { FromType: "FamilyMemberHistory", - EdgeLabel: "bodySite_reference_FamilyMemberHistory", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_FamilyMemberHistory", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18957,9 +18691,9 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "DocumentReference|bodySite_reference_BodyStructure|BodyStructure": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_BodyStructure", + "FamilyMemberHistory|reason_reference_BodyStructure|BodyStructure": { + FromType: "FamilyMemberHistory", + EdgeLabel: "reason_reference_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", @@ -18974,10 +18708,10 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "BodyStructure|bodySite_reference_BodyStructure|DocumentReference": { + "BodyStructure|reason_reference_BodyStructure|FamilyMemberHistory": { FromType: "BodyStructure", - EdgeLabel: "bodySite_reference_BodyStructure", - ToType: "DocumentReference", + EdgeLabel: "reason_reference_BodyStructure", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -18991,9 +18725,9 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "DocumentReference|event_reference_Organization|Organization": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_Organization", + "Group|managingEntity_Organization|Organization": { + FromType: "Group", + EdgeLabel: "managingEntity_Organization", ToType: "Organization", Direction: []string{ "outbound", @@ -19002,16 +18736,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group", }, RegexMatch: []string{ "Organization/*", }, }, - "Organization|event_reference_Organization|DocumentReference": { + "Organization|managingEntity_Organization|Group": { FromType: "Organization", - EdgeLabel: "event_reference_Organization", - ToType: "DocumentReference", + EdgeLabel: "managingEntity_Organization", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19019,16 +18753,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group", }, RegexMatch: []string{ "Organization/*", }, }, - "DocumentReference|event_reference_Group|Group": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_Group", - ToType: "Group", + "Group|managingEntity_Practitioner|Practitioner": { + FromType: "Group", + EdgeLabel: "managingEntity_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -19036,16 +18770,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group", }, RegexMatch: []string{ - "Group/*", + "Practitioner/*", }, }, - "Group|event_reference_Group|DocumentReference": { - FromType: "Group", - EdgeLabel: "event_reference_Group", - ToType: "DocumentReference", + "Practitioner|managingEntity_Practitioner|Group": { + FromType: "Practitioner", + EdgeLabel: "managingEntity_Practitioner", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19053,16 +18787,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group", }, RegexMatch: []string{ - "Group/*", + "Practitioner/*", }, }, - "DocumentReference|event_reference_Practitioner|Practitioner": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_Practitioner", - ToType: "Practitioner", + "Group|managingEntity_PractitionerRole|PractitionerRole": { + FromType: "Group", + EdgeLabel: "managingEntity_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -19070,16 +18804,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group", }, RegexMatch: []string{ - "Practitioner/*", + "PractitionerRole/*", }, }, - "Practitioner|event_reference_Practitioner|DocumentReference": { - FromType: "Practitioner", - EdgeLabel: "event_reference_Practitioner", - ToType: "DocumentReference", + "PractitionerRole|managingEntity_PractitionerRole|Group": { + FromType: "PractitionerRole", + EdgeLabel: "managingEntity_PractitionerRole", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19087,16 +18821,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group", }, RegexMatch: []string{ - "Practitioner/*", + "PractitionerRole/*", }, }, - "DocumentReference|event_reference_PractitionerRole|PractitionerRole": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_PractitionerRole", - ToType: "PractitionerRole", + "Group|characteristic_valueReference_Organization|Organization": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -19104,16 +18838,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ - "PractitionerRole/*", + "Organization/*", }, }, - "PractitionerRole|event_reference_PractitionerRole|DocumentReference": { - FromType: "PractitionerRole", - EdgeLabel: "event_reference_PractitionerRole", - ToType: "DocumentReference", + "Organization|characteristic_valueReference_Organization|Group": { + FromType: "Organization", + EdgeLabel: "characteristic_valueReference_Organization", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19121,15 +18855,100 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", + }, + RegexMatch: []string{ + "Organization/*", + }, + }, + "Group|characteristic_valueReference_Group|Group": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_Group", + ToType: "Group", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "group_characteristic", + }, + RegexMatch: []string{ + "Group/*", + }, + }, + "Group|characteristic_valueReference_Practitioner|Practitioner": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_Practitioner", + ToType: "Practitioner", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "group_characteristic", + }, + RegexMatch: []string{ + "Practitioner/*", + }, + }, + "Practitioner|characteristic_valueReference_Practitioner|Group": { + FromType: "Practitioner", + EdgeLabel: "characteristic_valueReference_Practitioner", + ToType: "Group", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "group_characteristic", + }, + RegexMatch: []string{ + "Practitioner/*", + }, + }, + "Group|characteristic_valueReference_PractitionerRole|PractitionerRole": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_PractitionerRole", + ToType: "PractitionerRole", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "group_characteristic", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "DocumentReference|event_reference_ResearchStudy|ResearchStudy": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_ResearchStudy", + "PractitionerRole|characteristic_valueReference_PractitionerRole|Group": { + FromType: "PractitionerRole", + EdgeLabel: "characteristic_valueReference_PractitionerRole", + ToType: "Group", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "group_characteristic", + }, + RegexMatch: []string{ + "PractitionerRole/*", + }, + }, + "Group|characteristic_valueReference_ResearchStudy|ResearchStudy": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -19138,16 +18957,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "ResearchStudy|event_reference_ResearchStudy|DocumentReference": { + "ResearchStudy|characteristic_valueReference_ResearchStudy|Group": { FromType: "ResearchStudy", - EdgeLabel: "event_reference_ResearchStudy", - ToType: "DocumentReference", + EdgeLabel: "characteristic_valueReference_ResearchStudy", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19155,15 +18974,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "DocumentReference|event_reference_Patient|Patient": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_Patient", + "Group|characteristic_valueReference_Patient|Patient": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -19172,16 +18991,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|event_reference_Patient|DocumentReference": { + "Patient|characteristic_valueReference_Patient|Group": { FromType: "Patient", - EdgeLabel: "event_reference_Patient", - ToType: "DocumentReference", + EdgeLabel: "characteristic_valueReference_Patient", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19189,15 +19008,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "Patient/*", }, }, - "DocumentReference|event_reference_ResearchSubject|ResearchSubject": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_ResearchSubject", + "Group|characteristic_valueReference_ResearchSubject|ResearchSubject": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -19206,16 +19025,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "ResearchSubject|event_reference_ResearchSubject|DocumentReference": { + "ResearchSubject|characteristic_valueReference_ResearchSubject|Group": { FromType: "ResearchSubject", - EdgeLabel: "event_reference_ResearchSubject", - ToType: "DocumentReference", + EdgeLabel: "characteristic_valueReference_ResearchSubject", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19223,15 +19042,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "DocumentReference|event_reference_Substance|Substance": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_Substance", + "Group|characteristic_valueReference_Substance|Substance": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -19240,16 +19059,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "Substance/*", }, }, - "Substance|event_reference_Substance|DocumentReference": { + "Substance|characteristic_valueReference_Substance|Group": { FromType: "Substance", - EdgeLabel: "event_reference_Substance", - ToType: "DocumentReference", + EdgeLabel: "characteristic_valueReference_Substance", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19257,15 +19076,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "Substance/*", }, }, - "DocumentReference|event_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_SubstanceDefinition", + "Group|characteristic_valueReference_SubstanceDefinition|SubstanceDefinition": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -19274,16 +19093,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|event_reference_SubstanceDefinition|DocumentReference": { + "SubstanceDefinition|characteristic_valueReference_SubstanceDefinition|Group": { FromType: "SubstanceDefinition", - EdgeLabel: "event_reference_SubstanceDefinition", - ToType: "DocumentReference", + EdgeLabel: "characteristic_valueReference_SubstanceDefinition", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19291,15 +19110,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "DocumentReference|event_reference_Specimen|Specimen": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_Specimen", + "Group|characteristic_valueReference_Specimen|Specimen": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -19308,16 +19127,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "Specimen/*", }, }, - "Specimen|event_reference_Specimen|DocumentReference": { + "Specimen|characteristic_valueReference_Specimen|Group": { FromType: "Specimen", - EdgeLabel: "event_reference_Specimen", - ToType: "DocumentReference", + EdgeLabel: "characteristic_valueReference_Specimen", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19325,15 +19144,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "Specimen/*", }, }, - "DocumentReference|event_reference_Observation|Observation": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_Observation", + "Group|characteristic_valueReference_Observation|Observation": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -19342,16 +19161,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "Observation/*", }, }, - "Observation|event_reference_Observation|DocumentReference": { + "Observation|characteristic_valueReference_Observation|Group": { FromType: "Observation", - EdgeLabel: "event_reference_Observation", - ToType: "DocumentReference", + EdgeLabel: "characteristic_valueReference_Observation", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19359,15 +19178,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "Observation/*", }, }, - "DocumentReference|event_reference_DiagnosticReport|DiagnosticReport": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_DiagnosticReport", + "Group|characteristic_valueReference_DiagnosticReport|DiagnosticReport": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -19376,16 +19195,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "DiagnosticReport|event_reference_DiagnosticReport|DocumentReference": { + "DiagnosticReport|characteristic_valueReference_DiagnosticReport|Group": { FromType: "DiagnosticReport", - EdgeLabel: "event_reference_DiagnosticReport", - ToType: "DocumentReference", + EdgeLabel: "characteristic_valueReference_DiagnosticReport", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19393,15 +19212,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "DocumentReference|event_reference_Condition|Condition": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_Condition", + "Group|characteristic_valueReference_Condition|Condition": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -19410,16 +19229,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "Condition/*", }, }, - "Condition|event_reference_Condition|DocumentReference": { + "Condition|characteristic_valueReference_Condition|Group": { FromType: "Condition", - EdgeLabel: "event_reference_Condition", - ToType: "DocumentReference", + EdgeLabel: "characteristic_valueReference_Condition", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19427,15 +19246,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "Condition/*", }, }, - "DocumentReference|event_reference_Medication|Medication": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_Medication", + "Group|characteristic_valueReference_Medication|Medication": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -19444,16 +19263,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "Medication/*", }, }, - "Medication|event_reference_Medication|DocumentReference": { + "Medication|characteristic_valueReference_Medication|Group": { FromType: "Medication", - EdgeLabel: "event_reference_Medication", - ToType: "DocumentReference", + EdgeLabel: "characteristic_valueReference_Medication", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19461,15 +19280,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "Medication/*", }, }, - "DocumentReference|event_reference_MedicationAdministration|MedicationAdministration": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_MedicationAdministration", + "Group|characteristic_valueReference_MedicationAdministration|MedicationAdministration": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -19478,16 +19297,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "MedicationAdministration|event_reference_MedicationAdministration|DocumentReference": { + "MedicationAdministration|characteristic_valueReference_MedicationAdministration|Group": { FromType: "MedicationAdministration", - EdgeLabel: "event_reference_MedicationAdministration", - ToType: "DocumentReference", + EdgeLabel: "characteristic_valueReference_MedicationAdministration", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19495,15 +19314,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "DocumentReference|event_reference_MedicationStatement|MedicationStatement": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_MedicationStatement", + "Group|characteristic_valueReference_MedicationStatement|MedicationStatement": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -19512,16 +19331,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "MedicationStatement|event_reference_MedicationStatement|DocumentReference": { + "MedicationStatement|characteristic_valueReference_MedicationStatement|Group": { FromType: "MedicationStatement", - EdgeLabel: "event_reference_MedicationStatement", - ToType: "DocumentReference", + EdgeLabel: "characteristic_valueReference_MedicationStatement", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19529,15 +19348,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "DocumentReference|event_reference_MedicationRequest|MedicationRequest": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_MedicationRequest", + "Group|characteristic_valueReference_MedicationRequest|MedicationRequest": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -19546,16 +19365,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "MedicationRequest|event_reference_MedicationRequest|DocumentReference": { + "MedicationRequest|characteristic_valueReference_MedicationRequest|Group": { FromType: "MedicationRequest", - EdgeLabel: "event_reference_MedicationRequest", - ToType: "DocumentReference", + EdgeLabel: "characteristic_valueReference_MedicationRequest", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19563,15 +19382,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "DocumentReference|event_reference_Procedure|Procedure": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_Procedure", + "Group|characteristic_valueReference_Procedure|Procedure": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_Procedure", ToType: "Procedure", Direction: []string{ "outbound", @@ -19580,16 +19399,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "Procedure/*", }, }, - "Procedure|event_reference_Procedure|DocumentReference": { + "Procedure|characteristic_valueReference_Procedure|Group": { FromType: "Procedure", - EdgeLabel: "event_reference_Procedure", - ToType: "DocumentReference", + EdgeLabel: "characteristic_valueReference_Procedure", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19597,15 +19416,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "Procedure/*", }, }, - "DocumentReference|event_reference_DocumentReference|DocumentReference": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_DocumentReference", + "Group|characteristic_valueReference_DocumentReference|DocumentReference": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_DocumentReference", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -19614,15 +19433,32 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "DocumentReference/*", }, }, - "DocumentReference|event_reference_Task|Task": { + "DocumentReference|characteristic_valueReference_DocumentReference|Group": { FromType: "DocumentReference", - EdgeLabel: "event_reference_Task", + EdgeLabel: "characteristic_valueReference_DocumentReference", + ToType: "Group", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "group_characteristic", + }, + RegexMatch: []string{ + "DocumentReference/*", + }, + }, + "Group|characteristic_valueReference_Task|Task": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_Task", ToType: "Task", Direction: []string{ "outbound", @@ -19631,16 +19467,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "Task/*", }, }, - "Task|event_reference_Task|DocumentReference": { + "Task|characteristic_valueReference_Task|Group": { FromType: "Task", - EdgeLabel: "event_reference_Task", - ToType: "DocumentReference", + EdgeLabel: "characteristic_valueReference_Task", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19648,15 +19484,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "Task/*", }, }, - "DocumentReference|event_reference_ImagingStudy|ImagingStudy": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_ImagingStudy", + "Group|characteristic_valueReference_ImagingStudy|ImagingStudy": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", @@ -19665,16 +19501,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "ImagingStudy/*", }, }, - "ImagingStudy|event_reference_ImagingStudy|DocumentReference": { + "ImagingStudy|characteristic_valueReference_ImagingStudy|Group": { FromType: "ImagingStudy", - EdgeLabel: "event_reference_ImagingStudy", - ToType: "DocumentReference", + EdgeLabel: "characteristic_valueReference_ImagingStudy", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19682,15 +19518,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "ImagingStudy/*", }, }, - "DocumentReference|event_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_FamilyMemberHistory", + "Group|characteristic_valueReference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -19699,16 +19535,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|event_reference_FamilyMemberHistory|DocumentReference": { + "FamilyMemberHistory|characteristic_valueReference_FamilyMemberHistory|Group": { FromType: "FamilyMemberHistory", - EdgeLabel: "event_reference_FamilyMemberHistory", - ToType: "DocumentReference", + EdgeLabel: "characteristic_valueReference_FamilyMemberHistory", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19716,15 +19552,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "FamilyMemberHistory/*", }, }, - "DocumentReference|event_reference_BodyStructure|BodyStructure": { - FromType: "DocumentReference", - EdgeLabel: "event_reference_BodyStructure", + "Group|characteristic_valueReference_BodyStructure|BodyStructure": { + FromType: "Group", + EdgeLabel: "characteristic_valueReference_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", @@ -19733,16 +19569,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "BodyStructure/*", }, }, - "BodyStructure|event_reference_BodyStructure|DocumentReference": { + "BodyStructure|characteristic_valueReference_BodyStructure|Group": { FromType: "BodyStructure", - EdgeLabel: "event_reference_BodyStructure", - ToType: "DocumentReference", + EdgeLabel: "characteristic_valueReference_BodyStructure", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19750,16 +19586,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "group_characteristic", }, RegexMatch: []string{ "BodyStructure/*", }, }, - "DocumentReference|relatesTo_target|DocumentReference": { - FromType: "DocumentReference", - EdgeLabel: "relatesTo_target", - ToType: "DocumentReference", + "Group|member_entity_Group|Group": { + FromType: "Group", + EdgeLabel: "member_entity_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19767,16 +19603,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference_relates_to", + "group_member", }, RegexMatch: []string{ - "DocumentReference/*", + "Group/*", }, }, - "DocumentReferenceAttester|party_Patient|Patient": { - FromType: "DocumentReferenceAttester", - EdgeLabel: "party_Patient", - ToType: "Patient", + "Group|member_entity_Organization|Organization": { + FromType: "Group", + EdgeLabel: "member_entity_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -19784,16 +19620,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference_attester", + "group_member", }, RegexMatch: []string{ - "Patient/*", + "Organization/*", }, }, - "Patient|party_Patient|DocumentReferenceAttester": { - FromType: "Patient", - EdgeLabel: "party_Patient", - ToType: "DocumentReferenceAttester", + "Organization|member_entity_Organization|Group": { + FromType: "Organization", + EdgeLabel: "member_entity_Organization", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19801,16 +19637,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference_attester", + "group_member", }, RegexMatch: []string{ - "Patient/*", + "Organization/*", }, }, - "DocumentReferenceAttester|party_Practitioner|Practitioner": { - FromType: "DocumentReferenceAttester", - EdgeLabel: "party_Practitioner", - ToType: "Practitioner", + "Group|member_entity_Patient|Patient": { + FromType: "Group", + EdgeLabel: "member_entity_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -19818,16 +19654,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference_attester", + "group_member", }, RegexMatch: []string{ - "Practitioner/*", + "Patient/*", }, }, - "Practitioner|party_Practitioner|DocumentReferenceAttester": { - FromType: "Practitioner", - EdgeLabel: "party_Practitioner", - ToType: "DocumentReferenceAttester", + "Patient|member_entity_Patient|Group": { + FromType: "Patient", + EdgeLabel: "member_entity_Patient", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19835,16 +19671,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference_attester", + "group_member", }, RegexMatch: []string{ - "Practitioner/*", + "Patient/*", }, }, - "DocumentReferenceAttester|party_PractitionerRole|PractitionerRole": { - FromType: "DocumentReferenceAttester", - EdgeLabel: "party_PractitionerRole", - ToType: "PractitionerRole", + "Group|member_entity_Practitioner|Practitioner": { + FromType: "Group", + EdgeLabel: "member_entity_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -19852,16 +19688,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference_attester", + "group_member", }, RegexMatch: []string{ - "PractitionerRole/*", + "Practitioner/*", }, }, - "PractitionerRole|party_PractitionerRole|DocumentReferenceAttester": { - FromType: "PractitionerRole", - EdgeLabel: "party_PractitionerRole", - ToType: "DocumentReferenceAttester", + "Practitioner|member_entity_Practitioner|Group": { + FromType: "Practitioner", + EdgeLabel: "member_entity_Practitioner", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19869,16 +19705,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference_attester", + "group_member", }, RegexMatch: []string{ - "PractitionerRole/*", + "Practitioner/*", }, }, - "DocumentReferenceAttester|party_Organization|Organization": { - FromType: "DocumentReferenceAttester", - EdgeLabel: "party_Organization", - ToType: "Organization", + "Group|member_entity_PractitionerRole|PractitionerRole": { + FromType: "Group", + EdgeLabel: "member_entity_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -19886,16 +19722,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference_attester", + "group_member", }, RegexMatch: []string{ - "Organization/*", + "PractitionerRole/*", }, }, - "Organization|party_Organization|DocumentReferenceAttester": { - FromType: "Organization", - EdgeLabel: "party_Organization", - ToType: "DocumentReferenceAttester", + "PractitionerRole|member_entity_PractitionerRole|Group": { + FromType: "PractitionerRole", + EdgeLabel: "member_entity_PractitionerRole", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19903,16 +19739,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference_attester", + "group_member", }, RegexMatch: []string{ - "Organization/*", + "PractitionerRole/*", }, }, - "DocumentReferenceRelatesTo|target|DocumentReference": { - FromType: "DocumentReferenceRelatesTo", - EdgeLabel: "target", - ToType: "DocumentReference", + "Group|member_entity_Specimen|Specimen": { + FromType: "Group", + EdgeLabel: "member_entity_Specimen", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -19920,16 +19756,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference_relates_to", + "group_member", }, RegexMatch: []string{ - "DocumentReference/*", + "Specimen/*", }, }, - "DocumentReference|target|DocumentReferenceRelatesTo": { - FromType: "DocumentReference", - EdgeLabel: "target", - ToType: "DocumentReferenceRelatesTo", + "Specimen|member_entity_Specimen|Group": { + FromType: "Specimen", + EdgeLabel: "member_entity_Specimen", + ToType: "Group", Direction: []string{ "outbound", }, @@ -19937,84 +19773,84 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "document_reference_relates_to", + "group_member", }, RegexMatch: []string{ - "DocumentReference/*", + "Specimen/*", }, }, - "ExtendedContactDetail|organization|Organization": { - FromType: "ExtendedContactDetail", - EdgeLabel: "organization", - ToType: "Organization", + "ImagingStudy|basedOn_Task|Task": { + FromType: "ImagingStudy", + EdgeLabel: "basedOn_Task", + ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "extended_contact_detail", + "basedOn_imaging_study", }, RegexMatch: []string{ - "Organization/*", + "Task/*", }, }, - "Organization|organization|ExtendedContactDetail": { - FromType: "Organization", - EdgeLabel: "organization", - ToType: "ExtendedContactDetail", + "Task|basedOn_Task|ImagingStudy": { + FromType: "Task", + EdgeLabel: "basedOn_Task", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "extended_contact_detail", + "basedOn_imaging_study", }, RegexMatch: []string{ - "Organization/*", + "Task/*", }, }, - "Extension|valueReference_Organization|Organization": { - FromType: "Extension", - EdgeLabel: "valueReference_Organization", - ToType: "Organization", + "ImagingStudy|partOf|Procedure": { + FromType: "ImagingStudy", + EdgeLabel: "partOf", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "extension", + "partOf_imaging_study", }, RegexMatch: []string{ - "Organization/*", + "Procedure/*", }, }, - "Organization|valueReference_Organization|Extension": { - FromType: "Organization", - EdgeLabel: "valueReference_Organization", - ToType: "Extension", + "Procedure|partOf|ImagingStudy": { + FromType: "Procedure", + EdgeLabel: "partOf", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "extension", + "partOf_imaging_study", }, RegexMatch: []string{ - "Organization/*", + "Procedure/*", }, }, - "Extension|valueReference_Group|Group": { - FromType: "Extension", - EdgeLabel: "valueReference_Group", - ToType: "Group", + "ImagingStudy|referrer_Practitioner|Practitioner": { + FromType: "ImagingStudy", + EdgeLabel: "referrer_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -20022,16 +19858,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "imaging_study", }, RegexMatch: []string{ - "Group/*", + "Practitioner/*", }, }, - "Group|valueReference_Group|Extension": { - FromType: "Group", - EdgeLabel: "valueReference_Group", - ToType: "Extension", + "Practitioner|referrer_Practitioner|ImagingStudy": { + FromType: "Practitioner", + EdgeLabel: "referrer_Practitioner", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20039,16 +19875,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "imaging_study", }, RegexMatch: []string{ - "Group/*", + "Practitioner/*", }, }, - "Extension|valueReference_Practitioner|Practitioner": { - FromType: "Extension", - EdgeLabel: "valueReference_Practitioner", - ToType: "Practitioner", + "ImagingStudy|referrer_PractitionerRole|PractitionerRole": { + FromType: "ImagingStudy", + EdgeLabel: "referrer_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -20056,16 +19892,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "imaging_study", }, RegexMatch: []string{ - "Practitioner/*", + "PractitionerRole/*", }, }, - "Practitioner|valueReference_Practitioner|Extension": { - FromType: "Practitioner", - EdgeLabel: "valueReference_Practitioner", - ToType: "Extension", + "PractitionerRole|referrer_PractitionerRole|ImagingStudy": { + FromType: "PractitionerRole", + EdgeLabel: "referrer_PractitionerRole", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20073,16 +19909,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "imaging_study", }, RegexMatch: []string{ - "Practitioner/*", + "PractitionerRole/*", }, }, - "Extension|valueReference_PractitionerRole|PractitionerRole": { - FromType: "Extension", - EdgeLabel: "valueReference_PractitionerRole", - ToType: "PractitionerRole", + "ImagingStudy|subject_Patient|Patient": { + FromType: "ImagingStudy", + EdgeLabel: "subject_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -20090,16 +19926,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "imaging_study", }, RegexMatch: []string{ - "PractitionerRole/*", + "Patient/*", }, }, - "PractitionerRole|valueReference_PractitionerRole|Extension": { - FromType: "PractitionerRole", - EdgeLabel: "valueReference_PractitionerRole", - ToType: "Extension", + "Patient|subject_Patient|ImagingStudy": { + FromType: "Patient", + EdgeLabel: "subject_Patient", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20107,16 +19943,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "imaging_study", }, RegexMatch: []string{ - "PractitionerRole/*", + "Patient/*", }, }, - "Extension|valueReference_ResearchStudy|ResearchStudy": { - FromType: "Extension", - EdgeLabel: "valueReference_ResearchStudy", - ToType: "ResearchStudy", + "ImagingStudy|subject_Group|Group": { + FromType: "ImagingStudy", + EdgeLabel: "subject_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -20124,16 +19960,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "imaging_study", }, RegexMatch: []string{ - "ResearchStudy/*", + "Group/*", }, }, - "ResearchStudy|valueReference_ResearchStudy|Extension": { - FromType: "ResearchStudy", - EdgeLabel: "valueReference_ResearchStudy", - ToType: "Extension", + "Group|subject_Group|ImagingStudy": { + FromType: "Group", + EdgeLabel: "subject_Group", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20141,16 +19977,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "imaging_study", }, RegexMatch: []string{ - "ResearchStudy/*", + "Group/*", }, }, - "Extension|valueReference_Patient|Patient": { - FromType: "Extension", - EdgeLabel: "valueReference_Patient", - ToType: "Patient", + "ImagingStudy|note_authorReference_Practitioner|Practitioner": { + FromType: "ImagingStudy", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -20158,16 +19994,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "annotation", }, RegexMatch: []string{ - "Patient/*", + "Practitioner/*", }, }, - "Patient|valueReference_Patient|Extension": { - FromType: "Patient", - EdgeLabel: "valueReference_Patient", - ToType: "Extension", + "Practitioner|note_authorReference_Practitioner|ImagingStudy": { + FromType: "Practitioner", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20175,16 +20011,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "annotation", }, RegexMatch: []string{ - "Patient/*", + "Practitioner/*", }, }, - "Extension|valueReference_ResearchSubject|ResearchSubject": { - FromType: "Extension", - EdgeLabel: "valueReference_ResearchSubject", - ToType: "ResearchSubject", + "ImagingStudy|note_authorReference_PractitionerRole|PractitionerRole": { + FromType: "ImagingStudy", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -20192,16 +20028,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "annotation", }, RegexMatch: []string{ - "ResearchSubject/*", + "PractitionerRole/*", }, }, - "ResearchSubject|valueReference_ResearchSubject|Extension": { - FromType: "ResearchSubject", - EdgeLabel: "valueReference_ResearchSubject", - ToType: "Extension", + "PractitionerRole|note_authorReference_PractitionerRole|ImagingStudy": { + FromType: "PractitionerRole", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20209,16 +20045,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "annotation", }, RegexMatch: []string{ - "ResearchSubject/*", + "PractitionerRole/*", }, }, - "Extension|valueReference_Substance|Substance": { - FromType: "Extension", - EdgeLabel: "valueReference_Substance", - ToType: "Substance", + "ImagingStudy|note_authorReference_Patient|Patient": { + FromType: "ImagingStudy", + EdgeLabel: "note_authorReference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -20226,16 +20062,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "annotation", }, RegexMatch: []string{ - "Substance/*", + "Patient/*", }, }, - "Substance|valueReference_Substance|Extension": { - FromType: "Substance", - EdgeLabel: "valueReference_Substance", - ToType: "Extension", + "Patient|note_authorReference_Patient|ImagingStudy": { + FromType: "Patient", + EdgeLabel: "note_authorReference_Patient", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20243,16 +20079,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "annotation", }, RegexMatch: []string{ - "Substance/*", + "Patient/*", }, }, - "Extension|valueReference_SubstanceDefinition|SubstanceDefinition": { - FromType: "Extension", - EdgeLabel: "valueReference_SubstanceDefinition", - ToType: "SubstanceDefinition", + "ImagingStudy|note_authorReference_Organization|Organization": { + FromType: "ImagingStudy", + EdgeLabel: "note_authorReference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -20260,16 +20096,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "annotation", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "Organization/*", }, }, - "SubstanceDefinition|valueReference_SubstanceDefinition|Extension": { - FromType: "SubstanceDefinition", - EdgeLabel: "valueReference_SubstanceDefinition", - ToType: "Extension", + "Organization|note_authorReference_Organization|ImagingStudy": { + FromType: "Organization", + EdgeLabel: "note_authorReference_Organization", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20277,16 +20113,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "annotation", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "Organization/*", }, }, - "Extension|valueReference_Specimen|Specimen": { - FromType: "Extension", - EdgeLabel: "valueReference_Specimen", - ToType: "Specimen", + "ImagingStudy|procedure_reference_Organization|Organization": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -20294,16 +20130,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "Specimen/*", + "Organization/*", }, }, - "Specimen|valueReference_Specimen|Extension": { - FromType: "Specimen", - EdgeLabel: "valueReference_Specimen", - ToType: "Extension", + "Organization|procedure_reference_Organization|ImagingStudy": { + FromType: "Organization", + EdgeLabel: "procedure_reference_Organization", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20311,16 +20147,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "Specimen/*", + "Organization/*", }, }, - "Extension|valueReference_Observation|Observation": { - FromType: "Extension", - EdgeLabel: "valueReference_Observation", - ToType: "Observation", + "ImagingStudy|procedure_reference_Group|Group": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -20328,16 +20164,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "Observation/*", + "Group/*", }, }, - "Observation|valueReference_Observation|Extension": { - FromType: "Observation", - EdgeLabel: "valueReference_Observation", - ToType: "Extension", + "Group|procedure_reference_Group|ImagingStudy": { + FromType: "Group", + EdgeLabel: "procedure_reference_Group", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20345,16 +20181,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "Observation/*", + "Group/*", }, }, - "Extension|valueReference_DiagnosticReport|DiagnosticReport": { - FromType: "Extension", - EdgeLabel: "valueReference_DiagnosticReport", - ToType: "DiagnosticReport", + "ImagingStudy|procedure_reference_Practitioner|Practitioner": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -20362,16 +20198,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Practitioner/*", }, }, - "DiagnosticReport|valueReference_DiagnosticReport|Extension": { - FromType: "DiagnosticReport", - EdgeLabel: "valueReference_DiagnosticReport", - ToType: "Extension", + "Practitioner|procedure_reference_Practitioner|ImagingStudy": { + FromType: "Practitioner", + EdgeLabel: "procedure_reference_Practitioner", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20379,16 +20215,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Practitioner/*", }, }, - "Extension|valueReference_Condition|Condition": { - FromType: "Extension", - EdgeLabel: "valueReference_Condition", - ToType: "Condition", + "ImagingStudy|procedure_reference_PractitionerRole|PractitionerRole": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -20396,16 +20232,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "Condition/*", + "PractitionerRole/*", }, }, - "Condition|valueReference_Condition|Extension": { - FromType: "Condition", - EdgeLabel: "valueReference_Condition", - ToType: "Extension", + "PractitionerRole|procedure_reference_PractitionerRole|ImagingStudy": { + FromType: "PractitionerRole", + EdgeLabel: "procedure_reference_PractitionerRole", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20413,16 +20249,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "Condition/*", + "PractitionerRole/*", }, }, - "Extension|valueReference_Medication|Medication": { - FromType: "Extension", - EdgeLabel: "valueReference_Medication", - ToType: "Medication", + "ImagingStudy|procedure_reference_ResearchStudy|ResearchStudy": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_ResearchStudy", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -20430,16 +20266,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "Medication/*", + "ResearchStudy/*", }, }, - "Medication|valueReference_Medication|Extension": { - FromType: "Medication", - EdgeLabel: "valueReference_Medication", - ToType: "Extension", + "ResearchStudy|procedure_reference_ResearchStudy|ImagingStudy": { + FromType: "ResearchStudy", + EdgeLabel: "procedure_reference_ResearchStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20447,16 +20283,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "Medication/*", + "ResearchStudy/*", }, }, - "Extension|valueReference_MedicationAdministration|MedicationAdministration": { - FromType: "Extension", - EdgeLabel: "valueReference_MedicationAdministration", - ToType: "MedicationAdministration", + "ImagingStudy|procedure_reference_Patient|Patient": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -20464,16 +20300,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Patient/*", }, }, - "MedicationAdministration|valueReference_MedicationAdministration|Extension": { - FromType: "MedicationAdministration", - EdgeLabel: "valueReference_MedicationAdministration", - ToType: "Extension", + "Patient|procedure_reference_Patient|ImagingStudy": { + FromType: "Patient", + EdgeLabel: "procedure_reference_Patient", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20481,16 +20317,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Patient/*", }, }, - "Extension|valueReference_MedicationStatement|MedicationStatement": { - FromType: "Extension", - EdgeLabel: "valueReference_MedicationStatement", - ToType: "MedicationStatement", + "ImagingStudy|procedure_reference_ResearchSubject|ResearchSubject": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_ResearchSubject", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, @@ -20498,16 +20334,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "MedicationStatement/*", + "ResearchSubject/*", }, }, - "MedicationStatement|valueReference_MedicationStatement|Extension": { - FromType: "MedicationStatement", - EdgeLabel: "valueReference_MedicationStatement", - ToType: "Extension", + "ResearchSubject|procedure_reference_ResearchSubject|ImagingStudy": { + FromType: "ResearchSubject", + EdgeLabel: "procedure_reference_ResearchSubject", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20515,16 +20351,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "MedicationStatement/*", + "ResearchSubject/*", }, }, - "Extension|valueReference_MedicationRequest|MedicationRequest": { - FromType: "Extension", - EdgeLabel: "valueReference_MedicationRequest", - ToType: "MedicationRequest", + "ImagingStudy|procedure_reference_Substance|Substance": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_Substance", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -20532,16 +20368,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "MedicationRequest/*", + "Substance/*", }, }, - "MedicationRequest|valueReference_MedicationRequest|Extension": { - FromType: "MedicationRequest", - EdgeLabel: "valueReference_MedicationRequest", - ToType: "Extension", + "Substance|procedure_reference_Substance|ImagingStudy": { + FromType: "Substance", + EdgeLabel: "procedure_reference_Substance", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20549,16 +20385,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "MedicationRequest/*", + "Substance/*", }, }, - "Extension|valueReference_Procedure|Procedure": { - FromType: "Extension", - EdgeLabel: "valueReference_Procedure", - ToType: "Procedure", + "ImagingStudy|procedure_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_SubstanceDefinition", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, @@ -20566,16 +20402,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "Procedure/*", + "SubstanceDefinition/*", }, }, - "Procedure|valueReference_Procedure|Extension": { - FromType: "Procedure", - EdgeLabel: "valueReference_Procedure", - ToType: "Extension", + "SubstanceDefinition|procedure_reference_SubstanceDefinition|ImagingStudy": { + FromType: "SubstanceDefinition", + EdgeLabel: "procedure_reference_SubstanceDefinition", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20583,16 +20419,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "Procedure/*", + "SubstanceDefinition/*", }, }, - "Extension|valueReference_DocumentReference|DocumentReference": { - FromType: "Extension", - EdgeLabel: "valueReference_DocumentReference", - ToType: "DocumentReference", + "ImagingStudy|procedure_reference_Specimen|Specimen": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_Specimen", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -20600,16 +20436,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "DocumentReference/*", + "Specimen/*", }, }, - "DocumentReference|valueReference_DocumentReference|Extension": { - FromType: "DocumentReference", - EdgeLabel: "valueReference_DocumentReference", - ToType: "Extension", + "Specimen|procedure_reference_Specimen|ImagingStudy": { + FromType: "Specimen", + EdgeLabel: "procedure_reference_Specimen", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20617,16 +20453,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "DocumentReference/*", + "Specimen/*", }, }, - "Extension|valueReference_Task|Task": { - FromType: "Extension", - EdgeLabel: "valueReference_Task", - ToType: "Task", + "ImagingStudy|procedure_reference_Observation|Observation": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_Observation", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -20634,16 +20470,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "Task/*", + "Observation/*", }, }, - "Task|valueReference_Task|Extension": { - FromType: "Task", - EdgeLabel: "valueReference_Task", - ToType: "Extension", + "Observation|procedure_reference_Observation|ImagingStudy": { + FromType: "Observation", + EdgeLabel: "procedure_reference_Observation", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20651,16 +20487,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "Task/*", + "Observation/*", }, }, - "Extension|valueReference_ImagingStudy|ImagingStudy": { - FromType: "Extension", - EdgeLabel: "valueReference_ImagingStudy", - ToType: "ImagingStudy", + "ImagingStudy|procedure_reference_DiagnosticReport|DiagnosticReport": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_DiagnosticReport", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -20668,16 +20504,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "ImagingStudy/*", + "DiagnosticReport/*", }, }, - "ImagingStudy|valueReference_ImagingStudy|Extension": { - FromType: "ImagingStudy", - EdgeLabel: "valueReference_ImagingStudy", - ToType: "Extension", + "DiagnosticReport|procedure_reference_DiagnosticReport|ImagingStudy": { + FromType: "DiagnosticReport", + EdgeLabel: "procedure_reference_DiagnosticReport", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20685,16 +20521,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "ImagingStudy/*", + "DiagnosticReport/*", }, }, - "Extension|valueReference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "Extension", - EdgeLabel: "valueReference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", + "ImagingStudy|procedure_reference_Condition|Condition": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_Condition", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -20702,16 +20538,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Condition/*", }, }, - "FamilyMemberHistory|valueReference_FamilyMemberHistory|Extension": { - FromType: "FamilyMemberHistory", - EdgeLabel: "valueReference_FamilyMemberHistory", - ToType: "Extension", + "Condition|procedure_reference_Condition|ImagingStudy": { + FromType: "Condition", + EdgeLabel: "procedure_reference_Condition", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20719,16 +20555,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Condition/*", }, }, - "Extension|valueReference_BodyStructure|BodyStructure": { - FromType: "Extension", - EdgeLabel: "valueReference_BodyStructure", - ToType: "BodyStructure", + "ImagingStudy|procedure_reference_Medication|Medication": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_Medication", + ToType: "Medication", Direction: []string{ "outbound", }, @@ -20736,16 +20572,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "BodyStructure/*", + "Medication/*", }, }, - "BodyStructure|valueReference_BodyStructure|Extension": { - FromType: "BodyStructure", - EdgeLabel: "valueReference_BodyStructure", - ToType: "Extension", + "Medication|procedure_reference_Medication|ImagingStudy": { + FromType: "Medication", + EdgeLabel: "procedure_reference_Medication", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20753,16 +20589,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extension", + "codeable_reference", }, RegexMatch: []string{ - "BodyStructure/*", + "Medication/*", }, }, - "Extension|valueAnnotation_authorReference_Practitioner|Practitioner": { - FromType: "Extension", - EdgeLabel: "valueAnnotation_authorReference_Practitioner", - ToType: "Practitioner", + "ImagingStudy|procedure_reference_MedicationAdministration|MedicationAdministration": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_MedicationAdministration", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -20770,16 +20606,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "MedicationAdministration/*", }, }, - "Practitioner|valueAnnotation_authorReference_Practitioner|Extension": { - FromType: "Practitioner", - EdgeLabel: "valueAnnotation_authorReference_Practitioner", - ToType: "Extension", + "MedicationAdministration|procedure_reference_MedicationAdministration|ImagingStudy": { + FromType: "MedicationAdministration", + EdgeLabel: "procedure_reference_MedicationAdministration", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20787,16 +20623,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "MedicationAdministration/*", }, }, - "Extension|valueAnnotation_authorReference_PractitionerRole|PractitionerRole": { - FromType: "Extension", - EdgeLabel: "valueAnnotation_authorReference_PractitionerRole", - ToType: "PractitionerRole", + "ImagingStudy|procedure_reference_MedicationStatement|MedicationStatement": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_MedicationStatement", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -20804,16 +20640,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "MedicationStatement/*", }, }, - "PractitionerRole|valueAnnotation_authorReference_PractitionerRole|Extension": { - FromType: "PractitionerRole", - EdgeLabel: "valueAnnotation_authorReference_PractitionerRole", - ToType: "Extension", + "MedicationStatement|procedure_reference_MedicationStatement|ImagingStudy": { + FromType: "MedicationStatement", + EdgeLabel: "procedure_reference_MedicationStatement", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20821,16 +20657,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "MedicationStatement/*", }, }, - "Extension|valueAnnotation_authorReference_Patient|Patient": { - FromType: "Extension", - EdgeLabel: "valueAnnotation_authorReference_Patient", - ToType: "Patient", + "ImagingStudy|procedure_reference_MedicationRequest|MedicationRequest": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_MedicationRequest", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -20838,16 +20674,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "MedicationRequest/*", }, }, - "Patient|valueAnnotation_authorReference_Patient|Extension": { - FromType: "Patient", - EdgeLabel: "valueAnnotation_authorReference_Patient", - ToType: "Extension", + "MedicationRequest|procedure_reference_MedicationRequest|ImagingStudy": { + FromType: "MedicationRequest", + EdgeLabel: "procedure_reference_MedicationRequest", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20855,16 +20691,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "MedicationRequest/*", }, }, - "Extension|valueAnnotation_authorReference_Organization|Organization": { - FromType: "Extension", - EdgeLabel: "valueAnnotation_authorReference_Organization", - ToType: "Organization", + "ImagingStudy|procedure_reference_Procedure|Procedure": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -20872,16 +20708,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Procedure/*", }, }, - "Organization|valueAnnotation_authorReference_Organization|Extension": { - FromType: "Organization", - EdgeLabel: "valueAnnotation_authorReference_Organization", - ToType: "Extension", + "Procedure|procedure_reference_Procedure|ImagingStudy": { + FromType: "Procedure", + EdgeLabel: "procedure_reference_Procedure", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20889,16 +20725,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Procedure/*", }, }, - "Extension|valueCodeableReference_reference_Organization|Organization": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_Organization", - ToType: "Organization", + "ImagingStudy|procedure_reference_DocumentReference|DocumentReference": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -20909,13 +20745,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "DocumentReference/*", }, }, - "Organization|valueCodeableReference_reference_Organization|Extension": { - FromType: "Organization", - EdgeLabel: "valueCodeableReference_reference_Organization", - ToType: "Extension", + "DocumentReference|procedure_reference_DocumentReference|ImagingStudy": { + FromType: "DocumentReference", + EdgeLabel: "procedure_reference_DocumentReference", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20926,13 +20762,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "DocumentReference/*", }, }, - "Extension|valueCodeableReference_reference_Group|Group": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_Group", - ToType: "Group", + "ImagingStudy|procedure_reference_Task|Task": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_Task", + ToType: "Task", Direction: []string{ "outbound", }, @@ -20943,13 +20779,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "Task/*", }, }, - "Group|valueCodeableReference_reference_Group|Extension": { - FromType: "Group", - EdgeLabel: "valueCodeableReference_reference_Group", - ToType: "Extension", + "Task|procedure_reference_Task|ImagingStudy": { + FromType: "Task", + EdgeLabel: "procedure_reference_Task", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20960,13 +20796,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "Task/*", }, }, - "Extension|valueCodeableReference_reference_Practitioner|Practitioner": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_Practitioner", - ToType: "Practitioner", + "ImagingStudy|procedure_reference_ImagingStudy|ImagingStudy": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_ImagingStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -20977,13 +20813,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "ImagingStudy/*", }, }, - "Practitioner|valueCodeableReference_reference_Practitioner|Extension": { - FromType: "Practitioner", - EdgeLabel: "valueCodeableReference_reference_Practitioner", - ToType: "Extension", + "ImagingStudy|procedure_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_FamilyMemberHistory", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -20994,13 +20830,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "FamilyMemberHistory/*", }, }, - "Extension|valueCodeableReference_reference_PractitionerRole|PractitionerRole": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_PractitionerRole", - ToType: "PractitionerRole", + "FamilyMemberHistory|procedure_reference_FamilyMemberHistory|ImagingStudy": { + FromType: "FamilyMemberHistory", + EdgeLabel: "procedure_reference_FamilyMemberHistory", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21011,13 +20847,166 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "FamilyMemberHistory/*", }, }, - "PractitionerRole|valueCodeableReference_reference_PractitionerRole|Extension": { - FromType: "PractitionerRole", - EdgeLabel: "valueCodeableReference_reference_PractitionerRole", - ToType: "Extension", + "ImagingStudy|procedure_reference_BodyStructure|BodyStructure": { + FromType: "ImagingStudy", + EdgeLabel: "procedure_reference_BodyStructure", + ToType: "BodyStructure", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "BodyStructure/*", + }, + }, + "BodyStructure|procedure_reference_BodyStructure|ImagingStudy": { + FromType: "BodyStructure", + EdgeLabel: "procedure_reference_BodyStructure", + ToType: "ImagingStudy", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "BodyStructure/*", + }, + }, + "ImagingStudy|reason_reference_Organization|Organization": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_Organization", + ToType: "Organization", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "Organization/*", + }, + }, + "Organization|reason_reference_Organization|ImagingStudy": { + FromType: "Organization", + EdgeLabel: "reason_reference_Organization", + ToType: "ImagingStudy", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "Organization/*", + }, + }, + "ImagingStudy|reason_reference_Group|Group": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_Group", + ToType: "Group", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "Group/*", + }, + }, + "Group|reason_reference_Group|ImagingStudy": { + FromType: "Group", + EdgeLabel: "reason_reference_Group", + ToType: "ImagingStudy", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "Group/*", + }, + }, + "ImagingStudy|reason_reference_Practitioner|Practitioner": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_Practitioner", + ToType: "Practitioner", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "Practitioner/*", + }, + }, + "Practitioner|reason_reference_Practitioner|ImagingStudy": { + FromType: "Practitioner", + EdgeLabel: "reason_reference_Practitioner", + ToType: "ImagingStudy", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "Practitioner/*", + }, + }, + "ImagingStudy|reason_reference_PractitionerRole|PractitionerRole": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_PractitionerRole", + ToType: "PractitionerRole", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "PractitionerRole/*", + }, + }, + "PractitionerRole|reason_reference_PractitionerRole|ImagingStudy": { + FromType: "PractitionerRole", + EdgeLabel: "reason_reference_PractitionerRole", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21031,9 +21020,9 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "Extension|valueCodeableReference_reference_ResearchStudy|ResearchStudy": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_ResearchStudy", + "ImagingStudy|reason_reference_ResearchStudy|ResearchStudy": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -21048,10 +21037,10 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "ResearchStudy|valueCodeableReference_reference_ResearchStudy|Extension": { + "ResearchStudy|reason_reference_ResearchStudy|ImagingStudy": { FromType: "ResearchStudy", - EdgeLabel: "valueCodeableReference_reference_ResearchStudy", - ToType: "Extension", + EdgeLabel: "reason_reference_ResearchStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21065,9 +21054,9 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "Extension|valueCodeableReference_reference_Patient|Patient": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_Patient", + "ImagingStudy|reason_reference_Patient|Patient": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -21082,10 +21071,10 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "Patient|valueCodeableReference_reference_Patient|Extension": { + "Patient|reason_reference_Patient|ImagingStudy": { FromType: "Patient", - EdgeLabel: "valueCodeableReference_reference_Patient", - ToType: "Extension", + EdgeLabel: "reason_reference_Patient", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21099,9 +21088,9 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "Extension|valueCodeableReference_reference_ResearchSubject|ResearchSubject": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_ResearchSubject", + "ImagingStudy|reason_reference_ResearchSubject|ResearchSubject": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -21116,10 +21105,10 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "ResearchSubject|valueCodeableReference_reference_ResearchSubject|Extension": { + "ResearchSubject|reason_reference_ResearchSubject|ImagingStudy": { FromType: "ResearchSubject", - EdgeLabel: "valueCodeableReference_reference_ResearchSubject", - ToType: "Extension", + EdgeLabel: "reason_reference_ResearchSubject", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21133,9 +21122,9 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "Extension|valueCodeableReference_reference_Substance|Substance": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_Substance", + "ImagingStudy|reason_reference_Substance|Substance": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -21150,10 +21139,10 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "Substance|valueCodeableReference_reference_Substance|Extension": { + "Substance|reason_reference_Substance|ImagingStudy": { FromType: "Substance", - EdgeLabel: "valueCodeableReference_reference_Substance", - ToType: "Extension", + EdgeLabel: "reason_reference_Substance", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21167,9 +21156,9 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "Extension|valueCodeableReference_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_SubstanceDefinition", + "ImagingStudy|reason_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -21184,10 +21173,10 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|valueCodeableReference_reference_SubstanceDefinition|Extension": { + "SubstanceDefinition|reason_reference_SubstanceDefinition|ImagingStudy": { FromType: "SubstanceDefinition", - EdgeLabel: "valueCodeableReference_reference_SubstanceDefinition", - ToType: "Extension", + EdgeLabel: "reason_reference_SubstanceDefinition", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21201,9 +21190,9 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "Extension|valueCodeableReference_reference_Specimen|Specimen": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_Specimen", + "ImagingStudy|reason_reference_Specimen|Specimen": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -21218,10 +21207,10 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "Specimen|valueCodeableReference_reference_Specimen|Extension": { + "Specimen|reason_reference_Specimen|ImagingStudy": { FromType: "Specimen", - EdgeLabel: "valueCodeableReference_reference_Specimen", - ToType: "Extension", + EdgeLabel: "reason_reference_Specimen", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21235,9 +21224,9 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "Extension|valueCodeableReference_reference_Observation|Observation": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_Observation", + "ImagingStudy|reason_reference_Observation|Observation": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -21252,10 +21241,10 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "Observation|valueCodeableReference_reference_Observation|Extension": { + "Observation|reason_reference_Observation|ImagingStudy": { FromType: "Observation", - EdgeLabel: "valueCodeableReference_reference_Observation", - ToType: "Extension", + EdgeLabel: "reason_reference_Observation", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21269,9 +21258,9 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "Extension|valueCodeableReference_reference_DiagnosticReport|DiagnosticReport": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_DiagnosticReport", + "ImagingStudy|reason_reference_DiagnosticReport|DiagnosticReport": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -21286,10 +21275,10 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "DiagnosticReport|valueCodeableReference_reference_DiagnosticReport|Extension": { + "DiagnosticReport|reason_reference_DiagnosticReport|ImagingStudy": { FromType: "DiagnosticReport", - EdgeLabel: "valueCodeableReference_reference_DiagnosticReport", - ToType: "Extension", + EdgeLabel: "reason_reference_DiagnosticReport", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21303,9 +21292,9 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "Extension|valueCodeableReference_reference_Condition|Condition": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_Condition", + "ImagingStudy|reason_reference_Condition|Condition": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -21320,10 +21309,10 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "Condition|valueCodeableReference_reference_Condition|Extension": { + "Condition|reason_reference_Condition|ImagingStudy": { FromType: "Condition", - EdgeLabel: "valueCodeableReference_reference_Condition", - ToType: "Extension", + EdgeLabel: "reason_reference_Condition", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21337,9 +21326,9 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "Extension|valueCodeableReference_reference_Medication|Medication": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_Medication", + "ImagingStudy|reason_reference_Medication|Medication": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -21354,10 +21343,10 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "Medication|valueCodeableReference_reference_Medication|Extension": { + "Medication|reason_reference_Medication|ImagingStudy": { FromType: "Medication", - EdgeLabel: "valueCodeableReference_reference_Medication", - ToType: "Extension", + EdgeLabel: "reason_reference_Medication", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21371,9 +21360,9 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "Extension|valueCodeableReference_reference_MedicationAdministration|MedicationAdministration": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_MedicationAdministration", + "ImagingStudy|reason_reference_MedicationAdministration|MedicationAdministration": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -21388,10 +21377,10 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "MedicationAdministration|valueCodeableReference_reference_MedicationAdministration|Extension": { + "MedicationAdministration|reason_reference_MedicationAdministration|ImagingStudy": { FromType: "MedicationAdministration", - EdgeLabel: "valueCodeableReference_reference_MedicationAdministration", - ToType: "Extension", + EdgeLabel: "reason_reference_MedicationAdministration", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21405,9 +21394,9 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "Extension|valueCodeableReference_reference_MedicationStatement|MedicationStatement": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_MedicationStatement", + "ImagingStudy|reason_reference_MedicationStatement|MedicationStatement": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -21422,10 +21411,10 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "MedicationStatement|valueCodeableReference_reference_MedicationStatement|Extension": { + "MedicationStatement|reason_reference_MedicationStatement|ImagingStudy": { FromType: "MedicationStatement", - EdgeLabel: "valueCodeableReference_reference_MedicationStatement", - ToType: "Extension", + EdgeLabel: "reason_reference_MedicationStatement", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21439,9 +21428,9 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "Extension|valueCodeableReference_reference_MedicationRequest|MedicationRequest": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_MedicationRequest", + "ImagingStudy|reason_reference_MedicationRequest|MedicationRequest": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -21456,10 +21445,10 @@ var Traversals = map[string]Traversal{ "MedicationRequest/*", }, }, - "MedicationRequest|valueCodeableReference_reference_MedicationRequest|Extension": { + "MedicationRequest|reason_reference_MedicationRequest|ImagingStudy": { FromType: "MedicationRequest", - EdgeLabel: "valueCodeableReference_reference_MedicationRequest", - ToType: "Extension", + EdgeLabel: "reason_reference_MedicationRequest", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21473,9 +21462,9 @@ var Traversals = map[string]Traversal{ "MedicationRequest/*", }, }, - "Extension|valueCodeableReference_reference_Procedure|Procedure": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_Procedure", + "ImagingStudy|reason_reference_Procedure|Procedure": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_Procedure", ToType: "Procedure", Direction: []string{ "outbound", @@ -21490,10 +21479,10 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "Procedure|valueCodeableReference_reference_Procedure|Extension": { + "Procedure|reason_reference_Procedure|ImagingStudy": { FromType: "Procedure", - EdgeLabel: "valueCodeableReference_reference_Procedure", - ToType: "Extension", + EdgeLabel: "reason_reference_Procedure", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21507,9 +21496,9 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "Extension|valueCodeableReference_reference_DocumentReference|DocumentReference": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_DocumentReference", + "ImagingStudy|reason_reference_DocumentReference|DocumentReference": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_DocumentReference", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -21524,10 +21513,10 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "DocumentReference|valueCodeableReference_reference_DocumentReference|Extension": { + "DocumentReference|reason_reference_DocumentReference|ImagingStudy": { FromType: "DocumentReference", - EdgeLabel: "valueCodeableReference_reference_DocumentReference", - ToType: "Extension", + EdgeLabel: "reason_reference_DocumentReference", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21541,9 +21530,9 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "Extension|valueCodeableReference_reference_Task|Task": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_Task", + "ImagingStudy|reason_reference_Task|Task": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_Task", ToType: "Task", Direction: []string{ "outbound", @@ -21558,10 +21547,10 @@ var Traversals = map[string]Traversal{ "Task/*", }, }, - "Task|valueCodeableReference_reference_Task|Extension": { + "Task|reason_reference_Task|ImagingStudy": { FromType: "Task", - EdgeLabel: "valueCodeableReference_reference_Task", - ToType: "Extension", + EdgeLabel: "reason_reference_Task", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21575,9 +21564,9 @@ var Traversals = map[string]Traversal{ "Task/*", }, }, - "Extension|valueCodeableReference_reference_ImagingStudy|ImagingStudy": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_ImagingStudy", + "ImagingStudy|reason_reference_ImagingStudy|ImagingStudy": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", @@ -21592,26 +21581,9 @@ var Traversals = map[string]Traversal{ "ImagingStudy/*", }, }, - "ImagingStudy|valueCodeableReference_reference_ImagingStudy|Extension": { + "ImagingStudy|reason_reference_FamilyMemberHistory|FamilyMemberHistory": { FromType: "ImagingStudy", - EdgeLabel: "valueCodeableReference_reference_ImagingStudy", - ToType: "Extension", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "Extension|valueCodeableReference_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_FamilyMemberHistory", + EdgeLabel: "reason_reference_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -21626,10 +21598,10 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|valueCodeableReference_reference_FamilyMemberHistory|Extension": { + "FamilyMemberHistory|reason_reference_FamilyMemberHistory|ImagingStudy": { FromType: "FamilyMemberHistory", - EdgeLabel: "valueCodeableReference_reference_FamilyMemberHistory", - ToType: "Extension", + EdgeLabel: "reason_reference_FamilyMemberHistory", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21643,9 +21615,9 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "Extension|valueCodeableReference_reference_BodyStructure|BodyStructure": { - FromType: "Extension", - EdgeLabel: "valueCodeableReference_reference_BodyStructure", + "ImagingStudy|reason_reference_BodyStructure|BodyStructure": { + FromType: "ImagingStudy", + EdgeLabel: "reason_reference_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", @@ -21660,10 +21632,10 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "BodyStructure|valueCodeableReference_reference_BodyStructure|Extension": { + "BodyStructure|reason_reference_BodyStructure|ImagingStudy": { FromType: "BodyStructure", - EdgeLabel: "valueCodeableReference_reference_BodyStructure", - ToType: "Extension", + EdgeLabel: "reason_reference_BodyStructure", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -21677,43 +21649,43 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "Extension|valueDataRequirement_subjectReference|Group": { - FromType: "Extension", - EdgeLabel: "valueDataRequirement_subjectReference", - ToType: "Group", + "ImagingStudy|series_specimen|Specimen": { + FromType: "ImagingStudy", + EdgeLabel: "series_specimen", + ToType: "Specimen", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "data_requirement", + "specimen_imaging_study_series", }, RegexMatch: []string{ - "Group/*", + "Specimen/*", }, }, - "Group|valueDataRequirement_subjectReference|Extension": { - FromType: "Group", - EdgeLabel: "valueDataRequirement_subjectReference", - ToType: "Extension", + "Specimen|series_specimen|ImagingStudy": { + FromType: "Specimen", + EdgeLabel: "series_specimen", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "data_requirement", + "specimen_imaging_study_series", }, RegexMatch: []string{ - "Group/*", + "Specimen/*", }, }, - "Extension|valueExtendedContactDetail_organization|Organization": { - FromType: "Extension", - EdgeLabel: "valueExtendedContactDetail_organization", + "Medication|marketingAuthorizationHolder|Organization": { + FromType: "Medication", + EdgeLabel: "marketingAuthorizationHolder", ToType: "Organization", Direction: []string{ "outbound", @@ -21722,16 +21694,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extended_contact_detail", + "medication", }, RegexMatch: []string{ "Organization/*", }, }, - "Organization|valueExtendedContactDetail_organization|Extension": { + "Organization|marketingAuthorizationHolder|Medication": { FromType: "Organization", - EdgeLabel: "valueExtendedContactDetail_organization", - ToType: "Extension", + EdgeLabel: "marketingAuthorizationHolder", + ToType: "Medication", Direction: []string{ "outbound", }, @@ -21739,67 +21711,67 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extended_contact_detail", + "medication", }, RegexMatch: []string{ "Organization/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_Organization|Organization": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_Organization", - ToType: "Organization", + "MedicationAdministration|partOf_MedicationAdministration|MedicationAdministration": { + FromType: "MedicationAdministration", + EdgeLabel: "partOf_MedicationAdministration", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "partOf_medication_administration", }, RegexMatch: []string{ - "Organization/*", + "MedicationAdministration/*", }, }, - "Organization|valueRelatedArtifact_resourceReference_Organization|Extension": { - FromType: "Organization", - EdgeLabel: "valueRelatedArtifact_resourceReference_Organization", - ToType: "Extension", + "MedicationAdministration|partOf_Procedure|Procedure": { + FromType: "MedicationAdministration", + EdgeLabel: "partOf_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "partOf_medication_administration", }, RegexMatch: []string{ - "Organization/*", + "Procedure/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_Group|Group": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_Group", - ToType: "Group", + "Procedure|partOf_Procedure|MedicationAdministration": { + FromType: "Procedure", + EdgeLabel: "partOf_Procedure", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "partOf_medication_administration", }, RegexMatch: []string{ - "Group/*", + "Procedure/*", }, }, - "Group|valueRelatedArtifact_resourceReference_Group|Extension": { - FromType: "Group", - EdgeLabel: "valueRelatedArtifact_resourceReference_Group", - ToType: "Extension", + "MedicationAdministration|request|MedicationRequest": { + FromType: "MedicationAdministration", + EdgeLabel: "request", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -21807,16 +21779,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "medication_administration", }, RegexMatch: []string{ - "Group/*", + "MedicationRequest/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_Practitioner|Practitioner": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_Practitioner", - ToType: "Practitioner", + "MedicationRequest|request|MedicationAdministration": { + FromType: "MedicationRequest", + EdgeLabel: "request", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -21824,16 +21796,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "medication_administration", }, RegexMatch: []string{ - "Practitioner/*", + "MedicationRequest/*", }, }, - "Practitioner|valueRelatedArtifact_resourceReference_Practitioner|Extension": { - FromType: "Practitioner", - EdgeLabel: "valueRelatedArtifact_resourceReference_Practitioner", - ToType: "Extension", + "MedicationAdministration|subject_Patient|Patient": { + FromType: "MedicationAdministration", + EdgeLabel: "subject_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -21841,16 +21813,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "medication_administration", }, RegexMatch: []string{ - "Practitioner/*", + "Patient/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_PractitionerRole|PractitionerRole": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_PractitionerRole", - ToType: "PractitionerRole", + "Patient|subject_Patient|MedicationAdministration": { + FromType: "Patient", + EdgeLabel: "subject_Patient", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -21858,16 +21830,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "medication_administration", }, RegexMatch: []string{ - "PractitionerRole/*", + "Patient/*", }, }, - "PractitionerRole|valueRelatedArtifact_resourceReference_PractitionerRole|Extension": { - FromType: "PractitionerRole", - EdgeLabel: "valueRelatedArtifact_resourceReference_PractitionerRole", - ToType: "Extension", + "MedicationAdministration|subject_Group|Group": { + FromType: "MedicationAdministration", + EdgeLabel: "subject_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -21875,16 +21847,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "medication_administration", }, RegexMatch: []string{ - "PractitionerRole/*", + "Group/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_ResearchStudy|ResearchStudy": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_ResearchStudy", - ToType: "ResearchStudy", + "Group|subject_Group|MedicationAdministration": { + FromType: "Group", + EdgeLabel: "subject_Group", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -21892,781 +21864,781 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "medication_administration", }, RegexMatch: []string{ - "ResearchStudy/*", + "Group/*", }, }, - "ResearchStudy|valueRelatedArtifact_resourceReference_ResearchStudy|Extension": { - FromType: "ResearchStudy", - EdgeLabel: "valueRelatedArtifact_resourceReference_ResearchStudy", - ToType: "Extension", + "MedicationAdministration|supportingInformation_Organization|Organization": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "ResearchStudy/*", + "Organization/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_Patient|Patient": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_Patient", - ToType: "Patient", + "Organization|supportingInformation_Organization|MedicationAdministration": { + FromType: "Organization", + EdgeLabel: "supportingInformation_Organization", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Patient/*", + "Organization/*", }, }, - "Patient|valueRelatedArtifact_resourceReference_Patient|Extension": { - FromType: "Patient", - EdgeLabel: "valueRelatedArtifact_resourceReference_Patient", - ToType: "Extension", + "MedicationAdministration|supportingInformation_Group|Group": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_Group", + ToType: "Group", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Patient/*", + "Group/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_ResearchSubject|ResearchSubject": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_ResearchSubject", - ToType: "ResearchSubject", + "Group|supportingInformation_Group|MedicationAdministration": { + FromType: "Group", + EdgeLabel: "supportingInformation_Group", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "ResearchSubject/*", + "Group/*", }, }, - "ResearchSubject|valueRelatedArtifact_resourceReference_ResearchSubject|Extension": { - FromType: "ResearchSubject", - EdgeLabel: "valueRelatedArtifact_resourceReference_ResearchSubject", - ToType: "Extension", + "MedicationAdministration|supportingInformation_Practitioner|Practitioner": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "ResearchSubject/*", + "Practitioner/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_Substance|Substance": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_Substance", - ToType: "Substance", + "Practitioner|supportingInformation_Practitioner|MedicationAdministration": { + FromType: "Practitioner", + EdgeLabel: "supportingInformation_Practitioner", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Substance/*", + "Practitioner/*", }, }, - "Substance|valueRelatedArtifact_resourceReference_Substance|Extension": { - FromType: "Substance", - EdgeLabel: "valueRelatedArtifact_resourceReference_Substance", - ToType: "Extension", + "MedicationAdministration|supportingInformation_PractitionerRole|PractitionerRole": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Substance/*", + "PractitionerRole/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_SubstanceDefinition|SubstanceDefinition": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_SubstanceDefinition", - ToType: "SubstanceDefinition", + "PractitionerRole|supportingInformation_PractitionerRole|MedicationAdministration": { + FromType: "PractitionerRole", + EdgeLabel: "supportingInformation_PractitionerRole", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "PractitionerRole/*", }, }, - "SubstanceDefinition|valueRelatedArtifact_resourceReference_SubstanceDefinition|Extension": { - FromType: "SubstanceDefinition", - EdgeLabel: "valueRelatedArtifact_resourceReference_SubstanceDefinition", - ToType: "Extension", + "MedicationAdministration|supportingInformation_ResearchStudy|ResearchStudy": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_ResearchStudy", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "ResearchStudy/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_Specimen|Specimen": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_Specimen", - ToType: "Specimen", + "ResearchStudy|supportingInformation_ResearchStudy|MedicationAdministration": { + FromType: "ResearchStudy", + EdgeLabel: "supportingInformation_ResearchStudy", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Specimen/*", + "ResearchStudy/*", }, }, - "Specimen|valueRelatedArtifact_resourceReference_Specimen|Extension": { - FromType: "Specimen", - EdgeLabel: "valueRelatedArtifact_resourceReference_Specimen", - ToType: "Extension", + "MedicationAdministration|supportingInformation_Patient|Patient": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Specimen/*", + "Patient/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_Observation|Observation": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_Observation", - ToType: "Observation", + "Patient|supportingInformation_Patient|MedicationAdministration": { + FromType: "Patient", + EdgeLabel: "supportingInformation_Patient", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Observation/*", + "Patient/*", }, }, - "Observation|valueRelatedArtifact_resourceReference_Observation|Extension": { - FromType: "Observation", - EdgeLabel: "valueRelatedArtifact_resourceReference_Observation", - ToType: "Extension", + "MedicationAdministration|supportingInformation_ResearchSubject|ResearchSubject": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_ResearchSubject", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Observation/*", + "ResearchSubject/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_DiagnosticReport|DiagnosticReport": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_DiagnosticReport", - ToType: "DiagnosticReport", + "ResearchSubject|supportingInformation_ResearchSubject|MedicationAdministration": { + FromType: "ResearchSubject", + EdgeLabel: "supportingInformation_ResearchSubject", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "DiagnosticReport/*", + "ResearchSubject/*", }, }, - "DiagnosticReport|valueRelatedArtifact_resourceReference_DiagnosticReport|Extension": { - FromType: "DiagnosticReport", - EdgeLabel: "valueRelatedArtifact_resourceReference_DiagnosticReport", - ToType: "Extension", + "MedicationAdministration|supportingInformation_Substance|Substance": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_Substance", + ToType: "Substance", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Substance/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_Condition|Condition": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_Condition", - ToType: "Condition", + "Substance|supportingInformation_Substance|MedicationAdministration": { + FromType: "Substance", + EdgeLabel: "supportingInformation_Substance", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Condition/*", + "Substance/*", }, }, - "Condition|valueRelatedArtifact_resourceReference_Condition|Extension": { - FromType: "Condition", - EdgeLabel: "valueRelatedArtifact_resourceReference_Condition", - ToType: "Extension", + "MedicationAdministration|supportingInformation_SubstanceDefinition|SubstanceDefinition": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_SubstanceDefinition", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Condition/*", + "SubstanceDefinition/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_Medication|Medication": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_Medication", - ToType: "Medication", + "SubstanceDefinition|supportingInformation_SubstanceDefinition|MedicationAdministration": { + FromType: "SubstanceDefinition", + EdgeLabel: "supportingInformation_SubstanceDefinition", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Medication/*", + "SubstanceDefinition/*", }, }, - "Medication|valueRelatedArtifact_resourceReference_Medication|Extension": { - FromType: "Medication", - EdgeLabel: "valueRelatedArtifact_resourceReference_Medication", - ToType: "Extension", + "MedicationAdministration|supportingInformation_Specimen|Specimen": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_Specimen", + ToType: "Specimen", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Medication/*", + "Specimen/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_MedicationAdministration|MedicationAdministration": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_MedicationAdministration", + "Specimen|supportingInformation_Specimen|MedicationAdministration": { + FromType: "Specimen", + EdgeLabel: "supportingInformation_Specimen", ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Specimen/*", }, }, - "MedicationAdministration|valueRelatedArtifact_resourceReference_MedicationAdministration|Extension": { + "MedicationAdministration|supportingInformation_Observation|Observation": { FromType: "MedicationAdministration", - EdgeLabel: "valueRelatedArtifact_resourceReference_MedicationAdministration", - ToType: "Extension", + EdgeLabel: "supportingInformation_Observation", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Observation/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_MedicationStatement|MedicationStatement": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_MedicationStatement", - ToType: "MedicationStatement", + "Observation|supportingInformation_Observation|MedicationAdministration": { + FromType: "Observation", + EdgeLabel: "supportingInformation_Observation", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "MedicationStatement/*", + "Observation/*", }, }, - "MedicationStatement|valueRelatedArtifact_resourceReference_MedicationStatement|Extension": { - FromType: "MedicationStatement", - EdgeLabel: "valueRelatedArtifact_resourceReference_MedicationStatement", - ToType: "Extension", + "MedicationAdministration|supportingInformation_DiagnosticReport|DiagnosticReport": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_DiagnosticReport", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "MedicationStatement/*", + "DiagnosticReport/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_MedicationRequest|MedicationRequest": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_MedicationRequest", - ToType: "MedicationRequest", + "DiagnosticReport|supportingInformation_DiagnosticReport|MedicationAdministration": { + FromType: "DiagnosticReport", + EdgeLabel: "supportingInformation_DiagnosticReport", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "MedicationRequest/*", + "DiagnosticReport/*", }, }, - "MedicationRequest|valueRelatedArtifact_resourceReference_MedicationRequest|Extension": { - FromType: "MedicationRequest", - EdgeLabel: "valueRelatedArtifact_resourceReference_MedicationRequest", - ToType: "Extension", + "MedicationAdministration|supportingInformation_Condition|Condition": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_Condition", + ToType: "Condition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "MedicationRequest/*", + "Condition/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_Procedure|Procedure": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_Procedure", - ToType: "Procedure", + "Condition|supportingInformation_Condition|MedicationAdministration": { + FromType: "Condition", + EdgeLabel: "supportingInformation_Condition", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Procedure/*", + "Condition/*", }, }, - "Procedure|valueRelatedArtifact_resourceReference_Procedure|Extension": { - FromType: "Procedure", - EdgeLabel: "valueRelatedArtifact_resourceReference_Procedure", - ToType: "Extension", + "MedicationAdministration|supportingInformation_Medication|Medication": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_Medication", + ToType: "Medication", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Procedure/*", + "Medication/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_DocumentReference|DocumentReference": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_DocumentReference", - ToType: "DocumentReference", + "Medication|supportingInformation_Medication|MedicationAdministration": { + FromType: "Medication", + EdgeLabel: "supportingInformation_Medication", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "DocumentReference/*", + "Medication/*", }, }, - "DocumentReference|valueRelatedArtifact_resourceReference_DocumentReference|Extension": { - FromType: "DocumentReference", - EdgeLabel: "valueRelatedArtifact_resourceReference_DocumentReference", - ToType: "Extension", + "MedicationAdministration|supportingInformation_MedicationAdministration|MedicationAdministration": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_MedicationAdministration", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "DocumentReference/*", + "MedicationAdministration/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_Task|Task": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_Task", - ToType: "Task", + "MedicationAdministration|supportingInformation_MedicationStatement|MedicationStatement": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_MedicationStatement", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Task/*", + "MedicationStatement/*", }, }, - "Task|valueRelatedArtifact_resourceReference_Task|Extension": { - FromType: "Task", - EdgeLabel: "valueRelatedArtifact_resourceReference_Task", - ToType: "Extension", + "MedicationStatement|supportingInformation_MedicationStatement|MedicationAdministration": { + FromType: "MedicationStatement", + EdgeLabel: "supportingInformation_MedicationStatement", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Task/*", + "MedicationStatement/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_ImagingStudy|ImagingStudy": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_ImagingStudy", - ToType: "ImagingStudy", + "MedicationAdministration|supportingInformation_MedicationRequest|MedicationRequest": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_MedicationRequest", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "ImagingStudy/*", + "MedicationRequest/*", }, }, - "ImagingStudy|valueRelatedArtifact_resourceReference_ImagingStudy|Extension": { - FromType: "ImagingStudy", - EdgeLabel: "valueRelatedArtifact_resourceReference_ImagingStudy", - ToType: "Extension", + "MedicationRequest|supportingInformation_MedicationRequest|MedicationAdministration": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_MedicationRequest", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "ImagingStudy/*", + "MedicationRequest/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", + "MedicationAdministration|supportingInformation_Procedure|Procedure": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Procedure/*", }, }, - "FamilyMemberHistory|valueRelatedArtifact_resourceReference_FamilyMemberHistory|Extension": { - FromType: "FamilyMemberHistory", - EdgeLabel: "valueRelatedArtifact_resourceReference_FamilyMemberHistory", - ToType: "Extension", + "Procedure|supportingInformation_Procedure|MedicationAdministration": { + FromType: "Procedure", + EdgeLabel: "supportingInformation_Procedure", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Procedure/*", }, }, - "Extension|valueRelatedArtifact_resourceReference_BodyStructure|BodyStructure": { - FromType: "Extension", - EdgeLabel: "valueRelatedArtifact_resourceReference_BodyStructure", - ToType: "BodyStructure", + "MedicationAdministration|supportingInformation_DocumentReference|DocumentReference": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "BodyStructure/*", + "DocumentReference/*", }, }, - "BodyStructure|valueRelatedArtifact_resourceReference_BodyStructure|Extension": { - FromType: "BodyStructure", - EdgeLabel: "valueRelatedArtifact_resourceReference_BodyStructure", - ToType: "Extension", + "DocumentReference|supportingInformation_DocumentReference|MedicationAdministration": { + FromType: "DocumentReference", + EdgeLabel: "supportingInformation_DocumentReference", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "BodyStructure/*", + "DocumentReference/*", }, }, - "Extension|valueSignature_onBehalfOf_Practitioner|Practitioner": { - FromType: "Extension", - EdgeLabel: "valueSignature_onBehalfOf_Practitioner", - ToType: "Practitioner", + "MedicationAdministration|supportingInformation_Task|Task": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_Task", + ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "onBehalfOf_signature", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Practitioner/*", + "Task/*", }, }, - "Practitioner|valueSignature_onBehalfOf_Practitioner|Extension": { - FromType: "Practitioner", - EdgeLabel: "valueSignature_onBehalfOf_Practitioner", - ToType: "Extension", + "Task|supportingInformation_Task|MedicationAdministration": { + FromType: "Task", + EdgeLabel: "supportingInformation_Task", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "onBehalfOf_signature", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Practitioner/*", + "Task/*", }, }, - "Extension|valueSignature_onBehalfOf_PractitionerRole|PractitionerRole": { - FromType: "Extension", - EdgeLabel: "valueSignature_onBehalfOf_PractitionerRole", - ToType: "PractitionerRole", + "MedicationAdministration|supportingInformation_ImagingStudy|ImagingStudy": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_ImagingStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "onBehalfOf_signature", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "PractitionerRole/*", + "ImagingStudy/*", }, }, - "PractitionerRole|valueSignature_onBehalfOf_PractitionerRole|Extension": { - FromType: "PractitionerRole", - EdgeLabel: "valueSignature_onBehalfOf_PractitionerRole", - ToType: "Extension", + "ImagingStudy|supportingInformation_ImagingStudy|MedicationAdministration": { + FromType: "ImagingStudy", + EdgeLabel: "supportingInformation_ImagingStudy", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "onBehalfOf_signature", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "PractitionerRole/*", + "ImagingStudy/*", }, }, - "Extension|valueSignature_onBehalfOf_Patient|Patient": { - FromType: "Extension", - EdgeLabel: "valueSignature_onBehalfOf_Patient", - ToType: "Patient", + "MedicationAdministration|supportingInformation_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_FamilyMemberHistory", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "onBehalfOf_signature", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Patient/*", + "FamilyMemberHistory/*", }, }, - "Patient|valueSignature_onBehalfOf_Patient|Extension": { - FromType: "Patient", - EdgeLabel: "valueSignature_onBehalfOf_Patient", - ToType: "Extension", + "FamilyMemberHistory|supportingInformation_FamilyMemberHistory|MedicationAdministration": { + FromType: "FamilyMemberHistory", + EdgeLabel: "supportingInformation_FamilyMemberHistory", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "onBehalfOf_signature", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Patient/*", + "FamilyMemberHistory/*", }, }, - "Extension|valueSignature_onBehalfOf_Organization|Organization": { - FromType: "Extension", - EdgeLabel: "valueSignature_onBehalfOf_Organization", - ToType: "Organization", + "MedicationAdministration|supportingInformation_BodyStructure|BodyStructure": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_BodyStructure", + ToType: "BodyStructure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "onBehalfOf_signature", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Organization/*", + "BodyStructure/*", }, }, - "Organization|valueSignature_onBehalfOf_Organization|Extension": { - FromType: "Organization", - EdgeLabel: "valueSignature_onBehalfOf_Organization", - ToType: "Extension", + "BodyStructure|supportingInformation_BodyStructure|MedicationAdministration": { + FromType: "BodyStructure", + EdgeLabel: "supportingInformation_BodyStructure", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "onBehalfOf_signature", + "supportingInformation_medication_administration", }, RegexMatch: []string{ - "Organization/*", + "BodyStructure/*", }, }, - "Extension|valueSignature_who_Practitioner|Practitioner": { - FromType: "Extension", - EdgeLabel: "valueSignature_who_Practitioner", - ToType: "Practitioner", + "MedicationAdministration|device_reference_Organization|Organization": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -22674,16 +22646,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Organization/*", }, }, - "Practitioner|valueSignature_who_Practitioner|Extension": { - FromType: "Practitioner", - EdgeLabel: "valueSignature_who_Practitioner", - ToType: "Extension", + "Organization|device_reference_Organization|MedicationAdministration": { + FromType: "Organization", + EdgeLabel: "device_reference_Organization", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -22691,16 +22663,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Organization/*", }, }, - "Extension|valueSignature_who_PractitionerRole|PractitionerRole": { - FromType: "Extension", - EdgeLabel: "valueSignature_who_PractitionerRole", - ToType: "PractitionerRole", + "MedicationAdministration|device_reference_Group|Group": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -22708,16 +22680,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Group/*", }, }, - "PractitionerRole|valueSignature_who_PractitionerRole|Extension": { - FromType: "PractitionerRole", - EdgeLabel: "valueSignature_who_PractitionerRole", - ToType: "Extension", + "Group|device_reference_Group|MedicationAdministration": { + FromType: "Group", + EdgeLabel: "device_reference_Group", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -22725,16 +22697,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Group/*", }, }, - "Extension|valueSignature_who_Patient|Patient": { - FromType: "Extension", - EdgeLabel: "valueSignature_who_Patient", - ToType: "Patient", + "MedicationAdministration|device_reference_Practitioner|Practitioner": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -22742,16 +22714,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "Practitioner/*", }, }, - "Patient|valueSignature_who_Patient|Extension": { - FromType: "Patient", - EdgeLabel: "valueSignature_who_Patient", - ToType: "Extension", + "Practitioner|device_reference_Practitioner|MedicationAdministration": { + FromType: "Practitioner", + EdgeLabel: "device_reference_Practitioner", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -22759,16 +22731,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "Practitioner/*", }, }, - "Extension|valueSignature_who_Organization|Organization": { - FromType: "Extension", - EdgeLabel: "valueSignature_who_Organization", - ToType: "Organization", + "MedicationAdministration|device_reference_PractitionerRole|PractitionerRole": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -22776,16 +22748,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "PractitionerRole/*", }, }, - "Organization|valueSignature_who_Organization|Extension": { - FromType: "Organization", - EdgeLabel: "valueSignature_who_Organization", - ToType: "Extension", + "PractitionerRole|device_reference_PractitionerRole|MedicationAdministration": { + FromType: "PractitionerRole", + EdgeLabel: "device_reference_PractitionerRole", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -22793,15 +22765,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "PractitionerRole/*", }, }, - "Extension|valueUsageContext_valueReference_ResearchStudy|ResearchStudy": { - FromType: "Extension", - EdgeLabel: "valueUsageContext_valueReference_ResearchStudy", + "MedicationAdministration|device_reference_ResearchStudy|ResearchStudy": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -22810,16 +22782,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "codeable_reference", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "ResearchStudy|valueUsageContext_valueReference_ResearchStudy|Extension": { + "ResearchStudy|device_reference_ResearchStudy|MedicationAdministration": { FromType: "ResearchStudy", - EdgeLabel: "valueUsageContext_valueReference_ResearchStudy", - ToType: "Extension", + EdgeLabel: "device_reference_ResearchStudy", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -22827,16 +22799,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "codeable_reference", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "Extension|valueUsageContext_valueReference_Group|Group": { - FromType: "Extension", - EdgeLabel: "valueUsageContext_valueReference_Group", - ToType: "Group", + "MedicationAdministration|device_reference_Patient|Patient": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -22844,16 +22816,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "Patient/*", }, }, - "Group|valueUsageContext_valueReference_Group|Extension": { - FromType: "Group", - EdgeLabel: "valueUsageContext_valueReference_Group", - ToType: "Extension", + "Patient|device_reference_Patient|MedicationAdministration": { + FromType: "Patient", + EdgeLabel: "device_reference_Patient", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -22861,16 +22833,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "Patient/*", }, }, - "Extension|valueUsageContext_valueReference_Organization|Organization": { - FromType: "Extension", - EdgeLabel: "valueUsageContext_valueReference_Organization", - ToType: "Organization", + "MedicationAdministration|device_reference_ResearchSubject|ResearchSubject": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_ResearchSubject", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, @@ -22878,16 +22850,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "ResearchSubject/*", }, }, - "Organization|valueUsageContext_valueReference_Organization|Extension": { - FromType: "Organization", - EdgeLabel: "valueUsageContext_valueReference_Organization", - ToType: "Extension", + "ResearchSubject|device_reference_ResearchSubject|MedicationAdministration": { + FromType: "ResearchSubject", + EdgeLabel: "device_reference_ResearchSubject", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -22895,16 +22867,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "ResearchSubject/*", }, }, - "FamilyMemberHistory|patient|Patient": { - FromType: "FamilyMemberHistory", - EdgeLabel: "patient", - ToType: "Patient", + "MedicationAdministration|device_reference_Substance|Substance": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_Substance", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -22912,16 +22884,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "family_member_history", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "Substance/*", }, }, - "Patient|patient|FamilyMemberHistory": { - FromType: "Patient", - EdgeLabel: "patient", - ToType: "FamilyMemberHistory", + "Substance|device_reference_Substance|MedicationAdministration": { + FromType: "Substance", + EdgeLabel: "device_reference_Substance", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -22929,16 +22901,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "family_member_history", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "Substance/*", }, }, - "FamilyMemberHistory|note_authorReference_Practitioner|Practitioner": { - FromType: "FamilyMemberHistory", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "Practitioner", + "MedicationAdministration|device_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_SubstanceDefinition", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, @@ -22946,16 +22918,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "SubstanceDefinition/*", }, }, - "Practitioner|note_authorReference_Practitioner|FamilyMemberHistory": { - FromType: "Practitioner", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "FamilyMemberHistory", + "SubstanceDefinition|device_reference_SubstanceDefinition|MedicationAdministration": { + FromType: "SubstanceDefinition", + EdgeLabel: "device_reference_SubstanceDefinition", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -22963,16 +22935,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "SubstanceDefinition/*", }, }, - "FamilyMemberHistory|note_authorReference_PractitionerRole|PractitionerRole": { - FromType: "FamilyMemberHistory", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "PractitionerRole", + "MedicationAdministration|device_reference_Specimen|Specimen": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_Specimen", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -22980,16 +22952,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Specimen/*", }, }, - "PractitionerRole|note_authorReference_PractitionerRole|FamilyMemberHistory": { - FromType: "PractitionerRole", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "FamilyMemberHistory", + "Specimen|device_reference_Specimen|MedicationAdministration": { + FromType: "Specimen", + EdgeLabel: "device_reference_Specimen", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -22997,16 +22969,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Specimen/*", }, }, - "FamilyMemberHistory|note_authorReference_Patient|Patient": { - FromType: "FamilyMemberHistory", - EdgeLabel: "note_authorReference_Patient", - ToType: "Patient", + "MedicationAdministration|device_reference_Observation|Observation": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_Observation", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -23014,16 +22986,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "Observation/*", }, }, - "Patient|note_authorReference_Patient|FamilyMemberHistory": { - FromType: "Patient", - EdgeLabel: "note_authorReference_Patient", - ToType: "FamilyMemberHistory", + "Observation|device_reference_Observation|MedicationAdministration": { + FromType: "Observation", + EdgeLabel: "device_reference_Observation", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23031,16 +23003,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "Observation/*", }, }, - "FamilyMemberHistory|note_authorReference_Organization|Organization": { - FromType: "FamilyMemberHistory", - EdgeLabel: "note_authorReference_Organization", - ToType: "Organization", + "MedicationAdministration|device_reference_DiagnosticReport|DiagnosticReport": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_DiagnosticReport", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -23048,16 +23020,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "DiagnosticReport/*", }, }, - "Organization|note_authorReference_Organization|FamilyMemberHistory": { - FromType: "Organization", - EdgeLabel: "note_authorReference_Organization", - ToType: "FamilyMemberHistory", + "DiagnosticReport|device_reference_DiagnosticReport|MedicationAdministration": { + FromType: "DiagnosticReport", + EdgeLabel: "device_reference_DiagnosticReport", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23065,16 +23037,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "DiagnosticReport/*", }, }, - "FamilyMemberHistory|participant_actor_Practitioner|Practitioner": { - FromType: "FamilyMemberHistory", - EdgeLabel: "participant_actor_Practitioner", - ToType: "Practitioner", + "MedicationAdministration|device_reference_Condition|Condition": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_Condition", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -23082,16 +23054,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "family_member_history_participant", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Condition/*", }, }, - "Practitioner|participant_actor_Practitioner|FamilyMemberHistory": { - FromType: "Practitioner", - EdgeLabel: "participant_actor_Practitioner", - ToType: "FamilyMemberHistory", + "Condition|device_reference_Condition|MedicationAdministration": { + FromType: "Condition", + EdgeLabel: "device_reference_Condition", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23099,16 +23071,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "family_member_history_participant", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Condition/*", }, }, - "FamilyMemberHistory|participant_actor_PractitionerRole|PractitionerRole": { - FromType: "FamilyMemberHistory", - EdgeLabel: "participant_actor_PractitionerRole", - ToType: "PractitionerRole", + "MedicationAdministration|device_reference_Medication|Medication": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_Medication", + ToType: "Medication", Direction: []string{ "outbound", }, @@ -23116,16 +23088,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "family_member_history_participant", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Medication/*", }, }, - "PractitionerRole|participant_actor_PractitionerRole|FamilyMemberHistory": { - FromType: "PractitionerRole", - EdgeLabel: "participant_actor_PractitionerRole", - ToType: "FamilyMemberHistory", + "Medication|device_reference_Medication|MedicationAdministration": { + FromType: "Medication", + EdgeLabel: "device_reference_Medication", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23133,16 +23105,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "family_member_history_participant", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Medication/*", }, }, - "FamilyMemberHistory|participant_actor_Patient|Patient": { - FromType: "FamilyMemberHistory", - EdgeLabel: "participant_actor_Patient", - ToType: "Patient", + "MedicationAdministration|device_reference_MedicationAdministration|MedicationAdministration": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_MedicationAdministration", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23150,16 +23122,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "family_member_history_participant", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "MedicationAdministration/*", }, }, - "Patient|participant_actor_Patient|FamilyMemberHistory": { - FromType: "Patient", - EdgeLabel: "participant_actor_Patient", - ToType: "FamilyMemberHistory", + "MedicationAdministration|device_reference_MedicationStatement|MedicationStatement": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_MedicationStatement", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -23167,16 +23139,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "family_member_history_participant", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "MedicationStatement/*", }, }, - "FamilyMemberHistory|participant_actor_Organization|Organization": { - FromType: "FamilyMemberHistory", - EdgeLabel: "participant_actor_Organization", - ToType: "Organization", + "MedicationStatement|device_reference_MedicationStatement|MedicationAdministration": { + FromType: "MedicationStatement", + EdgeLabel: "device_reference_MedicationStatement", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23184,16 +23156,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "family_member_history_participant", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "MedicationStatement/*", }, }, - "Organization|participant_actor_Organization|FamilyMemberHistory": { - FromType: "Organization", - EdgeLabel: "participant_actor_Organization", - ToType: "FamilyMemberHistory", + "MedicationAdministration|device_reference_MedicationRequest|MedicationRequest": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_MedicationRequest", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -23201,16 +23173,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "family_member_history_participant", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "MedicationRequest/*", }, }, - "FamilyMemberHistory|reason_reference_Organization|Organization": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_Organization", - ToType: "Organization", + "MedicationRequest|device_reference_MedicationRequest|MedicationAdministration": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_MedicationRequest", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23221,13 +23193,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "MedicationRequest/*", }, }, - "Organization|reason_reference_Organization|FamilyMemberHistory": { - FromType: "Organization", - EdgeLabel: "reason_reference_Organization", - ToType: "FamilyMemberHistory", + "MedicationAdministration|device_reference_Procedure|Procedure": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -23238,13 +23210,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Procedure/*", }, }, - "FamilyMemberHistory|reason_reference_Group|Group": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_Group", - ToType: "Group", + "Procedure|device_reference_Procedure|MedicationAdministration": { + FromType: "Procedure", + EdgeLabel: "device_reference_Procedure", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23255,13 +23227,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "Procedure/*", }, }, - "Group|reason_reference_Group|FamilyMemberHistory": { - FromType: "Group", - EdgeLabel: "reason_reference_Group", - ToType: "FamilyMemberHistory", + "MedicationAdministration|device_reference_DocumentReference|DocumentReference": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -23272,13 +23244,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "DocumentReference/*", }, }, - "FamilyMemberHistory|reason_reference_Practitioner|Practitioner": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_Practitioner", - ToType: "Practitioner", + "DocumentReference|device_reference_DocumentReference|MedicationAdministration": { + FromType: "DocumentReference", + EdgeLabel: "device_reference_DocumentReference", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23289,13 +23261,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "DocumentReference/*", }, }, - "Practitioner|reason_reference_Practitioner|FamilyMemberHistory": { - FromType: "Practitioner", - EdgeLabel: "reason_reference_Practitioner", - ToType: "FamilyMemberHistory", + "MedicationAdministration|device_reference_Task|Task": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_Task", + ToType: "Task", Direction: []string{ "outbound", }, @@ -23306,13 +23278,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Task/*", }, }, - "FamilyMemberHistory|reason_reference_PractitionerRole|PractitionerRole": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_PractitionerRole", - ToType: "PractitionerRole", + "Task|device_reference_Task|MedicationAdministration": { + FromType: "Task", + EdgeLabel: "device_reference_Task", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23323,13 +23295,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Task/*", }, }, - "PractitionerRole|reason_reference_PractitionerRole|FamilyMemberHistory": { - FromType: "PractitionerRole", - EdgeLabel: "reason_reference_PractitionerRole", - ToType: "FamilyMemberHistory", + "MedicationAdministration|device_reference_ImagingStudy|ImagingStudy": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_ImagingStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -23340,13 +23312,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "ImagingStudy/*", }, }, - "FamilyMemberHistory|reason_reference_ResearchStudy|ResearchStudy": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_ResearchStudy", - ToType: "ResearchStudy", + "ImagingStudy|device_reference_ImagingStudy|MedicationAdministration": { + FromType: "ImagingStudy", + EdgeLabel: "device_reference_ImagingStudy", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23357,12 +23329,12 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "ResearchStudy/*", + "ImagingStudy/*", }, }, - "ResearchStudy|reason_reference_ResearchStudy|FamilyMemberHistory": { - FromType: "ResearchStudy", - EdgeLabel: "reason_reference_ResearchStudy", + "MedicationAdministration|device_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -23374,13 +23346,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "ResearchStudy/*", + "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|reason_reference_Patient|Patient": { + "FamilyMemberHistory|device_reference_FamilyMemberHistory|MedicationAdministration": { FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_Patient", - ToType: "Patient", + EdgeLabel: "device_reference_FamilyMemberHistory", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23391,13 +23363,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "FamilyMemberHistory/*", }, }, - "Patient|reason_reference_Patient|FamilyMemberHistory": { - FromType: "Patient", - EdgeLabel: "reason_reference_Patient", - ToType: "FamilyMemberHistory", + "MedicationAdministration|device_reference_BodyStructure|BodyStructure": { + FromType: "MedicationAdministration", + EdgeLabel: "device_reference_BodyStructure", + ToType: "BodyStructure", Direction: []string{ "outbound", }, @@ -23408,13 +23380,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "BodyStructure/*", }, }, - "FamilyMemberHistory|reason_reference_ResearchSubject|ResearchSubject": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_ResearchSubject", - ToType: "ResearchSubject", + "BodyStructure|device_reference_BodyStructure|MedicationAdministration": { + FromType: "BodyStructure", + EdgeLabel: "device_reference_BodyStructure", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23425,13 +23397,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "ResearchSubject/*", + "BodyStructure/*", }, }, - "ResearchSubject|reason_reference_ResearchSubject|FamilyMemberHistory": { - FromType: "ResearchSubject", - EdgeLabel: "reason_reference_ResearchSubject", - ToType: "FamilyMemberHistory", + "MedicationAdministration|medication_reference_Organization|Organization": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -23442,13 +23414,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "ResearchSubject/*", + "Organization/*", }, }, - "FamilyMemberHistory|reason_reference_Substance|Substance": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_Substance", - ToType: "Substance", + "Organization|medication_reference_Organization|MedicationAdministration": { + FromType: "Organization", + EdgeLabel: "medication_reference_Organization", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23459,13 +23431,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Substance/*", + "Organization/*", }, }, - "Substance|reason_reference_Substance|FamilyMemberHistory": { - FromType: "Substance", - EdgeLabel: "reason_reference_Substance", - ToType: "FamilyMemberHistory", + "MedicationAdministration|medication_reference_Group|Group": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -23476,13 +23448,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Substance/*", + "Group/*", }, }, - "FamilyMemberHistory|reason_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_SubstanceDefinition", - ToType: "SubstanceDefinition", + "Group|medication_reference_Group|MedicationAdministration": { + FromType: "Group", + EdgeLabel: "medication_reference_Group", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23493,13 +23465,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "Group/*", }, }, - "SubstanceDefinition|reason_reference_SubstanceDefinition|FamilyMemberHistory": { - FromType: "SubstanceDefinition", - EdgeLabel: "reason_reference_SubstanceDefinition", - ToType: "FamilyMemberHistory", + "MedicationAdministration|medication_reference_Practitioner|Practitioner": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -23510,13 +23482,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "Practitioner/*", }, }, - "FamilyMemberHistory|reason_reference_Specimen|Specimen": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_Specimen", - ToType: "Specimen", + "Practitioner|medication_reference_Practitioner|MedicationAdministration": { + FromType: "Practitioner", + EdgeLabel: "medication_reference_Practitioner", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23527,13 +23499,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Specimen/*", + "Practitioner/*", }, }, - "Specimen|reason_reference_Specimen|FamilyMemberHistory": { - FromType: "Specimen", - EdgeLabel: "reason_reference_Specimen", - ToType: "FamilyMemberHistory", + "MedicationAdministration|medication_reference_PractitionerRole|PractitionerRole": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -23544,13 +23516,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Specimen/*", + "PractitionerRole/*", }, }, - "FamilyMemberHistory|reason_reference_Observation|Observation": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_Observation", - ToType: "Observation", + "PractitionerRole|medication_reference_PractitionerRole|MedicationAdministration": { + FromType: "PractitionerRole", + EdgeLabel: "medication_reference_PractitionerRole", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23561,13 +23533,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Observation/*", + "PractitionerRole/*", }, }, - "Observation|reason_reference_Observation|FamilyMemberHistory": { - FromType: "Observation", - EdgeLabel: "reason_reference_Observation", - ToType: "FamilyMemberHistory", + "MedicationAdministration|medication_reference_ResearchStudy|ResearchStudy": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_ResearchStudy", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -23578,13 +23550,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Observation/*", + "ResearchStudy/*", }, }, - "FamilyMemberHistory|reason_reference_DiagnosticReport|DiagnosticReport": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_DiagnosticReport", - ToType: "DiagnosticReport", + "ResearchStudy|medication_reference_ResearchStudy|MedicationAdministration": { + FromType: "ResearchStudy", + EdgeLabel: "medication_reference_ResearchStudy", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23595,13 +23567,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "DiagnosticReport/*", + "ResearchStudy/*", }, }, - "DiagnosticReport|reason_reference_DiagnosticReport|FamilyMemberHistory": { - FromType: "DiagnosticReport", - EdgeLabel: "reason_reference_DiagnosticReport", - ToType: "FamilyMemberHistory", + "MedicationAdministration|medication_reference_Patient|Patient": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -23612,13 +23584,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Patient/*", }, }, - "FamilyMemberHistory|reason_reference_Condition|Condition": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_Condition", - ToType: "Condition", + "Patient|medication_reference_Patient|MedicationAdministration": { + FromType: "Patient", + EdgeLabel: "medication_reference_Patient", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23629,13 +23601,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Condition/*", + "Patient/*", }, }, - "Condition|reason_reference_Condition|FamilyMemberHistory": { - FromType: "Condition", - EdgeLabel: "reason_reference_Condition", - ToType: "FamilyMemberHistory", + "MedicationAdministration|medication_reference_ResearchSubject|ResearchSubject": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_ResearchSubject", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, @@ -23646,13 +23618,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Condition/*", + "ResearchSubject/*", }, }, - "FamilyMemberHistory|reason_reference_Medication|Medication": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_Medication", - ToType: "Medication", + "ResearchSubject|medication_reference_ResearchSubject|MedicationAdministration": { + FromType: "ResearchSubject", + EdgeLabel: "medication_reference_ResearchSubject", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23663,13 +23635,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Medication/*", + "ResearchSubject/*", }, }, - "Medication|reason_reference_Medication|FamilyMemberHistory": { - FromType: "Medication", - EdgeLabel: "reason_reference_Medication", - ToType: "FamilyMemberHistory", + "MedicationAdministration|medication_reference_Substance|Substance": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_Substance", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -23680,12 +23652,12 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Medication/*", + "Substance/*", }, }, - "FamilyMemberHistory|reason_reference_MedicationAdministration|MedicationAdministration": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_MedicationAdministration", + "Substance|medication_reference_Substance|MedicationAdministration": { + FromType: "Substance", + EdgeLabel: "medication_reference_Substance", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -23697,13 +23669,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Substance/*", }, }, - "MedicationAdministration|reason_reference_MedicationAdministration|FamilyMemberHistory": { + "MedicationAdministration|medication_reference_SubstanceDefinition|SubstanceDefinition": { FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_MedicationAdministration", - ToType: "FamilyMemberHistory", + EdgeLabel: "medication_reference_SubstanceDefinition", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, @@ -23714,13 +23686,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "MedicationAdministration/*", + "SubstanceDefinition/*", }, }, - "FamilyMemberHistory|reason_reference_MedicationStatement|MedicationStatement": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_MedicationStatement", - ToType: "MedicationStatement", + "SubstanceDefinition|medication_reference_SubstanceDefinition|MedicationAdministration": { + FromType: "SubstanceDefinition", + EdgeLabel: "medication_reference_SubstanceDefinition", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23731,13 +23703,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "MedicationStatement/*", + "SubstanceDefinition/*", }, }, - "MedicationStatement|reason_reference_MedicationStatement|FamilyMemberHistory": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_MedicationStatement", - ToType: "FamilyMemberHistory", + "MedicationAdministration|medication_reference_Specimen|Specimen": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_Specimen", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -23748,13 +23720,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "MedicationStatement/*", + "Specimen/*", }, }, - "FamilyMemberHistory|reason_reference_MedicationRequest|MedicationRequest": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_MedicationRequest", - ToType: "MedicationRequest", + "Specimen|medication_reference_Specimen|MedicationAdministration": { + FromType: "Specimen", + EdgeLabel: "medication_reference_Specimen", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23765,13 +23737,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "MedicationRequest/*", + "Specimen/*", }, }, - "MedicationRequest|reason_reference_MedicationRequest|FamilyMemberHistory": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_MedicationRequest", - ToType: "FamilyMemberHistory", + "MedicationAdministration|medication_reference_Observation|Observation": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_Observation", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -23782,13 +23754,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "MedicationRequest/*", + "Observation/*", }, }, - "FamilyMemberHistory|reason_reference_Procedure|Procedure": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_Procedure", - ToType: "Procedure", + "Observation|medication_reference_Observation|MedicationAdministration": { + FromType: "Observation", + EdgeLabel: "medication_reference_Observation", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23799,13 +23771,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Procedure/*", + "Observation/*", }, }, - "Procedure|reason_reference_Procedure|FamilyMemberHistory": { - FromType: "Procedure", - EdgeLabel: "reason_reference_Procedure", - ToType: "FamilyMemberHistory", + "MedicationAdministration|medication_reference_DiagnosticReport|DiagnosticReport": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_DiagnosticReport", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -23816,13 +23788,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Procedure/*", + "DiagnosticReport/*", }, }, - "FamilyMemberHistory|reason_reference_DocumentReference|DocumentReference": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_DocumentReference", - ToType: "DocumentReference", + "DiagnosticReport|medication_reference_DiagnosticReport|MedicationAdministration": { + FromType: "DiagnosticReport", + EdgeLabel: "medication_reference_DiagnosticReport", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23833,13 +23805,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "DocumentReference/*", + "DiagnosticReport/*", }, }, - "DocumentReference|reason_reference_DocumentReference|FamilyMemberHistory": { - FromType: "DocumentReference", - EdgeLabel: "reason_reference_DocumentReference", - ToType: "FamilyMemberHistory", + "MedicationAdministration|medication_reference_Condition|Condition": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_Condition", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -23850,13 +23822,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "DocumentReference/*", + "Condition/*", }, }, - "FamilyMemberHistory|reason_reference_Task|Task": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_Task", - ToType: "Task", + "Condition|medication_reference_Condition|MedicationAdministration": { + FromType: "Condition", + EdgeLabel: "medication_reference_Condition", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23867,13 +23839,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Task/*", + "Condition/*", }, }, - "Task|reason_reference_Task|FamilyMemberHistory": { - FromType: "Task", - EdgeLabel: "reason_reference_Task", - ToType: "FamilyMemberHistory", + "MedicationAdministration|medication_reference_Medication|Medication": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_Medication", + ToType: "Medication", Direction: []string{ "outbound", }, @@ -23884,13 +23856,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Task/*", + "Medication/*", }, }, - "FamilyMemberHistory|reason_reference_ImagingStudy|ImagingStudy": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_ImagingStudy", - ToType: "ImagingStudy", + "Medication|medication_reference_Medication|MedicationAdministration": { + FromType: "Medication", + EdgeLabel: "medication_reference_Medication", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23901,13 +23873,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "ImagingStudy/*", + "Medication/*", }, }, - "ImagingStudy|reason_reference_ImagingStudy|FamilyMemberHistory": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_ImagingStudy", - ToType: "FamilyMemberHistory", + "MedicationAdministration|medication_reference_MedicationAdministration|MedicationAdministration": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_MedicationAdministration", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23918,13 +23890,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "ImagingStudy/*", + "MedicationAdministration/*", }, }, - "FamilyMemberHistory|reason_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", + "MedicationAdministration|medication_reference_MedicationStatement|MedicationStatement": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_MedicationStatement", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -23935,13 +23907,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "MedicationStatement/*", }, }, - "FamilyMemberHistory|reason_reference_BodyStructure|BodyStructure": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_BodyStructure", - ToType: "BodyStructure", + "MedicationStatement|medication_reference_MedicationStatement|MedicationAdministration": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_MedicationStatement", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -23952,13 +23924,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "BodyStructure/*", + "MedicationStatement/*", }, }, - "BodyStructure|reason_reference_BodyStructure|FamilyMemberHistory": { - FromType: "BodyStructure", - EdgeLabel: "reason_reference_BodyStructure", - ToType: "FamilyMemberHistory", + "MedicationAdministration|medication_reference_MedicationRequest|MedicationRequest": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_MedicationRequest", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -23969,64 +23941,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "FamilyMemberHistoryCondition|note_authorReference_Practitioner|Practitioner": { - FromType: "FamilyMemberHistoryCondition", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|note_authorReference_Practitioner|FamilyMemberHistoryCondition": { - FromType: "Practitioner", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "FamilyMemberHistoryCondition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "FamilyMemberHistoryCondition|note_authorReference_PractitionerRole|PractitionerRole": { - FromType: "FamilyMemberHistoryCondition", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", + "MedicationRequest/*", }, }, - "PractitionerRole|note_authorReference_PractitionerRole|FamilyMemberHistoryCondition": { - FromType: "PractitionerRole", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "FamilyMemberHistoryCondition", + "MedicationRequest|medication_reference_MedicationRequest|MedicationAdministration": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_MedicationRequest", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24034,16 +23955,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "MedicationRequest/*", }, }, - "FamilyMemberHistoryCondition|note_authorReference_Patient|Patient": { - FromType: "FamilyMemberHistoryCondition", - EdgeLabel: "note_authorReference_Patient", - ToType: "Patient", + "MedicationAdministration|medication_reference_Procedure|Procedure": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -24051,16 +23972,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "Procedure/*", }, }, - "Patient|note_authorReference_Patient|FamilyMemberHistoryCondition": { - FromType: "Patient", - EdgeLabel: "note_authorReference_Patient", - ToType: "FamilyMemberHistoryCondition", + "Procedure|medication_reference_Procedure|MedicationAdministration": { + FromType: "Procedure", + EdgeLabel: "medication_reference_Procedure", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24068,16 +23989,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "Procedure/*", }, }, - "FamilyMemberHistoryCondition|note_authorReference_Organization|Organization": { - FromType: "FamilyMemberHistoryCondition", - EdgeLabel: "note_authorReference_Organization", - ToType: "Organization", + "MedicationAdministration|medication_reference_DocumentReference|DocumentReference": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -24085,16 +24006,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "DocumentReference/*", }, }, - "Organization|note_authorReference_Organization|FamilyMemberHistoryCondition": { - FromType: "Organization", - EdgeLabel: "note_authorReference_Organization", - ToType: "FamilyMemberHistoryCondition", + "DocumentReference|medication_reference_DocumentReference|MedicationAdministration": { + FromType: "DocumentReference", + EdgeLabel: "medication_reference_DocumentReference", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24102,16 +24023,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "DocumentReference/*", }, }, - "FamilyMemberHistoryParticipant|actor_Practitioner|Practitioner": { - FromType: "FamilyMemberHistoryParticipant", - EdgeLabel: "actor_Practitioner", - ToType: "Practitioner", + "MedicationAdministration|medication_reference_Task|Task": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_Task", + ToType: "Task", Direction: []string{ "outbound", }, @@ -24119,16 +24040,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "family_member_history_participant", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Task/*", }, }, - "Practitioner|actor_Practitioner|FamilyMemberHistoryParticipant": { - FromType: "Practitioner", - EdgeLabel: "actor_Practitioner", - ToType: "FamilyMemberHistoryParticipant", + "Task|medication_reference_Task|MedicationAdministration": { + FromType: "Task", + EdgeLabel: "medication_reference_Task", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24136,16 +24057,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "family_member_history_participant", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Task/*", }, }, - "FamilyMemberHistoryParticipant|actor_PractitionerRole|PractitionerRole": { - FromType: "FamilyMemberHistoryParticipant", - EdgeLabel: "actor_PractitionerRole", - ToType: "PractitionerRole", + "MedicationAdministration|medication_reference_ImagingStudy|ImagingStudy": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_ImagingStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -24153,16 +24074,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "family_member_history_participant", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "ImagingStudy/*", }, }, - "PractitionerRole|actor_PractitionerRole|FamilyMemberHistoryParticipant": { - FromType: "PractitionerRole", - EdgeLabel: "actor_PractitionerRole", - ToType: "FamilyMemberHistoryParticipant", + "ImagingStudy|medication_reference_ImagingStudy|MedicationAdministration": { + FromType: "ImagingStudy", + EdgeLabel: "medication_reference_ImagingStudy", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24170,16 +24091,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "family_member_history_participant", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "ImagingStudy/*", }, }, - "FamilyMemberHistoryParticipant|actor_Patient|Patient": { - FromType: "FamilyMemberHistoryParticipant", - EdgeLabel: "actor_Patient", - ToType: "Patient", + "MedicationAdministration|medication_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_FamilyMemberHistory", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -24187,16 +24108,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "family_member_history_participant", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "FamilyMemberHistory/*", }, }, - "Patient|actor_Patient|FamilyMemberHistoryParticipant": { - FromType: "Patient", - EdgeLabel: "actor_Patient", - ToType: "FamilyMemberHistoryParticipant", + "FamilyMemberHistory|medication_reference_FamilyMemberHistory|MedicationAdministration": { + FromType: "FamilyMemberHistory", + EdgeLabel: "medication_reference_FamilyMemberHistory", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24204,16 +24125,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "family_member_history_participant", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "FamilyMemberHistory/*", }, }, - "FamilyMemberHistoryParticipant|actor_Organization|Organization": { - FromType: "FamilyMemberHistoryParticipant", - EdgeLabel: "actor_Organization", - ToType: "Organization", + "MedicationAdministration|medication_reference_BodyStructure|BodyStructure": { + FromType: "MedicationAdministration", + EdgeLabel: "medication_reference_BodyStructure", + ToType: "BodyStructure", Direction: []string{ "outbound", }, @@ -24221,16 +24142,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "family_member_history_participant", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "BodyStructure/*", }, }, - "Organization|actor_Organization|FamilyMemberHistoryParticipant": { - FromType: "Organization", - EdgeLabel: "actor_Organization", - ToType: "FamilyMemberHistoryParticipant", + "BodyStructure|medication_reference_BodyStructure|MedicationAdministration": { + FromType: "BodyStructure", + EdgeLabel: "medication_reference_BodyStructure", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24238,14 +24159,14 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "family_member_history_participant", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "BodyStructure/*", }, }, - "FamilyMemberHistoryProcedure|note_authorReference_Practitioner|Practitioner": { - FromType: "FamilyMemberHistoryProcedure", + "MedicationAdministration|note_authorReference_Practitioner|Practitioner": { + FromType: "MedicationAdministration", EdgeLabel: "note_authorReference_Practitioner", ToType: "Practitioner", Direction: []string{ @@ -24261,10 +24182,10 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "Practitioner|note_authorReference_Practitioner|FamilyMemberHistoryProcedure": { + "Practitioner|note_authorReference_Practitioner|MedicationAdministration": { FromType: "Practitioner", EdgeLabel: "note_authorReference_Practitioner", - ToType: "FamilyMemberHistoryProcedure", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24278,8 +24199,8 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "FamilyMemberHistoryProcedure|note_authorReference_PractitionerRole|PractitionerRole": { - FromType: "FamilyMemberHistoryProcedure", + "MedicationAdministration|note_authorReference_PractitionerRole|PractitionerRole": { + FromType: "MedicationAdministration", EdgeLabel: "note_authorReference_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ @@ -24295,10 +24216,10 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "PractitionerRole|note_authorReference_PractitionerRole|FamilyMemberHistoryProcedure": { + "PractitionerRole|note_authorReference_PractitionerRole|MedicationAdministration": { FromType: "PractitionerRole", EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "FamilyMemberHistoryProcedure", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24312,8 +24233,8 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "FamilyMemberHistoryProcedure|note_authorReference_Patient|Patient": { - FromType: "FamilyMemberHistoryProcedure", + "MedicationAdministration|note_authorReference_Patient|Patient": { + FromType: "MedicationAdministration", EdgeLabel: "note_authorReference_Patient", ToType: "Patient", Direction: []string{ @@ -24329,10 +24250,10 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "Patient|note_authorReference_Patient|FamilyMemberHistoryProcedure": { + "Patient|note_authorReference_Patient|MedicationAdministration": { FromType: "Patient", EdgeLabel: "note_authorReference_Patient", - ToType: "FamilyMemberHistoryProcedure", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24346,8 +24267,8 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "FamilyMemberHistoryProcedure|note_authorReference_Organization|Organization": { - FromType: "FamilyMemberHistoryProcedure", + "MedicationAdministration|note_authorReference_Organization|Organization": { + FromType: "MedicationAdministration", EdgeLabel: "note_authorReference_Organization", ToType: "Organization", Direction: []string{ @@ -24363,10 +24284,10 @@ var Traversals = map[string]Traversal{ "Organization/*", }, }, - "Organization|note_authorReference_Organization|FamilyMemberHistoryProcedure": { + "Organization|note_authorReference_Organization|MedicationAdministration": { FromType: "Organization", EdgeLabel: "note_authorReference_Organization", - ToType: "FamilyMemberHistoryProcedure", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24380,9 +24301,9 @@ var Traversals = map[string]Traversal{ "Organization/*", }, }, - "Group|managingEntity_Organization|Organization": { - FromType: "Group", - EdgeLabel: "managingEntity_Organization", + "MedicationAdministration|reason_reference_Organization|Organization": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_Organization", ToType: "Organization", Direction: []string{ "outbound", @@ -24391,101 +24312,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group", + "codeable_reference", }, RegexMatch: []string{ "Organization/*", }, }, - "Organization|managingEntity_Organization|Group": { + "Organization|reason_reference_Organization|MedicationAdministration": { FromType: "Organization", - EdgeLabel: "managingEntity_Organization", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "group", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Group|managingEntity_Practitioner|Practitioner": { - FromType: "Group", - EdgeLabel: "managingEntity_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "group", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|managingEntity_Practitioner|Group": { - FromType: "Practitioner", - EdgeLabel: "managingEntity_Practitioner", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "group", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Group|managingEntity_PractitionerRole|PractitionerRole": { - FromType: "Group", - EdgeLabel: "managingEntity_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "group", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|managingEntity_PractitionerRole|Group": { - FromType: "PractitionerRole", - EdgeLabel: "managingEntity_PractitionerRole", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "group", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Group|characteristic_valueReference_Organization|Organization": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_Organization", - ToType: "Organization", + EdgeLabel: "reason_reference_Organization", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24493,15 +24329,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Organization/*", }, }, - "Organization|characteristic_valueReference_Organization|Group": { - FromType: "Organization", - EdgeLabel: "characteristic_valueReference_Organization", + "MedicationAdministration|reason_reference_Group|Group": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_Group", ToType: "Group", Direction: []string{ "outbound", @@ -24510,16 +24346,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Group/*", }, }, - "Group|characteristic_valueReference_Group|Group": { + "Group|reason_reference_Group|MedicationAdministration": { FromType: "Group", - EdgeLabel: "characteristic_valueReference_Group", - ToType: "Group", + EdgeLabel: "reason_reference_Group", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24527,15 +24363,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Group/*", }, }, - "Group|characteristic_valueReference_Practitioner|Practitioner": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_Practitioner", + "MedicationAdministration|reason_reference_Practitioner|Practitioner": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", @@ -24544,16 +24380,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Practitioner|characteristic_valueReference_Practitioner|Group": { + "Practitioner|reason_reference_Practitioner|MedicationAdministration": { FromType: "Practitioner", - EdgeLabel: "characteristic_valueReference_Practitioner", - ToType: "Group", + EdgeLabel: "reason_reference_Practitioner", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24561,15 +24397,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Group|characteristic_valueReference_PractitionerRole|PractitionerRole": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_PractitionerRole", + "MedicationAdministration|reason_reference_PractitionerRole|PractitionerRole": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", @@ -24578,16 +24414,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "PractitionerRole|characteristic_valueReference_PractitionerRole|Group": { + "PractitionerRole|reason_reference_PractitionerRole|MedicationAdministration": { FromType: "PractitionerRole", - EdgeLabel: "characteristic_valueReference_PractitionerRole", - ToType: "Group", + EdgeLabel: "reason_reference_PractitionerRole", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24595,15 +24431,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "Group|characteristic_valueReference_ResearchStudy|ResearchStudy": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_ResearchStudy", + "MedicationAdministration|reason_reference_ResearchStudy|ResearchStudy": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -24612,16 +24448,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "ResearchStudy|characteristic_valueReference_ResearchStudy|Group": { + "ResearchStudy|reason_reference_ResearchStudy|MedicationAdministration": { FromType: "ResearchStudy", - EdgeLabel: "characteristic_valueReference_ResearchStudy", - ToType: "Group", + EdgeLabel: "reason_reference_ResearchStudy", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24629,15 +24465,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "Group|characteristic_valueReference_Patient|Patient": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_Patient", + "MedicationAdministration|reason_reference_Patient|Patient": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -24646,16 +24482,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|characteristic_valueReference_Patient|Group": { + "Patient|reason_reference_Patient|MedicationAdministration": { FromType: "Patient", - EdgeLabel: "characteristic_valueReference_Patient", - ToType: "Group", + EdgeLabel: "reason_reference_Patient", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24663,15 +24499,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Patient/*", }, }, - "Group|characteristic_valueReference_ResearchSubject|ResearchSubject": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_ResearchSubject", + "MedicationAdministration|reason_reference_ResearchSubject|ResearchSubject": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -24680,16 +24516,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "ResearchSubject|characteristic_valueReference_ResearchSubject|Group": { + "ResearchSubject|reason_reference_ResearchSubject|MedicationAdministration": { FromType: "ResearchSubject", - EdgeLabel: "characteristic_valueReference_ResearchSubject", - ToType: "Group", + EdgeLabel: "reason_reference_ResearchSubject", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24697,15 +24533,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "Group|characteristic_valueReference_Substance|Substance": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_Substance", + "MedicationAdministration|reason_reference_Substance|Substance": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -24714,16 +24550,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Substance/*", }, }, - "Substance|characteristic_valueReference_Substance|Group": { + "Substance|reason_reference_Substance|MedicationAdministration": { FromType: "Substance", - EdgeLabel: "characteristic_valueReference_Substance", - ToType: "Group", + EdgeLabel: "reason_reference_Substance", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24731,15 +24567,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Substance/*", }, }, - "Group|characteristic_valueReference_SubstanceDefinition|SubstanceDefinition": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_SubstanceDefinition", + "MedicationAdministration|reason_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -24748,16 +24584,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|characteristic_valueReference_SubstanceDefinition|Group": { + "SubstanceDefinition|reason_reference_SubstanceDefinition|MedicationAdministration": { FromType: "SubstanceDefinition", - EdgeLabel: "characteristic_valueReference_SubstanceDefinition", - ToType: "Group", + EdgeLabel: "reason_reference_SubstanceDefinition", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24765,15 +24601,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "Group|characteristic_valueReference_Specimen|Specimen": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_Specimen", + "MedicationAdministration|reason_reference_Specimen|Specimen": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -24782,16 +24618,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Specimen/*", }, }, - "Specimen|characteristic_valueReference_Specimen|Group": { + "Specimen|reason_reference_Specimen|MedicationAdministration": { FromType: "Specimen", - EdgeLabel: "characteristic_valueReference_Specimen", - ToType: "Group", + EdgeLabel: "reason_reference_Specimen", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24799,15 +24635,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Specimen/*", }, }, - "Group|characteristic_valueReference_Observation|Observation": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_Observation", + "MedicationAdministration|reason_reference_Observation|Observation": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -24816,16 +24652,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Observation/*", }, }, - "Observation|characteristic_valueReference_Observation|Group": { + "Observation|reason_reference_Observation|MedicationAdministration": { FromType: "Observation", - EdgeLabel: "characteristic_valueReference_Observation", - ToType: "Group", + EdgeLabel: "reason_reference_Observation", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24833,15 +24669,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Observation/*", }, }, - "Group|characteristic_valueReference_DiagnosticReport|DiagnosticReport": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_DiagnosticReport", + "MedicationAdministration|reason_reference_DiagnosticReport|DiagnosticReport": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -24850,16 +24686,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "DiagnosticReport|characteristic_valueReference_DiagnosticReport|Group": { + "DiagnosticReport|reason_reference_DiagnosticReport|MedicationAdministration": { FromType: "DiagnosticReport", - EdgeLabel: "characteristic_valueReference_DiagnosticReport", - ToType: "Group", + EdgeLabel: "reason_reference_DiagnosticReport", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24867,15 +24703,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "Group|characteristic_valueReference_Condition|Condition": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_Condition", + "MedicationAdministration|reason_reference_Condition|Condition": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -24884,16 +24720,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Condition/*", }, }, - "Condition|characteristic_valueReference_Condition|Group": { + "Condition|reason_reference_Condition|MedicationAdministration": { FromType: "Condition", - EdgeLabel: "characteristic_valueReference_Condition", - ToType: "Group", + EdgeLabel: "reason_reference_Condition", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24901,15 +24737,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Condition/*", }, }, - "Group|characteristic_valueReference_Medication|Medication": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_Medication", + "MedicationAdministration|reason_reference_Medication|Medication": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -24918,16 +24754,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Medication/*", }, }, - "Medication|characteristic_valueReference_Medication|Group": { + "Medication|reason_reference_Medication|MedicationAdministration": { FromType: "Medication", - EdgeLabel: "characteristic_valueReference_Medication", - ToType: "Group", + EdgeLabel: "reason_reference_Medication", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -24935,15 +24771,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Medication/*", }, }, - "Group|characteristic_valueReference_MedicationAdministration|MedicationAdministration": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_MedicationAdministration", + "MedicationAdministration|reason_reference_MedicationAdministration|MedicationAdministration": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -24952,32 +24788,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "MedicationAdministration|characteristic_valueReference_MedicationAdministration|Group": { + "MedicationAdministration|reason_reference_MedicationStatement|MedicationStatement": { FromType: "MedicationAdministration", - EdgeLabel: "characteristic_valueReference_MedicationAdministration", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "group_characteristic", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "Group|characteristic_valueReference_MedicationStatement|MedicationStatement": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_MedicationStatement", + EdgeLabel: "reason_reference_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -24986,16 +24805,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "MedicationStatement|characteristic_valueReference_MedicationStatement|Group": { + "MedicationStatement|reason_reference_MedicationStatement|MedicationAdministration": { FromType: "MedicationStatement", - EdgeLabel: "characteristic_valueReference_MedicationStatement", - ToType: "Group", + EdgeLabel: "reason_reference_MedicationStatement", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -25003,15 +24822,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "Group|characteristic_valueReference_MedicationRequest|MedicationRequest": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_MedicationRequest", + "MedicationAdministration|reason_reference_MedicationRequest|MedicationRequest": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -25020,16 +24839,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "MedicationRequest|characteristic_valueReference_MedicationRequest|Group": { + "MedicationRequest|reason_reference_MedicationRequest|MedicationAdministration": { FromType: "MedicationRequest", - EdgeLabel: "characteristic_valueReference_MedicationRequest", - ToType: "Group", + EdgeLabel: "reason_reference_MedicationRequest", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -25037,15 +24856,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "Group|characteristic_valueReference_Procedure|Procedure": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_Procedure", + "MedicationAdministration|reason_reference_Procedure|Procedure": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_Procedure", ToType: "Procedure", Direction: []string{ "outbound", @@ -25054,16 +24873,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Procedure/*", }, }, - "Procedure|characteristic_valueReference_Procedure|Group": { + "Procedure|reason_reference_Procedure|MedicationAdministration": { FromType: "Procedure", - EdgeLabel: "characteristic_valueReference_Procedure", - ToType: "Group", + EdgeLabel: "reason_reference_Procedure", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -25071,15 +24890,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Procedure/*", }, }, - "Group|characteristic_valueReference_DocumentReference|DocumentReference": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_DocumentReference", + "MedicationAdministration|reason_reference_DocumentReference|DocumentReference": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_DocumentReference", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -25088,16 +24907,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "DocumentReference/*", }, }, - "DocumentReference|characteristic_valueReference_DocumentReference|Group": { + "DocumentReference|reason_reference_DocumentReference|MedicationAdministration": { FromType: "DocumentReference", - EdgeLabel: "characteristic_valueReference_DocumentReference", - ToType: "Group", + EdgeLabel: "reason_reference_DocumentReference", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -25105,15 +24924,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "DocumentReference/*", }, }, - "Group|characteristic_valueReference_Task|Task": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_Task", + "MedicationAdministration|reason_reference_Task|Task": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_Task", ToType: "Task", Direction: []string{ "outbound", @@ -25122,16 +24941,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Task/*", }, }, - "Task|characteristic_valueReference_Task|Group": { + "Task|reason_reference_Task|MedicationAdministration": { FromType: "Task", - EdgeLabel: "characteristic_valueReference_Task", - ToType: "Group", + EdgeLabel: "reason_reference_Task", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -25139,15 +24958,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "Task/*", }, }, - "Group|characteristic_valueReference_ImagingStudy|ImagingStudy": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_ImagingStudy", + "MedicationAdministration|reason_reference_ImagingStudy|ImagingStudy": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", @@ -25156,16 +24975,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "ImagingStudy/*", }, }, - "ImagingStudy|characteristic_valueReference_ImagingStudy|Group": { + "ImagingStudy|reason_reference_ImagingStudy|MedicationAdministration": { FromType: "ImagingStudy", - EdgeLabel: "characteristic_valueReference_ImagingStudy", - ToType: "Group", + EdgeLabel: "reason_reference_ImagingStudy", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -25173,15 +24992,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "ImagingStudy/*", }, }, - "Group|characteristic_valueReference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_FamilyMemberHistory", + "MedicationAdministration|reason_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -25190,16 +25009,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|characteristic_valueReference_FamilyMemberHistory|Group": { + "FamilyMemberHistory|reason_reference_FamilyMemberHistory|MedicationAdministration": { FromType: "FamilyMemberHistory", - EdgeLabel: "characteristic_valueReference_FamilyMemberHistory", - ToType: "Group", + EdgeLabel: "reason_reference_FamilyMemberHistory", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -25207,15 +25026,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "FamilyMemberHistory/*", }, }, - "Group|characteristic_valueReference_BodyStructure|BodyStructure": { - FromType: "Group", - EdgeLabel: "characteristic_valueReference_BodyStructure", + "MedicationAdministration|reason_reference_BodyStructure|BodyStructure": { + FromType: "MedicationAdministration", + EdgeLabel: "reason_reference_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", @@ -25224,16 +25043,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "BodyStructure/*", }, }, - "BodyStructure|characteristic_valueReference_BodyStructure|Group": { + "BodyStructure|reason_reference_BodyStructure|MedicationAdministration": { FromType: "BodyStructure", - EdgeLabel: "characteristic_valueReference_BodyStructure", - ToType: "Group", + EdgeLabel: "reason_reference_BodyStructure", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -25241,339 +25060,305 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "codeable_reference", }, RegexMatch: []string{ "BodyStructure/*", }, }, - "Group|member_entity_Group|Group": { - FromType: "Group", - EdgeLabel: "member_entity_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "group_member", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|member_entity_Organization|Organization": { - FromType: "Group", - EdgeLabel: "member_entity_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "group_member", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|member_entity_Organization|Group": { - FromType: "Organization", - EdgeLabel: "member_entity_Organization", - ToType: "Group", + "MedicationRequest|basedOn_MedicationRequest|MedicationRequest": { + FromType: "MedicationRequest", + EdgeLabel: "basedOn_MedicationRequest", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "basedOn_medication_request", }, RegexMatch: []string{ - "Organization/*", + "MedicationRequest/*", }, }, - "Group|member_entity_Patient|Patient": { - FromType: "Group", - EdgeLabel: "member_entity_Patient", + "MedicationRequest|informationSource_Patient|Patient": { + FromType: "MedicationRequest", + EdgeLabel: "informationSource_Patient", ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "informationSource_medication_request", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|member_entity_Patient|Group": { + "Patient|informationSource_Patient|MedicationRequest": { FromType: "Patient", - EdgeLabel: "member_entity_Patient", - ToType: "Group", + EdgeLabel: "informationSource_Patient", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "informationSource_medication_request", }, RegexMatch: []string{ "Patient/*", }, }, - "Group|member_entity_Practitioner|Practitioner": { - FromType: "Group", - EdgeLabel: "member_entity_Practitioner", + "MedicationRequest|informationSource_Practitioner|Practitioner": { + FromType: "MedicationRequest", + EdgeLabel: "informationSource_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "informationSource_medication_request", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Practitioner|member_entity_Practitioner|Group": { + "Practitioner|informationSource_Practitioner|MedicationRequest": { FromType: "Practitioner", - EdgeLabel: "member_entity_Practitioner", - ToType: "Group", + EdgeLabel: "informationSource_Practitioner", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "informationSource_medication_request", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Group|member_entity_PractitionerRole|PractitionerRole": { - FromType: "Group", - EdgeLabel: "member_entity_PractitionerRole", + "MedicationRequest|informationSource_PractitionerRole|PractitionerRole": { + FromType: "MedicationRequest", + EdgeLabel: "informationSource_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "informationSource_medication_request", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "PractitionerRole|member_entity_PractitionerRole|Group": { + "PractitionerRole|informationSource_PractitionerRole|MedicationRequest": { FromType: "PractitionerRole", - EdgeLabel: "member_entity_PractitionerRole", - ToType: "Group", + EdgeLabel: "informationSource_PractitionerRole", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "informationSource_medication_request", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "Group|member_entity_Specimen|Specimen": { - FromType: "Group", - EdgeLabel: "member_entity_Specimen", - ToType: "Specimen", + "MedicationRequest|informationSource_Organization|Organization": { + FromType: "MedicationRequest", + EdgeLabel: "informationSource_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "informationSource_medication_request", }, RegexMatch: []string{ - "Specimen/*", + "Organization/*", }, }, - "Specimen|member_entity_Specimen|Group": { - FromType: "Specimen", - EdgeLabel: "member_entity_Specimen", - ToType: "Group", + "Organization|informationSource_Organization|MedicationRequest": { + FromType: "Organization", + EdgeLabel: "informationSource_Organization", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "informationSource_medication_request", }, RegexMatch: []string{ - "Specimen/*", + "Organization/*", }, }, - "GroupCharacteristic|valueReference_Organization|Organization": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_Organization", - ToType: "Organization", + "MedicationRequest|performer_Practitioner|Practitioner": { + FromType: "MedicationRequest", + EdgeLabel: "performer_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "performer_medication_request", }, RegexMatch: []string{ - "Organization/*", + "Practitioner/*", }, }, - "Organization|valueReference_Organization|GroupCharacteristic": { - FromType: "Organization", - EdgeLabel: "valueReference_Organization", - ToType: "GroupCharacteristic", + "Practitioner|performer_Practitioner|MedicationRequest": { + FromType: "Practitioner", + EdgeLabel: "performer_Practitioner", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "performer_medication_request", }, RegexMatch: []string{ - "Organization/*", + "Practitioner/*", }, }, - "GroupCharacteristic|valueReference_Group|Group": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_Group", - ToType: "Group", + "MedicationRequest|performer_PractitionerRole|PractitionerRole": { + FromType: "MedicationRequest", + EdgeLabel: "performer_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "performer_medication_request", }, RegexMatch: []string{ - "Group/*", + "PractitionerRole/*", }, }, - "Group|valueReference_Group|GroupCharacteristic": { - FromType: "Group", - EdgeLabel: "valueReference_Group", - ToType: "GroupCharacteristic", + "PractitionerRole|performer_PractitionerRole|MedicationRequest": { + FromType: "PractitionerRole", + EdgeLabel: "performer_PractitionerRole", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "performer_medication_request", }, RegexMatch: []string{ - "Group/*", + "PractitionerRole/*", }, }, - "GroupCharacteristic|valueReference_Practitioner|Practitioner": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_Practitioner", - ToType: "Practitioner", + "MedicationRequest|performer_Organization|Organization": { + FromType: "MedicationRequest", + EdgeLabel: "performer_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "performer_medication_request", }, RegexMatch: []string{ - "Practitioner/*", + "Organization/*", }, }, - "Practitioner|valueReference_Practitioner|GroupCharacteristic": { - FromType: "Practitioner", - EdgeLabel: "valueReference_Practitioner", - ToType: "GroupCharacteristic", + "Organization|performer_Organization|MedicationRequest": { + FromType: "Organization", + EdgeLabel: "performer_Organization", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "performer_medication_request", }, RegexMatch: []string{ - "Practitioner/*", + "Organization/*", }, }, - "GroupCharacteristic|valueReference_PractitionerRole|PractitionerRole": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_PractitionerRole", - ToType: "PractitionerRole", + "MedicationRequest|performer_Patient|Patient": { + FromType: "MedicationRequest", + EdgeLabel: "performer_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "performer_medication_request", }, RegexMatch: []string{ - "PractitionerRole/*", + "Patient/*", }, }, - "PractitionerRole|valueReference_PractitionerRole|GroupCharacteristic": { - FromType: "PractitionerRole", - EdgeLabel: "valueReference_PractitionerRole", - ToType: "GroupCharacteristic", + "Patient|performer_Patient|MedicationRequest": { + FromType: "Patient", + EdgeLabel: "performer_Patient", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "performer_medication_request", }, RegexMatch: []string{ - "PractitionerRole/*", + "Patient/*", }, }, - "GroupCharacteristic|valueReference_ResearchStudy|ResearchStudy": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_ResearchStudy", - ToType: "ResearchStudy", + "MedicationRequest|priorPrescription|MedicationRequest": { + FromType: "MedicationRequest", + EdgeLabel: "priorPrescription", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -25581,16 +25366,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "priorPrescription_medication_request", }, RegexMatch: []string{ - "ResearchStudy/*", + "MedicationRequest/*", }, }, - "ResearchStudy|valueReference_ResearchStudy|GroupCharacteristic": { - FromType: "ResearchStudy", - EdgeLabel: "valueReference_ResearchStudy", - ToType: "GroupCharacteristic", + "MedicationRequest|recorder_Practitioner|Practitioner": { + FromType: "MedicationRequest", + EdgeLabel: "recorder_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -25598,16 +25383,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "recorder_medication_request", }, RegexMatch: []string{ - "ResearchStudy/*", + "Practitioner/*", }, }, - "GroupCharacteristic|valueReference_Patient|Patient": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_Patient", - ToType: "Patient", + "Practitioner|recorder_Practitioner|MedicationRequest": { + FromType: "Practitioner", + EdgeLabel: "recorder_Practitioner", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -25615,16 +25400,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "recorder_medication_request", }, RegexMatch: []string{ - "Patient/*", + "Practitioner/*", }, }, - "Patient|valueReference_Patient|GroupCharacteristic": { - FromType: "Patient", - EdgeLabel: "valueReference_Patient", - ToType: "GroupCharacteristic", + "MedicationRequest|recorder_PractitionerRole|PractitionerRole": { + FromType: "MedicationRequest", + EdgeLabel: "recorder_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -25632,16 +25417,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "recorder_medication_request", }, RegexMatch: []string{ - "Patient/*", + "PractitionerRole/*", }, }, - "GroupCharacteristic|valueReference_ResearchSubject|ResearchSubject": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_ResearchSubject", - ToType: "ResearchSubject", + "PractitionerRole|recorder_PractitionerRole|MedicationRequest": { + FromType: "PractitionerRole", + EdgeLabel: "recorder_PractitionerRole", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -25649,33 +25434,33 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "recorder_medication_request", }, RegexMatch: []string{ - "ResearchSubject/*", + "PractitionerRole/*", }, }, - "ResearchSubject|valueReference_ResearchSubject|GroupCharacteristic": { - FromType: "ResearchSubject", - EdgeLabel: "valueReference_ResearchSubject", - ToType: "GroupCharacteristic", - Direction: []string{ - "outbound", - }, + "MedicationRequest|requester_Practitioner|Practitioner": { + FromType: "MedicationRequest", + EdgeLabel: "requester_Practitioner", + ToType: "Practitioner", + Direction: []string{ + "outbound", + }, Multiplicity: []string{ "has_one", }, Backref: []string{ - "group_characteristic", + "requester_medication_request", }, RegexMatch: []string{ - "ResearchSubject/*", + "Practitioner/*", }, }, - "GroupCharacteristic|valueReference_Substance|Substance": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_Substance", - ToType: "Substance", + "Practitioner|requester_Practitioner|MedicationRequest": { + FromType: "Practitioner", + EdgeLabel: "requester_Practitioner", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -25683,16 +25468,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "requester_medication_request", }, RegexMatch: []string{ - "Substance/*", + "Practitioner/*", }, }, - "Substance|valueReference_Substance|GroupCharacteristic": { - FromType: "Substance", - EdgeLabel: "valueReference_Substance", - ToType: "GroupCharacteristic", + "MedicationRequest|requester_PractitionerRole|PractitionerRole": { + FromType: "MedicationRequest", + EdgeLabel: "requester_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -25700,16 +25485,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "requester_medication_request", }, RegexMatch: []string{ - "Substance/*", + "PractitionerRole/*", }, }, - "GroupCharacteristic|valueReference_SubstanceDefinition|SubstanceDefinition": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_SubstanceDefinition", - ToType: "SubstanceDefinition", + "PractitionerRole|requester_PractitionerRole|MedicationRequest": { + FromType: "PractitionerRole", + EdgeLabel: "requester_PractitionerRole", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -25717,16 +25502,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "requester_medication_request", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "PractitionerRole/*", }, }, - "SubstanceDefinition|valueReference_SubstanceDefinition|GroupCharacteristic": { - FromType: "SubstanceDefinition", - EdgeLabel: "valueReference_SubstanceDefinition", - ToType: "GroupCharacteristic", + "MedicationRequest|requester_Organization|Organization": { + FromType: "MedicationRequest", + EdgeLabel: "requester_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -25734,16 +25519,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "requester_medication_request", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "Organization/*", }, }, - "GroupCharacteristic|valueReference_Specimen|Specimen": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_Specimen", - ToType: "Specimen", + "Organization|requester_Organization|MedicationRequest": { + FromType: "Organization", + EdgeLabel: "requester_Organization", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -25751,16 +25536,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "requester_medication_request", }, RegexMatch: []string{ - "Specimen/*", + "Organization/*", }, }, - "Specimen|valueReference_Specimen|GroupCharacteristic": { - FromType: "Specimen", - EdgeLabel: "valueReference_Specimen", - ToType: "GroupCharacteristic", + "MedicationRequest|requester_Patient|Patient": { + FromType: "MedicationRequest", + EdgeLabel: "requester_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -25768,16 +25553,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "requester_medication_request", }, RegexMatch: []string{ - "Specimen/*", + "Patient/*", }, }, - "GroupCharacteristic|valueReference_Observation|Observation": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_Observation", - ToType: "Observation", + "Patient|requester_Patient|MedicationRequest": { + FromType: "Patient", + EdgeLabel: "requester_Patient", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -25785,16 +25570,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "requester_medication_request", }, RegexMatch: []string{ - "Observation/*", + "Patient/*", }, }, - "Observation|valueReference_Observation|GroupCharacteristic": { - FromType: "Observation", - EdgeLabel: "valueReference_Observation", - ToType: "GroupCharacteristic", + "MedicationRequest|subject_Patient|Patient": { + FromType: "MedicationRequest", + EdgeLabel: "subject_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -25802,16 +25587,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "subject_medication_request", }, RegexMatch: []string{ - "Observation/*", + "Patient/*", }, }, - "GroupCharacteristic|valueReference_DiagnosticReport|DiagnosticReport": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_DiagnosticReport", - ToType: "DiagnosticReport", + "Patient|subject_Patient|MedicationRequest": { + FromType: "Patient", + EdgeLabel: "subject_Patient", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -25819,16 +25604,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "subject_medication_request", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Patient/*", }, }, - "DiagnosticReport|valueReference_DiagnosticReport|GroupCharacteristic": { - FromType: "DiagnosticReport", - EdgeLabel: "valueReference_DiagnosticReport", - ToType: "GroupCharacteristic", + "MedicationRequest|subject_Group|Group": { + FromType: "MedicationRequest", + EdgeLabel: "subject_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -25836,16 +25621,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "subject_medication_request", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Group/*", }, }, - "GroupCharacteristic|valueReference_Condition|Condition": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_Condition", - ToType: "Condition", + "Group|subject_Group|MedicationRequest": { + FromType: "Group", + EdgeLabel: "subject_Group", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -25853,611 +25638,611 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "group_characteristic", + "subject_medication_request", }, RegexMatch: []string{ - "Condition/*", + "Group/*", }, }, - "Condition|valueReference_Condition|GroupCharacteristic": { - FromType: "Condition", - EdgeLabel: "valueReference_Condition", - ToType: "GroupCharacteristic", + "MedicationRequest|supportingInformation_Organization|Organization": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Condition/*", + "Organization/*", }, }, - "GroupCharacteristic|valueReference_Medication|Medication": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_Medication", - ToType: "Medication", + "Organization|supportingInformation_Organization|MedicationRequest": { + FromType: "Organization", + EdgeLabel: "supportingInformation_Organization", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Medication/*", + "Organization/*", }, }, - "Medication|valueReference_Medication|GroupCharacteristic": { - FromType: "Medication", - EdgeLabel: "valueReference_Medication", - ToType: "GroupCharacteristic", + "MedicationRequest|supportingInformation_Group|Group": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_Group", + ToType: "Group", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Medication/*", + "Group/*", }, }, - "GroupCharacteristic|valueReference_MedicationAdministration|MedicationAdministration": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_MedicationAdministration", - ToType: "MedicationAdministration", + "Group|supportingInformation_Group|MedicationRequest": { + FromType: "Group", + EdgeLabel: "supportingInformation_Group", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Group/*", }, }, - "MedicationAdministration|valueReference_MedicationAdministration|GroupCharacteristic": { - FromType: "MedicationAdministration", - EdgeLabel: "valueReference_MedicationAdministration", - ToType: "GroupCharacteristic", + "MedicationRequest|supportingInformation_Practitioner|Practitioner": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Practitioner/*", }, }, - "GroupCharacteristic|valueReference_MedicationStatement|MedicationStatement": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_MedicationStatement", - ToType: "MedicationStatement", + "Practitioner|supportingInformation_Practitioner|MedicationRequest": { + FromType: "Practitioner", + EdgeLabel: "supportingInformation_Practitioner", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "MedicationStatement/*", + "Practitioner/*", }, }, - "MedicationStatement|valueReference_MedicationStatement|GroupCharacteristic": { - FromType: "MedicationStatement", - EdgeLabel: "valueReference_MedicationStatement", - ToType: "GroupCharacteristic", + "MedicationRequest|supportingInformation_PractitionerRole|PractitionerRole": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "MedicationStatement/*", + "PractitionerRole/*", }, }, - "GroupCharacteristic|valueReference_MedicationRequest|MedicationRequest": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_MedicationRequest", + "PractitionerRole|supportingInformation_PractitionerRole|MedicationRequest": { + FromType: "PractitionerRole", + EdgeLabel: "supportingInformation_PractitionerRole", ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "MedicationRequest/*", + "PractitionerRole/*", }, }, - "MedicationRequest|valueReference_MedicationRequest|GroupCharacteristic": { + "MedicationRequest|supportingInformation_ResearchStudy|ResearchStudy": { FromType: "MedicationRequest", - EdgeLabel: "valueReference_MedicationRequest", - ToType: "GroupCharacteristic", + EdgeLabel: "supportingInformation_ResearchStudy", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "MedicationRequest/*", + "ResearchStudy/*", }, }, - "GroupCharacteristic|valueReference_Procedure|Procedure": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_Procedure", - ToType: "Procedure", + "ResearchStudy|supportingInformation_ResearchStudy|MedicationRequest": { + FromType: "ResearchStudy", + EdgeLabel: "supportingInformation_ResearchStudy", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Procedure/*", + "ResearchStudy/*", }, }, - "Procedure|valueReference_Procedure|GroupCharacteristic": { - FromType: "Procedure", - EdgeLabel: "valueReference_Procedure", - ToType: "GroupCharacteristic", + "MedicationRequest|supportingInformation_Patient|Patient": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Procedure/*", + "Patient/*", }, }, - "GroupCharacteristic|valueReference_DocumentReference|DocumentReference": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_DocumentReference", - ToType: "DocumentReference", + "Patient|supportingInformation_Patient|MedicationRequest": { + FromType: "Patient", + EdgeLabel: "supportingInformation_Patient", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "DocumentReference/*", + "Patient/*", }, }, - "DocumentReference|valueReference_DocumentReference|GroupCharacteristic": { - FromType: "DocumentReference", - EdgeLabel: "valueReference_DocumentReference", - ToType: "GroupCharacteristic", + "MedicationRequest|supportingInformation_ResearchSubject|ResearchSubject": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_ResearchSubject", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "DocumentReference/*", + "ResearchSubject/*", }, }, - "GroupCharacteristic|valueReference_Task|Task": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_Task", - ToType: "Task", + "ResearchSubject|supportingInformation_ResearchSubject|MedicationRequest": { + FromType: "ResearchSubject", + EdgeLabel: "supportingInformation_ResearchSubject", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Task/*", + "ResearchSubject/*", }, }, - "Task|valueReference_Task|GroupCharacteristic": { - FromType: "Task", - EdgeLabel: "valueReference_Task", - ToType: "GroupCharacteristic", + "MedicationRequest|supportingInformation_Substance|Substance": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_Substance", + ToType: "Substance", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Task/*", + "Substance/*", }, }, - "GroupCharacteristic|valueReference_ImagingStudy|ImagingStudy": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_ImagingStudy", - ToType: "ImagingStudy", + "Substance|supportingInformation_Substance|MedicationRequest": { + FromType: "Substance", + EdgeLabel: "supportingInformation_Substance", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "ImagingStudy/*", + "Substance/*", }, }, - "ImagingStudy|valueReference_ImagingStudy|GroupCharacteristic": { - FromType: "ImagingStudy", - EdgeLabel: "valueReference_ImagingStudy", - ToType: "GroupCharacteristic", + "MedicationRequest|supportingInformation_SubstanceDefinition|SubstanceDefinition": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_SubstanceDefinition", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "ImagingStudy/*", + "SubstanceDefinition/*", }, }, - "GroupCharacteristic|valueReference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", + "SubstanceDefinition|supportingInformation_SubstanceDefinition|MedicationRequest": { + FromType: "SubstanceDefinition", + EdgeLabel: "supportingInformation_SubstanceDefinition", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "SubstanceDefinition/*", }, }, - "FamilyMemberHistory|valueReference_FamilyMemberHistory|GroupCharacteristic": { - FromType: "FamilyMemberHistory", - EdgeLabel: "valueReference_FamilyMemberHistory", - ToType: "GroupCharacteristic", + "MedicationRequest|supportingInformation_Specimen|Specimen": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_Specimen", + ToType: "Specimen", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Specimen/*", }, }, - "GroupCharacteristic|valueReference_BodyStructure|BodyStructure": { - FromType: "GroupCharacteristic", - EdgeLabel: "valueReference_BodyStructure", - ToType: "BodyStructure", + "Specimen|supportingInformation_Specimen|MedicationRequest": { + FromType: "Specimen", + EdgeLabel: "supportingInformation_Specimen", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "BodyStructure/*", + "Specimen/*", }, }, - "BodyStructure|valueReference_BodyStructure|GroupCharacteristic": { - FromType: "BodyStructure", - EdgeLabel: "valueReference_BodyStructure", - ToType: "GroupCharacteristic", + "MedicationRequest|supportingInformation_Observation|Observation": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_Observation", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_characteristic", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "BodyStructure/*", + "Observation/*", }, }, - "GroupMember|entity_Group|Group": { - FromType: "GroupMember", - EdgeLabel: "entity_Group", - ToType: "Group", + "Observation|supportingInformation_Observation|MedicationRequest": { + FromType: "Observation", + EdgeLabel: "supportingInformation_Observation", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Group/*", + "Observation/*", }, }, - "Group|entity_Group|GroupMember": { - FromType: "Group", - EdgeLabel: "entity_Group", - ToType: "GroupMember", + "MedicationRequest|supportingInformation_DiagnosticReport|DiagnosticReport": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_DiagnosticReport", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Group/*", + "DiagnosticReport/*", }, }, - "GroupMember|entity_Organization|Organization": { - FromType: "GroupMember", - EdgeLabel: "entity_Organization", - ToType: "Organization", + "DiagnosticReport|supportingInformation_DiagnosticReport|MedicationRequest": { + FromType: "DiagnosticReport", + EdgeLabel: "supportingInformation_DiagnosticReport", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Organization/*", + "DiagnosticReport/*", }, }, - "Organization|entity_Organization|GroupMember": { - FromType: "Organization", - EdgeLabel: "entity_Organization", - ToType: "GroupMember", + "MedicationRequest|supportingInformation_Condition|Condition": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_Condition", + ToType: "Condition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Organization/*", + "Condition/*", }, }, - "GroupMember|entity_Patient|Patient": { - FromType: "GroupMember", - EdgeLabel: "entity_Patient", - ToType: "Patient", + "Condition|supportingInformation_Condition|MedicationRequest": { + FromType: "Condition", + EdgeLabel: "supportingInformation_Condition", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Patient/*", + "Condition/*", }, }, - "Patient|entity_Patient|GroupMember": { - FromType: "Patient", - EdgeLabel: "entity_Patient", - ToType: "GroupMember", + "MedicationRequest|supportingInformation_Medication|Medication": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_Medication", + ToType: "Medication", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Patient/*", + "Medication/*", }, }, - "GroupMember|entity_Practitioner|Practitioner": { - FromType: "GroupMember", - EdgeLabel: "entity_Practitioner", - ToType: "Practitioner", + "Medication|supportingInformation_Medication|MedicationRequest": { + FromType: "Medication", + EdgeLabel: "supportingInformation_Medication", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Practitioner/*", + "Medication/*", }, }, - "Practitioner|entity_Practitioner|GroupMember": { - FromType: "Practitioner", - EdgeLabel: "entity_Practitioner", - ToType: "GroupMember", + "MedicationRequest|supportingInformation_MedicationAdministration|MedicationAdministration": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_MedicationAdministration", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Practitioner/*", + "MedicationAdministration/*", }, }, - "GroupMember|entity_PractitionerRole|PractitionerRole": { - FromType: "GroupMember", - EdgeLabel: "entity_PractitionerRole", - ToType: "PractitionerRole", + "MedicationAdministration|supportingInformation_MedicationAdministration|MedicationRequest": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInformation_MedicationAdministration", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "PractitionerRole/*", + "MedicationAdministration/*", }, }, - "PractitionerRole|entity_PractitionerRole|GroupMember": { - FromType: "PractitionerRole", - EdgeLabel: "entity_PractitionerRole", - ToType: "GroupMember", + "MedicationRequest|supportingInformation_MedicationStatement|MedicationStatement": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_MedicationStatement", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "PractitionerRole/*", + "MedicationStatement/*", }, }, - "GroupMember|entity_Specimen|Specimen": { - FromType: "GroupMember", - EdgeLabel: "entity_Specimen", - ToType: "Specimen", + "MedicationStatement|supportingInformation_MedicationStatement|MedicationRequest": { + FromType: "MedicationStatement", + EdgeLabel: "supportingInformation_MedicationStatement", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Specimen/*", + "MedicationStatement/*", }, }, - "Specimen|entity_Specimen|GroupMember": { - FromType: "Specimen", - EdgeLabel: "entity_Specimen", - ToType: "GroupMember", + "MedicationRequest|supportingInformation_MedicationRequest|MedicationRequest": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_MedicationRequest", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "group_member", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Specimen/*", + "MedicationRequest/*", }, }, - "Identifier|assigner|Organization": { - FromType: "Identifier", - EdgeLabel: "assigner", - ToType: "Organization", + "MedicationRequest|supportingInformation_Procedure|Procedure": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "identifier", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Organization/*", + "Procedure/*", }, }, - "Organization|assigner|Identifier": { - FromType: "Organization", - EdgeLabel: "assigner", - ToType: "Identifier", + "Procedure|supportingInformation_Procedure|MedicationRequest": { + FromType: "Procedure", + EdgeLabel: "supportingInformation_Procedure", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "identifier", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Organization/*", + "Procedure/*", }, }, - "ImagingStudy|basedOn_Task|Task": { - FromType: "ImagingStudy", - EdgeLabel: "basedOn_Task", - ToType: "Task", + "MedicationRequest|supportingInformation_DocumentReference|DocumentReference": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -26465,16 +26250,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "basedOn_imaging_study", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Task/*", + "DocumentReference/*", }, }, - "Task|basedOn_Task|ImagingStudy": { - FromType: "Task", - EdgeLabel: "basedOn_Task", - ToType: "ImagingStudy", + "DocumentReference|supportingInformation_DocumentReference|MedicationRequest": { + FromType: "DocumentReference", + EdgeLabel: "supportingInformation_DocumentReference", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -26482,16 +26267,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "basedOn_imaging_study", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Task/*", + "DocumentReference/*", }, }, - "ImagingStudy|partOf|Procedure": { - FromType: "ImagingStudy", - EdgeLabel: "partOf", - ToType: "Procedure", + "MedicationRequest|supportingInformation_Task|Task": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_Task", + ToType: "Task", Direction: []string{ "outbound", }, @@ -26499,16 +26284,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "partOf_imaging_study", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Procedure/*", + "Task/*", }, }, - "Procedure|partOf|ImagingStudy": { - FromType: "Procedure", - EdgeLabel: "partOf", - ToType: "ImagingStudy", + "Task|supportingInformation_Task|MedicationRequest": { + FromType: "Task", + EdgeLabel: "supportingInformation_Task", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -26516,287 +26301,117 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "partOf_imaging_study", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "ImagingStudy|referrer_Practitioner|Practitioner": { - FromType: "ImagingStudy", - EdgeLabel: "referrer_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "imaging_study", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|referrer_Practitioner|ImagingStudy": { - FromType: "Practitioner", - EdgeLabel: "referrer_Practitioner", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "imaging_study", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "ImagingStudy|referrer_PractitionerRole|PractitionerRole": { - FromType: "ImagingStudy", - EdgeLabel: "referrer_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "imaging_study", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|referrer_PractitionerRole|ImagingStudy": { - FromType: "PractitionerRole", - EdgeLabel: "referrer_PractitionerRole", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "imaging_study", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "ImagingStudy|subject_Patient|Patient": { - FromType: "ImagingStudy", - EdgeLabel: "subject_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "imaging_study", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|subject_Patient|ImagingStudy": { - FromType: "Patient", - EdgeLabel: "subject_Patient", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "imaging_study", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "ImagingStudy|subject_Group|Group": { - FromType: "ImagingStudy", - EdgeLabel: "subject_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "imaging_study", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|subject_Group|ImagingStudy": { - FromType: "Group", - EdgeLabel: "subject_Group", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "imaging_study", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "ImagingStudy|note_authorReference_Practitioner|Practitioner": { - FromType: "ImagingStudy", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Practitioner/*", + "Task/*", }, }, - "Practitioner|note_authorReference_Practitioner|ImagingStudy": { - FromType: "Practitioner", - EdgeLabel: "note_authorReference_Practitioner", + "MedicationRequest|supportingInformation_ImagingStudy|ImagingStudy": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "annotation", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Practitioner/*", + "ImagingStudy/*", }, }, - "ImagingStudy|note_authorReference_PractitionerRole|PractitionerRole": { + "ImagingStudy|supportingInformation_ImagingStudy|MedicationRequest": { FromType: "ImagingStudy", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|note_authorReference_PractitionerRole|ImagingStudy": { - FromType: "PractitionerRole", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "ImagingStudy", + EdgeLabel: "supportingInformation_ImagingStudy", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "annotation", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "PractitionerRole/*", + "ImagingStudy/*", }, }, - "ImagingStudy|note_authorReference_Patient|Patient": { - FromType: "ImagingStudy", - EdgeLabel: "note_authorReference_Patient", - ToType: "Patient", + "MedicationRequest|supportingInformation_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_FamilyMemberHistory", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "annotation", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Patient/*", + "FamilyMemberHistory/*", }, }, - "Patient|note_authorReference_Patient|ImagingStudy": { - FromType: "Patient", - EdgeLabel: "note_authorReference_Patient", - ToType: "ImagingStudy", + "FamilyMemberHistory|supportingInformation_FamilyMemberHistory|MedicationRequest": { + FromType: "FamilyMemberHistory", + EdgeLabel: "supportingInformation_FamilyMemberHistory", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "annotation", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Patient/*", + "FamilyMemberHistory/*", }, }, - "ImagingStudy|note_authorReference_Organization|Organization": { - FromType: "ImagingStudy", - EdgeLabel: "note_authorReference_Organization", - ToType: "Organization", + "MedicationRequest|supportingInformation_BodyStructure|BodyStructure": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInformation_BodyStructure", + ToType: "BodyStructure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "annotation", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Organization/*", + "BodyStructure/*", }, }, - "Organization|note_authorReference_Organization|ImagingStudy": { - FromType: "Organization", - EdgeLabel: "note_authorReference_Organization", - ToType: "ImagingStudy", + "BodyStructure|supportingInformation_BodyStructure|MedicationRequest": { + FromType: "BodyStructure", + EdgeLabel: "supportingInformation_BodyStructure", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "annotation", + "supportingInformation_medication_request", }, RegexMatch: []string{ - "Organization/*", + "BodyStructure/*", }, }, - "ImagingStudy|procedure_reference_Organization|Organization": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_Organization", + "MedicationRequest|device_reference_Organization|Organization": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_Organization", ToType: "Organization", Direction: []string{ "outbound", @@ -26811,10 +26426,10 @@ var Traversals = map[string]Traversal{ "Organization/*", }, }, - "Organization|procedure_reference_Organization|ImagingStudy": { + "Organization|device_reference_Organization|MedicationRequest": { FromType: "Organization", - EdgeLabel: "procedure_reference_Organization", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_Organization", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -26828,9 +26443,9 @@ var Traversals = map[string]Traversal{ "Organization/*", }, }, - "ImagingStudy|procedure_reference_Group|Group": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_Group", + "MedicationRequest|device_reference_Group|Group": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_Group", ToType: "Group", Direction: []string{ "outbound", @@ -26845,10 +26460,10 @@ var Traversals = map[string]Traversal{ "Group/*", }, }, - "Group|procedure_reference_Group|ImagingStudy": { + "Group|device_reference_Group|MedicationRequest": { FromType: "Group", - EdgeLabel: "procedure_reference_Group", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_Group", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -26862,9 +26477,9 @@ var Traversals = map[string]Traversal{ "Group/*", }, }, - "ImagingStudy|procedure_reference_Practitioner|Practitioner": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_Practitioner", + "MedicationRequest|device_reference_Practitioner|Practitioner": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", @@ -26879,10 +26494,10 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "Practitioner|procedure_reference_Practitioner|ImagingStudy": { + "Practitioner|device_reference_Practitioner|MedicationRequest": { FromType: "Practitioner", - EdgeLabel: "procedure_reference_Practitioner", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_Practitioner", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -26896,9 +26511,9 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "ImagingStudy|procedure_reference_PractitionerRole|PractitionerRole": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_PractitionerRole", + "MedicationRequest|device_reference_PractitionerRole|PractitionerRole": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", @@ -26913,10 +26528,10 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "PractitionerRole|procedure_reference_PractitionerRole|ImagingStudy": { + "PractitionerRole|device_reference_PractitionerRole|MedicationRequest": { FromType: "PractitionerRole", - EdgeLabel: "procedure_reference_PractitionerRole", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_PractitionerRole", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -26930,9 +26545,9 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "ImagingStudy|procedure_reference_ResearchStudy|ResearchStudy": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_ResearchStudy", + "MedicationRequest|device_reference_ResearchStudy|ResearchStudy": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -26947,10 +26562,10 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "ResearchStudy|procedure_reference_ResearchStudy|ImagingStudy": { + "ResearchStudy|device_reference_ResearchStudy|MedicationRequest": { FromType: "ResearchStudy", - EdgeLabel: "procedure_reference_ResearchStudy", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_ResearchStudy", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -26964,9 +26579,9 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "ImagingStudy|procedure_reference_Patient|Patient": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_Patient", + "MedicationRequest|device_reference_Patient|Patient": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -26981,10 +26596,10 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "Patient|procedure_reference_Patient|ImagingStudy": { + "Patient|device_reference_Patient|MedicationRequest": { FromType: "Patient", - EdgeLabel: "procedure_reference_Patient", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_Patient", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -26998,9 +26613,9 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "ImagingStudy|procedure_reference_ResearchSubject|ResearchSubject": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_ResearchSubject", + "MedicationRequest|device_reference_ResearchSubject|ResearchSubject": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -27015,10 +26630,10 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "ResearchSubject|procedure_reference_ResearchSubject|ImagingStudy": { + "ResearchSubject|device_reference_ResearchSubject|MedicationRequest": { FromType: "ResearchSubject", - EdgeLabel: "procedure_reference_ResearchSubject", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_ResearchSubject", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27032,9 +26647,9 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "ImagingStudy|procedure_reference_Substance|Substance": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_Substance", + "MedicationRequest|device_reference_Substance|Substance": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -27049,10 +26664,10 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "Substance|procedure_reference_Substance|ImagingStudy": { + "Substance|device_reference_Substance|MedicationRequest": { FromType: "Substance", - EdgeLabel: "procedure_reference_Substance", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_Substance", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27066,9 +26681,9 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "ImagingStudy|procedure_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_SubstanceDefinition", + "MedicationRequest|device_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -27083,10 +26698,10 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|procedure_reference_SubstanceDefinition|ImagingStudy": { + "SubstanceDefinition|device_reference_SubstanceDefinition|MedicationRequest": { FromType: "SubstanceDefinition", - EdgeLabel: "procedure_reference_SubstanceDefinition", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_SubstanceDefinition", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27100,9 +26715,9 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "ImagingStudy|procedure_reference_Specimen|Specimen": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_Specimen", + "MedicationRequest|device_reference_Specimen|Specimen": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -27117,10 +26732,10 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "Specimen|procedure_reference_Specimen|ImagingStudy": { + "Specimen|device_reference_Specimen|MedicationRequest": { FromType: "Specimen", - EdgeLabel: "procedure_reference_Specimen", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_Specimen", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27134,9 +26749,9 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "ImagingStudy|procedure_reference_Observation|Observation": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_Observation", + "MedicationRequest|device_reference_Observation|Observation": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -27151,10 +26766,10 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "Observation|procedure_reference_Observation|ImagingStudy": { + "Observation|device_reference_Observation|MedicationRequest": { FromType: "Observation", - EdgeLabel: "procedure_reference_Observation", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_Observation", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27168,9 +26783,9 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "ImagingStudy|procedure_reference_DiagnosticReport|DiagnosticReport": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_DiagnosticReport", + "MedicationRequest|device_reference_DiagnosticReport|DiagnosticReport": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -27185,10 +26800,10 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "DiagnosticReport|procedure_reference_DiagnosticReport|ImagingStudy": { + "DiagnosticReport|device_reference_DiagnosticReport|MedicationRequest": { FromType: "DiagnosticReport", - EdgeLabel: "procedure_reference_DiagnosticReport", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_DiagnosticReport", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27202,9 +26817,9 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "ImagingStudy|procedure_reference_Condition|Condition": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_Condition", + "MedicationRequest|device_reference_Condition|Condition": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -27219,10 +26834,10 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "Condition|procedure_reference_Condition|ImagingStudy": { + "Condition|device_reference_Condition|MedicationRequest": { FromType: "Condition", - EdgeLabel: "procedure_reference_Condition", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_Condition", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27236,9 +26851,9 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "ImagingStudy|procedure_reference_Medication|Medication": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_Medication", + "MedicationRequest|device_reference_Medication|Medication": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -27253,10 +26868,10 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "Medication|procedure_reference_Medication|ImagingStudy": { + "Medication|device_reference_Medication|MedicationRequest": { FromType: "Medication", - EdgeLabel: "procedure_reference_Medication", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_Medication", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27270,9 +26885,9 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "ImagingStudy|procedure_reference_MedicationAdministration|MedicationAdministration": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_MedicationAdministration", + "MedicationRequest|device_reference_MedicationAdministration|MedicationAdministration": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -27287,10 +26902,10 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "MedicationAdministration|procedure_reference_MedicationAdministration|ImagingStudy": { + "MedicationAdministration|device_reference_MedicationAdministration|MedicationRequest": { FromType: "MedicationAdministration", - EdgeLabel: "procedure_reference_MedicationAdministration", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_MedicationAdministration", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27304,9 +26919,9 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "ImagingStudy|procedure_reference_MedicationStatement|MedicationStatement": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_MedicationStatement", + "MedicationRequest|device_reference_MedicationStatement|MedicationStatement": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -27321,10 +26936,10 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "MedicationStatement|procedure_reference_MedicationStatement|ImagingStudy": { + "MedicationStatement|device_reference_MedicationStatement|MedicationRequest": { FromType: "MedicationStatement", - EdgeLabel: "procedure_reference_MedicationStatement", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_MedicationStatement", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27338,9 +26953,9 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "ImagingStudy|procedure_reference_MedicationRequest|MedicationRequest": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_MedicationRequest", + "MedicationRequest|device_reference_MedicationRequest|MedicationRequest": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -27355,26 +26970,9 @@ var Traversals = map[string]Traversal{ "MedicationRequest/*", }, }, - "MedicationRequest|procedure_reference_MedicationRequest|ImagingStudy": { + "MedicationRequest|device_reference_Procedure|Procedure": { FromType: "MedicationRequest", - EdgeLabel: "procedure_reference_MedicationRequest", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "ImagingStudy|procedure_reference_Procedure|Procedure": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_Procedure", + EdgeLabel: "device_reference_Procedure", ToType: "Procedure", Direction: []string{ "outbound", @@ -27389,10 +26987,10 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "Procedure|procedure_reference_Procedure|ImagingStudy": { + "Procedure|device_reference_Procedure|MedicationRequest": { FromType: "Procedure", - EdgeLabel: "procedure_reference_Procedure", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_Procedure", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27406,9 +27004,9 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "ImagingStudy|procedure_reference_DocumentReference|DocumentReference": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_DocumentReference", + "MedicationRequest|device_reference_DocumentReference|DocumentReference": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_DocumentReference", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -27423,10 +27021,10 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "DocumentReference|procedure_reference_DocumentReference|ImagingStudy": { + "DocumentReference|device_reference_DocumentReference|MedicationRequest": { FromType: "DocumentReference", - EdgeLabel: "procedure_reference_DocumentReference", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_DocumentReference", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27440,9 +27038,9 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "ImagingStudy|procedure_reference_Task|Task": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_Task", + "MedicationRequest|device_reference_Task|Task": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_Task", ToType: "Task", Direction: []string{ "outbound", @@ -27457,10 +27055,10 @@ var Traversals = map[string]Traversal{ "Task/*", }, }, - "Task|procedure_reference_Task|ImagingStudy": { + "Task|device_reference_Task|MedicationRequest": { FromType: "Task", - EdgeLabel: "procedure_reference_Task", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_Task", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27474,9 +27072,9 @@ var Traversals = map[string]Traversal{ "Task/*", }, }, - "ImagingStudy|procedure_reference_ImagingStudy|ImagingStudy": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_ImagingStudy", + "MedicationRequest|device_reference_ImagingStudy|ImagingStudy": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", @@ -27491,9 +27089,26 @@ var Traversals = map[string]Traversal{ "ImagingStudy/*", }, }, - "ImagingStudy|procedure_reference_FamilyMemberHistory|FamilyMemberHistory": { + "ImagingStudy|device_reference_ImagingStudy|MedicationRequest": { FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_FamilyMemberHistory", + EdgeLabel: "device_reference_ImagingStudy", + ToType: "MedicationRequest", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "ImagingStudy/*", + }, + }, + "MedicationRequest|device_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -27508,10 +27123,10 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|procedure_reference_FamilyMemberHistory|ImagingStudy": { + "FamilyMemberHistory|device_reference_FamilyMemberHistory|MedicationRequest": { FromType: "FamilyMemberHistory", - EdgeLabel: "procedure_reference_FamilyMemberHistory", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_FamilyMemberHistory", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27525,9 +27140,9 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "ImagingStudy|procedure_reference_BodyStructure|BodyStructure": { - FromType: "ImagingStudy", - EdgeLabel: "procedure_reference_BodyStructure", + "MedicationRequest|device_reference_BodyStructure|BodyStructure": { + FromType: "MedicationRequest", + EdgeLabel: "device_reference_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", @@ -27542,10 +27157,10 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "BodyStructure|procedure_reference_BodyStructure|ImagingStudy": { + "BodyStructure|device_reference_BodyStructure|MedicationRequest": { FromType: "BodyStructure", - EdgeLabel: "procedure_reference_BodyStructure", - ToType: "ImagingStudy", + EdgeLabel: "device_reference_BodyStructure", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27559,9 +27174,43 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "ImagingStudy|reason_reference_Organization|Organization": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_Organization", + "MedicationRequest|dispenseRequest_dispenser|Organization": { + FromType: "MedicationRequest", + EdgeLabel: "dispenseRequest_dispenser", + ToType: "Organization", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "medication_request_dispense_request", + }, + RegexMatch: []string{ + "Organization/*", + }, + }, + "Organization|dispenseRequest_dispenser|MedicationRequest": { + FromType: "Organization", + EdgeLabel: "dispenseRequest_dispenser", + ToType: "MedicationRequest", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "medication_request_dispense_request", + }, + RegexMatch: []string{ + "Organization/*", + }, + }, + "MedicationRequest|medication_reference_Organization|Organization": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_Organization", ToType: "Organization", Direction: []string{ "outbound", @@ -27576,10 +27225,10 @@ var Traversals = map[string]Traversal{ "Organization/*", }, }, - "Organization|reason_reference_Organization|ImagingStudy": { + "Organization|medication_reference_Organization|MedicationRequest": { FromType: "Organization", - EdgeLabel: "reason_reference_Organization", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_Organization", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27593,9 +27242,9 @@ var Traversals = map[string]Traversal{ "Organization/*", }, }, - "ImagingStudy|reason_reference_Group|Group": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_Group", + "MedicationRequest|medication_reference_Group|Group": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_Group", ToType: "Group", Direction: []string{ "outbound", @@ -27610,10 +27259,10 @@ var Traversals = map[string]Traversal{ "Group/*", }, }, - "Group|reason_reference_Group|ImagingStudy": { + "Group|medication_reference_Group|MedicationRequest": { FromType: "Group", - EdgeLabel: "reason_reference_Group", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_Group", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27627,9 +27276,9 @@ var Traversals = map[string]Traversal{ "Group/*", }, }, - "ImagingStudy|reason_reference_Practitioner|Practitioner": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_Practitioner", + "MedicationRequest|medication_reference_Practitioner|Practitioner": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", @@ -27644,10 +27293,10 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "Practitioner|reason_reference_Practitioner|ImagingStudy": { + "Practitioner|medication_reference_Practitioner|MedicationRequest": { FromType: "Practitioner", - EdgeLabel: "reason_reference_Practitioner", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_Practitioner", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27661,9 +27310,9 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "ImagingStudy|reason_reference_PractitionerRole|PractitionerRole": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_PractitionerRole", + "MedicationRequest|medication_reference_PractitionerRole|PractitionerRole": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", @@ -27678,10 +27327,10 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "PractitionerRole|reason_reference_PractitionerRole|ImagingStudy": { + "PractitionerRole|medication_reference_PractitionerRole|MedicationRequest": { FromType: "PractitionerRole", - EdgeLabel: "reason_reference_PractitionerRole", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_PractitionerRole", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27695,9 +27344,9 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "ImagingStudy|reason_reference_ResearchStudy|ResearchStudy": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_ResearchStudy", + "MedicationRequest|medication_reference_ResearchStudy|ResearchStudy": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -27712,10 +27361,10 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "ResearchStudy|reason_reference_ResearchStudy|ImagingStudy": { + "ResearchStudy|medication_reference_ResearchStudy|MedicationRequest": { FromType: "ResearchStudy", - EdgeLabel: "reason_reference_ResearchStudy", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_ResearchStudy", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27729,9 +27378,9 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "ImagingStudy|reason_reference_Patient|Patient": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_Patient", + "MedicationRequest|medication_reference_Patient|Patient": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -27746,10 +27395,10 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "Patient|reason_reference_Patient|ImagingStudy": { + "Patient|medication_reference_Patient|MedicationRequest": { FromType: "Patient", - EdgeLabel: "reason_reference_Patient", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_Patient", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27763,9 +27412,9 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "ImagingStudy|reason_reference_ResearchSubject|ResearchSubject": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_ResearchSubject", + "MedicationRequest|medication_reference_ResearchSubject|ResearchSubject": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -27780,10 +27429,10 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "ResearchSubject|reason_reference_ResearchSubject|ImagingStudy": { + "ResearchSubject|medication_reference_ResearchSubject|MedicationRequest": { FromType: "ResearchSubject", - EdgeLabel: "reason_reference_ResearchSubject", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_ResearchSubject", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27797,9 +27446,9 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "ImagingStudy|reason_reference_Substance|Substance": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_Substance", + "MedicationRequest|medication_reference_Substance|Substance": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -27814,10 +27463,10 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "Substance|reason_reference_Substance|ImagingStudy": { + "Substance|medication_reference_Substance|MedicationRequest": { FromType: "Substance", - EdgeLabel: "reason_reference_Substance", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_Substance", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27831,9 +27480,9 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "ImagingStudy|reason_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_SubstanceDefinition", + "MedicationRequest|medication_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -27848,10 +27497,10 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|reason_reference_SubstanceDefinition|ImagingStudy": { + "SubstanceDefinition|medication_reference_SubstanceDefinition|MedicationRequest": { FromType: "SubstanceDefinition", - EdgeLabel: "reason_reference_SubstanceDefinition", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_SubstanceDefinition", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27865,9 +27514,9 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "ImagingStudy|reason_reference_Specimen|Specimen": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_Specimen", + "MedicationRequest|medication_reference_Specimen|Specimen": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -27882,10 +27531,10 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "Specimen|reason_reference_Specimen|ImagingStudy": { + "Specimen|medication_reference_Specimen|MedicationRequest": { FromType: "Specimen", - EdgeLabel: "reason_reference_Specimen", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_Specimen", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27899,9 +27548,9 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "ImagingStudy|reason_reference_Observation|Observation": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_Observation", + "MedicationRequest|medication_reference_Observation|Observation": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -27916,10 +27565,10 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "Observation|reason_reference_Observation|ImagingStudy": { + "Observation|medication_reference_Observation|MedicationRequest": { FromType: "Observation", - EdgeLabel: "reason_reference_Observation", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_Observation", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27933,9 +27582,9 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "ImagingStudy|reason_reference_DiagnosticReport|DiagnosticReport": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_DiagnosticReport", + "MedicationRequest|medication_reference_DiagnosticReport|DiagnosticReport": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -27950,10 +27599,10 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "DiagnosticReport|reason_reference_DiagnosticReport|ImagingStudy": { + "DiagnosticReport|medication_reference_DiagnosticReport|MedicationRequest": { FromType: "DiagnosticReport", - EdgeLabel: "reason_reference_DiagnosticReport", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_DiagnosticReport", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -27967,9 +27616,9 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "ImagingStudy|reason_reference_Condition|Condition": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_Condition", + "MedicationRequest|medication_reference_Condition|Condition": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -27984,10 +27633,10 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "Condition|reason_reference_Condition|ImagingStudy": { + "Condition|medication_reference_Condition|MedicationRequest": { FromType: "Condition", - EdgeLabel: "reason_reference_Condition", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_Condition", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28001,9 +27650,9 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "ImagingStudy|reason_reference_Medication|Medication": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_Medication", + "MedicationRequest|medication_reference_Medication|Medication": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -28018,10 +27667,10 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "Medication|reason_reference_Medication|ImagingStudy": { + "Medication|medication_reference_Medication|MedicationRequest": { FromType: "Medication", - EdgeLabel: "reason_reference_Medication", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_Medication", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28035,9 +27684,9 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "ImagingStudy|reason_reference_MedicationAdministration|MedicationAdministration": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_MedicationAdministration", + "MedicationRequest|medication_reference_MedicationAdministration|MedicationAdministration": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -28052,10 +27701,10 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "MedicationAdministration|reason_reference_MedicationAdministration|ImagingStudy": { + "MedicationAdministration|medication_reference_MedicationAdministration|MedicationRequest": { FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_MedicationAdministration", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_MedicationAdministration", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28069,9 +27718,9 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "ImagingStudy|reason_reference_MedicationStatement|MedicationStatement": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_MedicationStatement", + "MedicationRequest|medication_reference_MedicationStatement|MedicationStatement": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -28086,10 +27735,10 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "MedicationStatement|reason_reference_MedicationStatement|ImagingStudy": { + "MedicationStatement|medication_reference_MedicationStatement|MedicationRequest": { FromType: "MedicationStatement", - EdgeLabel: "reason_reference_MedicationStatement", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_MedicationStatement", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28103,9 +27752,9 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "ImagingStudy|reason_reference_MedicationRequest|MedicationRequest": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_MedicationRequest", + "MedicationRequest|medication_reference_MedicationRequest|MedicationRequest": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -28120,10 +27769,10 @@ var Traversals = map[string]Traversal{ "MedicationRequest/*", }, }, - "MedicationRequest|reason_reference_MedicationRequest|ImagingStudy": { + "MedicationRequest|medication_reference_Procedure|Procedure": { FromType: "MedicationRequest", - EdgeLabel: "reason_reference_MedicationRequest", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -28134,13 +27783,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "MedicationRequest/*", + "Procedure/*", }, }, - "ImagingStudy|reason_reference_Procedure|Procedure": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_Procedure", - ToType: "Procedure", + "Procedure|medication_reference_Procedure|MedicationRequest": { + FromType: "Procedure", + EdgeLabel: "medication_reference_Procedure", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28154,10 +27803,10 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "Procedure|reason_reference_Procedure|ImagingStudy": { - FromType: "Procedure", - EdgeLabel: "reason_reference_Procedure", - ToType: "ImagingStudy", + "MedicationRequest|medication_reference_DocumentReference|DocumentReference": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -28168,13 +27817,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Procedure/*", + "DocumentReference/*", }, }, - "ImagingStudy|reason_reference_DocumentReference|DocumentReference": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_DocumentReference", - ToType: "DocumentReference", + "DocumentReference|medication_reference_DocumentReference|MedicationRequest": { + FromType: "DocumentReference", + EdgeLabel: "medication_reference_DocumentReference", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28188,10 +27837,10 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "DocumentReference|reason_reference_DocumentReference|ImagingStudy": { - FromType: "DocumentReference", - EdgeLabel: "reason_reference_DocumentReference", - ToType: "ImagingStudy", + "MedicationRequest|medication_reference_Task|Task": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_Task", + ToType: "Task", Direction: []string{ "outbound", }, @@ -28202,13 +27851,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "DocumentReference/*", + "Task/*", }, }, - "ImagingStudy|reason_reference_Task|Task": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_Task", - ToType: "Task", + "Task|medication_reference_Task|MedicationRequest": { + FromType: "Task", + EdgeLabel: "medication_reference_Task", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28222,9 +27871,9 @@ var Traversals = map[string]Traversal{ "Task/*", }, }, - "Task|reason_reference_Task|ImagingStudy": { - FromType: "Task", - EdgeLabel: "reason_reference_Task", + "MedicationRequest|medication_reference_ImagingStudy|ImagingStudy": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", @@ -28236,13 +27885,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Task/*", + "ImagingStudy/*", }, }, - "ImagingStudy|reason_reference_ImagingStudy|ImagingStudy": { + "ImagingStudy|medication_reference_ImagingStudy|MedicationRequest": { FromType: "ImagingStudy", - EdgeLabel: "reason_reference_ImagingStudy", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_ImagingStudy", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28256,9 +27905,9 @@ var Traversals = map[string]Traversal{ "ImagingStudy/*", }, }, - "ImagingStudy|reason_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_FamilyMemberHistory", + "MedicationRequest|medication_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -28273,10 +27922,10 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|reason_reference_FamilyMemberHistory|ImagingStudy": { + "FamilyMemberHistory|medication_reference_FamilyMemberHistory|MedicationRequest": { FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_FamilyMemberHistory", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_FamilyMemberHistory", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28290,9 +27939,9 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "ImagingStudy|reason_reference_BodyStructure|BodyStructure": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_BodyStructure", + "MedicationRequest|medication_reference_BodyStructure|BodyStructure": { + FromType: "MedicationRequest", + EdgeLabel: "medication_reference_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", @@ -28307,10 +27956,10 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "BodyStructure|reason_reference_BodyStructure|ImagingStudy": { + "BodyStructure|medication_reference_BodyStructure|MedicationRequest": { FromType: "BodyStructure", - EdgeLabel: "reason_reference_BodyStructure", - ToType: "ImagingStudy", + EdgeLabel: "medication_reference_BodyStructure", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28324,78 +27973,78 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "ImagingStudy|series_specimen|Specimen": { - FromType: "ImagingStudy", - EdgeLabel: "series_specimen", - ToType: "Specimen", + "MedicationRequest|note_authorReference_Practitioner|Practitioner": { + FromType: "MedicationRequest", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "specimen_imaging_study_series", + "annotation", }, RegexMatch: []string{ - "Specimen/*", + "Practitioner/*", }, }, - "Specimen|series_specimen|ImagingStudy": { - FromType: "Specimen", - EdgeLabel: "series_specimen", - ToType: "ImagingStudy", + "Practitioner|note_authorReference_Practitioner|MedicationRequest": { + FromType: "Practitioner", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "specimen_imaging_study_series", + "annotation", }, RegexMatch: []string{ - "Specimen/*", + "Practitioner/*", }, }, - "ImagingStudySeries|specimen|Specimen": { - FromType: "ImagingStudySeries", - EdgeLabel: "specimen", - ToType: "Specimen", + "MedicationRequest|note_authorReference_PractitionerRole|PractitionerRole": { + FromType: "MedicationRequest", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "specimen_imaging_study_series", + "annotation", }, RegexMatch: []string{ - "Specimen/*", + "PractitionerRole/*", }, }, - "Specimen|specimen|ImagingStudySeries": { - FromType: "Specimen", - EdgeLabel: "specimen", - ToType: "ImagingStudySeries", + "PractitionerRole|note_authorReference_PractitionerRole|MedicationRequest": { + FromType: "PractitionerRole", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "specimen_imaging_study_series", + "annotation", }, RegexMatch: []string{ - "Specimen/*", + "PractitionerRole/*", }, }, - "ImagingStudySeries|bodySite_reference_Organization|Organization": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_Organization", - ToType: "Organization", + "MedicationRequest|note_authorReference_Patient|Patient": { + FromType: "MedicationRequest", + EdgeLabel: "note_authorReference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -28403,16 +28052,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Organization/*", + "Patient/*", }, }, - "Organization|bodySite_reference_Organization|ImagingStudySeries": { - FromType: "Organization", - EdgeLabel: "bodySite_reference_Organization", - ToType: "ImagingStudySeries", + "Patient|note_authorReference_Patient|MedicationRequest": { + FromType: "Patient", + EdgeLabel: "note_authorReference_Patient", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28420,16 +28069,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Organization/*", + "Patient/*", }, }, - "ImagingStudySeries|bodySite_reference_Group|Group": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_Group", - ToType: "Group", + "MedicationRequest|note_authorReference_Organization|Organization": { + FromType: "MedicationRequest", + EdgeLabel: "note_authorReference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -28437,16 +28086,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Group/*", + "Organization/*", }, }, - "Group|bodySite_reference_Group|ImagingStudySeries": { - FromType: "Group", - EdgeLabel: "bodySite_reference_Group", - ToType: "ImagingStudySeries", + "Organization|note_authorReference_Organization|MedicationRequest": { + FromType: "Organization", + EdgeLabel: "note_authorReference_Organization", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28454,16 +28103,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Group/*", + "Organization/*", }, }, - "ImagingStudySeries|bodySite_reference_Practitioner|Practitioner": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_Practitioner", - ToType: "Practitioner", + "MedicationRequest|reason_reference_Organization|Organization": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -28474,13 +28123,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Organization/*", }, }, - "Practitioner|bodySite_reference_Practitioner|ImagingStudySeries": { - FromType: "Practitioner", - EdgeLabel: "bodySite_reference_Practitioner", - ToType: "ImagingStudySeries", + "Organization|reason_reference_Organization|MedicationRequest": { + FromType: "Organization", + EdgeLabel: "reason_reference_Organization", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28491,13 +28140,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Organization/*", }, }, - "ImagingStudySeries|bodySite_reference_PractitionerRole|PractitionerRole": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_PractitionerRole", - ToType: "PractitionerRole", + "MedicationRequest|reason_reference_Group|Group": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -28508,13 +28157,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Group/*", }, }, - "PractitionerRole|bodySite_reference_PractitionerRole|ImagingStudySeries": { - FromType: "PractitionerRole", - EdgeLabel: "bodySite_reference_PractitionerRole", - ToType: "ImagingStudySeries", + "Group|reason_reference_Group|MedicationRequest": { + FromType: "Group", + EdgeLabel: "reason_reference_Group", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28525,13 +28174,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Group/*", }, }, - "ImagingStudySeries|bodySite_reference_ResearchStudy|ResearchStudy": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_ResearchStudy", - ToType: "ResearchStudy", + "MedicationRequest|reason_reference_Practitioner|Practitioner": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -28542,13 +28191,64 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "ResearchStudy/*", + "Practitioner/*", }, }, - "ResearchStudy|bodySite_reference_ResearchStudy|ImagingStudySeries": { - FromType: "ResearchStudy", - EdgeLabel: "bodySite_reference_ResearchStudy", - ToType: "ImagingStudySeries", + "Practitioner|reason_reference_Practitioner|MedicationRequest": { + FromType: "Practitioner", + EdgeLabel: "reason_reference_Practitioner", + ToType: "MedicationRequest", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "Practitioner/*", + }, + }, + "MedicationRequest|reason_reference_PractitionerRole|PractitionerRole": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_PractitionerRole", + ToType: "PractitionerRole", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "PractitionerRole/*", + }, + }, + "PractitionerRole|reason_reference_PractitionerRole|MedicationRequest": { + FromType: "PractitionerRole", + EdgeLabel: "reason_reference_PractitionerRole", + ToType: "MedicationRequest", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "PractitionerRole/*", + }, + }, + "MedicationRequest|reason_reference_ResearchStudy|ResearchStudy": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_ResearchStudy", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -28562,9 +28262,26 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "ImagingStudySeries|bodySite_reference_Patient|Patient": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_Patient", + "ResearchStudy|reason_reference_ResearchStudy|MedicationRequest": { + FromType: "ResearchStudy", + EdgeLabel: "reason_reference_ResearchStudy", + ToType: "MedicationRequest", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "ResearchStudy/*", + }, + }, + "MedicationRequest|reason_reference_Patient|Patient": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -28579,10 +28296,10 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "Patient|bodySite_reference_Patient|ImagingStudySeries": { + "Patient|reason_reference_Patient|MedicationRequest": { FromType: "Patient", - EdgeLabel: "bodySite_reference_Patient", - ToType: "ImagingStudySeries", + EdgeLabel: "reason_reference_Patient", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28596,9 +28313,9 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "ImagingStudySeries|bodySite_reference_ResearchSubject|ResearchSubject": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_ResearchSubject", + "MedicationRequest|reason_reference_ResearchSubject|ResearchSubject": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -28613,10 +28330,10 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "ResearchSubject|bodySite_reference_ResearchSubject|ImagingStudySeries": { + "ResearchSubject|reason_reference_ResearchSubject|MedicationRequest": { FromType: "ResearchSubject", - EdgeLabel: "bodySite_reference_ResearchSubject", - ToType: "ImagingStudySeries", + EdgeLabel: "reason_reference_ResearchSubject", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28630,9 +28347,9 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "ImagingStudySeries|bodySite_reference_Substance|Substance": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_Substance", + "MedicationRequest|reason_reference_Substance|Substance": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -28647,10 +28364,10 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "Substance|bodySite_reference_Substance|ImagingStudySeries": { + "Substance|reason_reference_Substance|MedicationRequest": { FromType: "Substance", - EdgeLabel: "bodySite_reference_Substance", - ToType: "ImagingStudySeries", + EdgeLabel: "reason_reference_Substance", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28664,9 +28381,9 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "ImagingStudySeries|bodySite_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_SubstanceDefinition", + "MedicationRequest|reason_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -28681,10 +28398,10 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|bodySite_reference_SubstanceDefinition|ImagingStudySeries": { + "SubstanceDefinition|reason_reference_SubstanceDefinition|MedicationRequest": { FromType: "SubstanceDefinition", - EdgeLabel: "bodySite_reference_SubstanceDefinition", - ToType: "ImagingStudySeries", + EdgeLabel: "reason_reference_SubstanceDefinition", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28698,9 +28415,9 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "ImagingStudySeries|bodySite_reference_Specimen|Specimen": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_Specimen", + "MedicationRequest|reason_reference_Specimen|Specimen": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -28715,10 +28432,10 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "Specimen|bodySite_reference_Specimen|ImagingStudySeries": { + "Specimen|reason_reference_Specimen|MedicationRequest": { FromType: "Specimen", - EdgeLabel: "bodySite_reference_Specimen", - ToType: "ImagingStudySeries", + EdgeLabel: "reason_reference_Specimen", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28732,9 +28449,9 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "ImagingStudySeries|bodySite_reference_Observation|Observation": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_Observation", + "MedicationRequest|reason_reference_Observation|Observation": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -28749,10 +28466,10 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "Observation|bodySite_reference_Observation|ImagingStudySeries": { + "Observation|reason_reference_Observation|MedicationRequest": { FromType: "Observation", - EdgeLabel: "bodySite_reference_Observation", - ToType: "ImagingStudySeries", + EdgeLabel: "reason_reference_Observation", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28766,9 +28483,9 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "ImagingStudySeries|bodySite_reference_DiagnosticReport|DiagnosticReport": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_DiagnosticReport", + "MedicationRequest|reason_reference_DiagnosticReport|DiagnosticReport": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -28783,10 +28500,10 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "DiagnosticReport|bodySite_reference_DiagnosticReport|ImagingStudySeries": { + "DiagnosticReport|reason_reference_DiagnosticReport|MedicationRequest": { FromType: "DiagnosticReport", - EdgeLabel: "bodySite_reference_DiagnosticReport", - ToType: "ImagingStudySeries", + EdgeLabel: "reason_reference_DiagnosticReport", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28800,9 +28517,9 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "ImagingStudySeries|bodySite_reference_Condition|Condition": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_Condition", + "MedicationRequest|reason_reference_Condition|Condition": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -28817,10 +28534,10 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "Condition|bodySite_reference_Condition|ImagingStudySeries": { + "Condition|reason_reference_Condition|MedicationRequest": { FromType: "Condition", - EdgeLabel: "bodySite_reference_Condition", - ToType: "ImagingStudySeries", + EdgeLabel: "reason_reference_Condition", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28834,9 +28551,9 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "ImagingStudySeries|bodySite_reference_Medication|Medication": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_Medication", + "MedicationRequest|reason_reference_Medication|Medication": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -28851,10 +28568,10 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "Medication|bodySite_reference_Medication|ImagingStudySeries": { + "Medication|reason_reference_Medication|MedicationRequest": { FromType: "Medication", - EdgeLabel: "bodySite_reference_Medication", - ToType: "ImagingStudySeries", + EdgeLabel: "reason_reference_Medication", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28868,9 +28585,9 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "ImagingStudySeries|bodySite_reference_MedicationAdministration|MedicationAdministration": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_MedicationAdministration", + "MedicationRequest|reason_reference_MedicationAdministration|MedicationAdministration": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -28885,10 +28602,10 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "MedicationAdministration|bodySite_reference_MedicationAdministration|ImagingStudySeries": { + "MedicationAdministration|reason_reference_MedicationAdministration|MedicationRequest": { FromType: "MedicationAdministration", - EdgeLabel: "bodySite_reference_MedicationAdministration", - ToType: "ImagingStudySeries", + EdgeLabel: "reason_reference_MedicationAdministration", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28902,9 +28619,9 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "ImagingStudySeries|bodySite_reference_MedicationStatement|MedicationStatement": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_MedicationStatement", + "MedicationRequest|reason_reference_MedicationStatement|MedicationStatement": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -28919,10 +28636,10 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "MedicationStatement|bodySite_reference_MedicationStatement|ImagingStudySeries": { + "MedicationStatement|reason_reference_MedicationStatement|MedicationRequest": { FromType: "MedicationStatement", - EdgeLabel: "bodySite_reference_MedicationStatement", - ToType: "ImagingStudySeries", + EdgeLabel: "reason_reference_MedicationStatement", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -28936,9 +28653,9 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "ImagingStudySeries|bodySite_reference_MedicationRequest|MedicationRequest": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_MedicationRequest", + "MedicationRequest|reason_reference_MedicationRequest|MedicationRequest": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -28953,26 +28670,9 @@ var Traversals = map[string]Traversal{ "MedicationRequest/*", }, }, - "MedicationRequest|bodySite_reference_MedicationRequest|ImagingStudySeries": { + "MedicationRequest|reason_reference_Procedure|Procedure": { FromType: "MedicationRequest", - EdgeLabel: "bodySite_reference_MedicationRequest", - ToType: "ImagingStudySeries", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "ImagingStudySeries|bodySite_reference_Procedure|Procedure": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_Procedure", + EdgeLabel: "reason_reference_Procedure", ToType: "Procedure", Direction: []string{ "outbound", @@ -28987,10 +28687,10 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "Procedure|bodySite_reference_Procedure|ImagingStudySeries": { + "Procedure|reason_reference_Procedure|MedicationRequest": { FromType: "Procedure", - EdgeLabel: "bodySite_reference_Procedure", - ToType: "ImagingStudySeries", + EdgeLabel: "reason_reference_Procedure", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -29004,9 +28704,9 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "ImagingStudySeries|bodySite_reference_DocumentReference|DocumentReference": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_DocumentReference", + "MedicationRequest|reason_reference_DocumentReference|DocumentReference": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_DocumentReference", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -29021,10 +28721,10 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "DocumentReference|bodySite_reference_DocumentReference|ImagingStudySeries": { + "DocumentReference|reason_reference_DocumentReference|MedicationRequest": { FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_DocumentReference", - ToType: "ImagingStudySeries", + EdgeLabel: "reason_reference_DocumentReference", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -29038,9 +28738,9 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "ImagingStudySeries|bodySite_reference_Task|Task": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_Task", + "MedicationRequest|reason_reference_Task|Task": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_Task", ToType: "Task", Direction: []string{ "outbound", @@ -29055,10 +28755,10 @@ var Traversals = map[string]Traversal{ "Task/*", }, }, - "Task|bodySite_reference_Task|ImagingStudySeries": { + "Task|reason_reference_Task|MedicationRequest": { FromType: "Task", - EdgeLabel: "bodySite_reference_Task", - ToType: "ImagingStudySeries", + EdgeLabel: "reason_reference_Task", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -29072,9 +28772,9 @@ var Traversals = map[string]Traversal{ "Task/*", }, }, - "ImagingStudySeries|bodySite_reference_ImagingStudy|ImagingStudy": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_ImagingStudy", + "MedicationRequest|reason_reference_ImagingStudy|ImagingStudy": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", @@ -29089,10 +28789,10 @@ var Traversals = map[string]Traversal{ "ImagingStudy/*", }, }, - "ImagingStudy|bodySite_reference_ImagingStudy|ImagingStudySeries": { + "ImagingStudy|reason_reference_ImagingStudy|MedicationRequest": { FromType: "ImagingStudy", - EdgeLabel: "bodySite_reference_ImagingStudy", - ToType: "ImagingStudySeries", + EdgeLabel: "reason_reference_ImagingStudy", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -29106,9 +28806,9 @@ var Traversals = map[string]Traversal{ "ImagingStudy/*", }, }, - "ImagingStudySeries|bodySite_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_FamilyMemberHistory", + "MedicationRequest|reason_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -29123,10 +28823,10 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|bodySite_reference_FamilyMemberHistory|ImagingStudySeries": { + "FamilyMemberHistory|reason_reference_FamilyMemberHistory|MedicationRequest": { FromType: "FamilyMemberHistory", - EdgeLabel: "bodySite_reference_FamilyMemberHistory", - ToType: "ImagingStudySeries", + EdgeLabel: "reason_reference_FamilyMemberHistory", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -29140,9 +28840,9 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "ImagingStudySeries|bodySite_reference_BodyStructure|BodyStructure": { - FromType: "ImagingStudySeries", - EdgeLabel: "bodySite_reference_BodyStructure", + "MedicationRequest|reason_reference_BodyStructure|BodyStructure": { + FromType: "MedicationRequest", + EdgeLabel: "reason_reference_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", @@ -29157,10 +28857,10 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "BodyStructure|bodySite_reference_BodyStructure|ImagingStudySeries": { + "BodyStructure|reason_reference_BodyStructure|MedicationRequest": { FromType: "BodyStructure", - EdgeLabel: "bodySite_reference_BodyStructure", - ToType: "ImagingStudySeries", + EdgeLabel: "reason_reference_BodyStructure", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -29174,316 +28874,316 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "ImagingStudySeries|performer_actor_Practitioner|Practitioner": { - FromType: "ImagingStudySeries", - EdgeLabel: "performer_actor_Practitioner", - ToType: "Practitioner", + "MedicationStatement|derivedFrom_Organization|Organization": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "imaging_study_series_performer", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Practitioner/*", + "Organization/*", }, }, - "Practitioner|performer_actor_Practitioner|ImagingStudySeries": { - FromType: "Practitioner", - EdgeLabel: "performer_actor_Practitioner", - ToType: "ImagingStudySeries", + "Organization|derivedFrom_Organization|MedicationStatement": { + FromType: "Organization", + EdgeLabel: "derivedFrom_Organization", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "imaging_study_series_performer", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Practitioner/*", + "Organization/*", }, }, - "ImagingStudySeries|performer_actor_PractitionerRole|PractitionerRole": { - FromType: "ImagingStudySeries", - EdgeLabel: "performer_actor_PractitionerRole", - ToType: "PractitionerRole", + "MedicationStatement|derivedFrom_Group|Group": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_Group", + ToType: "Group", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "imaging_study_series_performer", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "PractitionerRole/*", + "Group/*", }, }, - "PractitionerRole|performer_actor_PractitionerRole|ImagingStudySeries": { - FromType: "PractitionerRole", - EdgeLabel: "performer_actor_PractitionerRole", - ToType: "ImagingStudySeries", + "Group|derivedFrom_Group|MedicationStatement": { + FromType: "Group", + EdgeLabel: "derivedFrom_Group", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "imaging_study_series_performer", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "PractitionerRole/*", + "Group/*", }, }, - "ImagingStudySeries|performer_actor_Organization|Organization": { - FromType: "ImagingStudySeries", - EdgeLabel: "performer_actor_Organization", - ToType: "Organization", + "MedicationStatement|derivedFrom_Practitioner|Practitioner": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "imaging_study_series_performer", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Organization/*", + "Practitioner/*", }, }, - "Organization|performer_actor_Organization|ImagingStudySeries": { - FromType: "Organization", - EdgeLabel: "performer_actor_Organization", - ToType: "ImagingStudySeries", + "Practitioner|derivedFrom_Practitioner|MedicationStatement": { + FromType: "Practitioner", + EdgeLabel: "derivedFrom_Practitioner", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "imaging_study_series_performer", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Organization/*", + "Practitioner/*", }, }, - "ImagingStudySeries|performer_actor_Patient|Patient": { - FromType: "ImagingStudySeries", - EdgeLabel: "performer_actor_Patient", - ToType: "Patient", + "MedicationStatement|derivedFrom_PractitionerRole|PractitionerRole": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "imaging_study_series_performer", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Patient/*", + "PractitionerRole/*", }, }, - "Patient|performer_actor_Patient|ImagingStudySeries": { - FromType: "Patient", - EdgeLabel: "performer_actor_Patient", - ToType: "ImagingStudySeries", + "PractitionerRole|derivedFrom_PractitionerRole|MedicationStatement": { + FromType: "PractitionerRole", + EdgeLabel: "derivedFrom_PractitionerRole", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "imaging_study_series_performer", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Patient/*", + "PractitionerRole/*", }, }, - "ImagingStudySeriesPerformer|actor_Practitioner|Practitioner": { - FromType: "ImagingStudySeriesPerformer", - EdgeLabel: "actor_Practitioner", - ToType: "Practitioner", + "MedicationStatement|derivedFrom_ResearchStudy|ResearchStudy": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_ResearchStudy", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "imaging_study_series_performer", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Practitioner/*", + "ResearchStudy/*", }, }, - "Practitioner|actor_Practitioner|ImagingStudySeriesPerformer": { - FromType: "Practitioner", - EdgeLabel: "actor_Practitioner", - ToType: "ImagingStudySeriesPerformer", + "ResearchStudy|derivedFrom_ResearchStudy|MedicationStatement": { + FromType: "ResearchStudy", + EdgeLabel: "derivedFrom_ResearchStudy", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "imaging_study_series_performer", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Practitioner/*", + "ResearchStudy/*", }, }, - "ImagingStudySeriesPerformer|actor_PractitionerRole|PractitionerRole": { - FromType: "ImagingStudySeriesPerformer", - EdgeLabel: "actor_PractitionerRole", - ToType: "PractitionerRole", + "MedicationStatement|derivedFrom_Patient|Patient": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "imaging_study_series_performer", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "PractitionerRole/*", + "Patient/*", }, }, - "PractitionerRole|actor_PractitionerRole|ImagingStudySeriesPerformer": { - FromType: "PractitionerRole", - EdgeLabel: "actor_PractitionerRole", - ToType: "ImagingStudySeriesPerformer", + "Patient|derivedFrom_Patient|MedicationStatement": { + FromType: "Patient", + EdgeLabel: "derivedFrom_Patient", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "imaging_study_series_performer", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "PractitionerRole/*", + "Patient/*", }, }, - "ImagingStudySeriesPerformer|actor_Organization|Organization": { - FromType: "ImagingStudySeriesPerformer", - EdgeLabel: "actor_Organization", - ToType: "Organization", + "MedicationStatement|derivedFrom_ResearchSubject|ResearchSubject": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_ResearchSubject", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "imaging_study_series_performer", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Organization/*", + "ResearchSubject/*", }, }, - "Organization|actor_Organization|ImagingStudySeriesPerformer": { - FromType: "Organization", - EdgeLabel: "actor_Organization", - ToType: "ImagingStudySeriesPerformer", + "ResearchSubject|derivedFrom_ResearchSubject|MedicationStatement": { + FromType: "ResearchSubject", + EdgeLabel: "derivedFrom_ResearchSubject", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "imaging_study_series_performer", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Organization/*", + "ResearchSubject/*", }, }, - "ImagingStudySeriesPerformer|actor_Patient|Patient": { - FromType: "ImagingStudySeriesPerformer", - EdgeLabel: "actor_Patient", - ToType: "Patient", + "MedicationStatement|derivedFrom_Substance|Substance": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_Substance", + ToType: "Substance", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "imaging_study_series_performer", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Patient/*", + "Substance/*", }, }, - "Patient|actor_Patient|ImagingStudySeriesPerformer": { - FromType: "Patient", - EdgeLabel: "actor_Patient", - ToType: "ImagingStudySeriesPerformer", + "Substance|derivedFrom_Substance|MedicationStatement": { + FromType: "Substance", + EdgeLabel: "derivedFrom_Substance", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "imaging_study_series_performer", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Patient/*", + "Substance/*", }, }, - "Medication|marketingAuthorizationHolder|Organization": { - FromType: "Medication", - EdgeLabel: "marketingAuthorizationHolder", - ToType: "Organization", + "MedicationStatement|derivedFrom_SubstanceDefinition|SubstanceDefinition": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_SubstanceDefinition", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "medication", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Organization/*", + "SubstanceDefinition/*", }, }, - "Organization|marketingAuthorizationHolder|Medication": { - FromType: "Organization", - EdgeLabel: "marketingAuthorizationHolder", - ToType: "Medication", + "SubstanceDefinition|derivedFrom_SubstanceDefinition|MedicationStatement": { + FromType: "SubstanceDefinition", + EdgeLabel: "derivedFrom_SubstanceDefinition", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "medication", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Organization/*", + "SubstanceDefinition/*", }, }, - "MedicationAdministration|partOf_MedicationAdministration|MedicationAdministration": { - FromType: "MedicationAdministration", - EdgeLabel: "partOf_MedicationAdministration", - ToType: "MedicationAdministration", + "MedicationStatement|derivedFrom_Specimen|Specimen": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_Specimen", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -29491,16 +29191,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "partOf_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Specimen/*", }, }, - "MedicationAdministration|partOf_Procedure|Procedure": { - FromType: "MedicationAdministration", - EdgeLabel: "partOf_Procedure", - ToType: "Procedure", + "Specimen|derivedFrom_Specimen|MedicationStatement": { + FromType: "Specimen", + EdgeLabel: "derivedFrom_Specimen", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -29508,16 +29208,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "partOf_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Procedure/*", + "Specimen/*", }, }, - "Procedure|partOf_Procedure|MedicationAdministration": { - FromType: "Procedure", - EdgeLabel: "partOf_Procedure", - ToType: "MedicationAdministration", + "MedicationStatement|derivedFrom_Observation|Observation": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_Observation", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -29525,118 +29225,118 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "partOf_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Procedure/*", + "Observation/*", }, }, - "MedicationAdministration|request|MedicationRequest": { - FromType: "MedicationAdministration", - EdgeLabel: "request", - ToType: "MedicationRequest", + "Observation|derivedFrom_Observation|MedicationStatement": { + FromType: "Observation", + EdgeLabel: "derivedFrom_Observation", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "MedicationRequest/*", + "Observation/*", }, }, - "MedicationRequest|request|MedicationAdministration": { - FromType: "MedicationRequest", - EdgeLabel: "request", - ToType: "MedicationAdministration", + "MedicationStatement|derivedFrom_DiagnosticReport|DiagnosticReport": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_DiagnosticReport", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "MedicationRequest/*", + "DiagnosticReport/*", }, }, - "MedicationAdministration|subject_Patient|Patient": { - FromType: "MedicationAdministration", - EdgeLabel: "subject_Patient", - ToType: "Patient", + "DiagnosticReport|derivedFrom_DiagnosticReport|MedicationStatement": { + FromType: "DiagnosticReport", + EdgeLabel: "derivedFrom_DiagnosticReport", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Patient/*", + "DiagnosticReport/*", }, }, - "Patient|subject_Patient|MedicationAdministration": { - FromType: "Patient", - EdgeLabel: "subject_Patient", - ToType: "MedicationAdministration", + "MedicationStatement|derivedFrom_Condition|Condition": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_Condition", + ToType: "Condition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Patient/*", + "Condition/*", }, }, - "MedicationAdministration|subject_Group|Group": { - FromType: "MedicationAdministration", - EdgeLabel: "subject_Group", - ToType: "Group", + "Condition|derivedFrom_Condition|MedicationStatement": { + FromType: "Condition", + EdgeLabel: "derivedFrom_Condition", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Group/*", + "Condition/*", }, }, - "Group|subject_Group|MedicationAdministration": { - FromType: "Group", - EdgeLabel: "subject_Group", - ToType: "MedicationAdministration", + "MedicationStatement|derivedFrom_Medication|Medication": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_Medication", + ToType: "Medication", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Group/*", + "Medication/*", }, }, - "MedicationAdministration|supportingInformation_Organization|Organization": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_Organization", - ToType: "Organization", + "Medication|derivedFrom_Medication|MedicationStatement": { + FromType: "Medication", + EdgeLabel: "derivedFrom_Medication", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -29644,15 +29344,15 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Organization/*", + "Medication/*", }, }, - "Organization|supportingInformation_Organization|MedicationAdministration": { - FromType: "Organization", - EdgeLabel: "supportingInformation_Organization", + "MedicationStatement|derivedFrom_MedicationAdministration|MedicationAdministration": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -29661,16 +29361,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Organization/*", + "MedicationAdministration/*", }, }, - "MedicationAdministration|supportingInformation_Group|Group": { + "MedicationAdministration|derivedFrom_MedicationAdministration|MedicationStatement": { FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_Group", - ToType: "Group", + EdgeLabel: "derivedFrom_MedicationAdministration", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -29678,16 +29378,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Group/*", + "MedicationAdministration/*", }, }, - "Group|supportingInformation_Group|MedicationAdministration": { - FromType: "Group", - EdgeLabel: "supportingInformation_Group", - ToType: "MedicationAdministration", + "MedicationStatement|derivedFrom_MedicationStatement|MedicationStatement": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_MedicationStatement", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -29695,16 +29395,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Group/*", + "MedicationStatement/*", }, }, - "MedicationAdministration|supportingInformation_Practitioner|Practitioner": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_Practitioner", - ToType: "Practitioner", + "MedicationStatement|derivedFrom_MedicationRequest|MedicationRequest": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_MedicationRequest", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -29712,16 +29412,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Practitioner/*", + "MedicationRequest/*", }, }, - "Practitioner|supportingInformation_Practitioner|MedicationAdministration": { - FromType: "Practitioner", - EdgeLabel: "supportingInformation_Practitioner", - ToType: "MedicationAdministration", + "MedicationRequest|derivedFrom_MedicationRequest|MedicationStatement": { + FromType: "MedicationRequest", + EdgeLabel: "derivedFrom_MedicationRequest", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -29729,16 +29429,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Practitioner/*", + "MedicationRequest/*", }, }, - "MedicationAdministration|supportingInformation_PractitionerRole|PractitionerRole": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_PractitionerRole", - ToType: "PractitionerRole", + "MedicationStatement|derivedFrom_Procedure|Procedure": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -29746,16 +29446,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "PractitionerRole/*", + "Procedure/*", }, }, - "PractitionerRole|supportingInformation_PractitionerRole|MedicationAdministration": { - FromType: "PractitionerRole", - EdgeLabel: "supportingInformation_PractitionerRole", - ToType: "MedicationAdministration", + "Procedure|derivedFrom_Procedure|MedicationStatement": { + FromType: "Procedure", + EdgeLabel: "derivedFrom_Procedure", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -29763,16 +29463,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "PractitionerRole/*", + "Procedure/*", }, }, - "MedicationAdministration|supportingInformation_ResearchStudy|ResearchStudy": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_ResearchStudy", - ToType: "ResearchStudy", + "MedicationStatement|derivedFrom_DocumentReference|DocumentReference": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -29780,16 +29480,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "ResearchStudy/*", + "DocumentReference/*", }, }, - "ResearchStudy|supportingInformation_ResearchStudy|MedicationAdministration": { - FromType: "ResearchStudy", - EdgeLabel: "supportingInformation_ResearchStudy", - ToType: "MedicationAdministration", + "DocumentReference|derivedFrom_DocumentReference|MedicationStatement": { + FromType: "DocumentReference", + EdgeLabel: "derivedFrom_DocumentReference", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -29797,16 +29497,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "ResearchStudy/*", + "DocumentReference/*", }, }, - "MedicationAdministration|supportingInformation_Patient|Patient": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_Patient", - ToType: "Patient", + "MedicationStatement|derivedFrom_Task|Task": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_Task", + ToType: "Task", Direction: []string{ "outbound", }, @@ -29814,16 +29514,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Patient/*", + "Task/*", }, }, - "Patient|supportingInformation_Patient|MedicationAdministration": { - FromType: "Patient", - EdgeLabel: "supportingInformation_Patient", - ToType: "MedicationAdministration", + "Task|derivedFrom_Task|MedicationStatement": { + FromType: "Task", + EdgeLabel: "derivedFrom_Task", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -29831,16 +29531,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Patient/*", + "Task/*", }, }, - "MedicationAdministration|supportingInformation_ResearchSubject|ResearchSubject": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_ResearchSubject", - ToType: "ResearchSubject", + "MedicationStatement|derivedFrom_ImagingStudy|ImagingStudy": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_ImagingStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -29848,16 +29548,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "ResearchSubject/*", + "ImagingStudy/*", }, }, - "ResearchSubject|supportingInformation_ResearchSubject|MedicationAdministration": { - FromType: "ResearchSubject", - EdgeLabel: "supportingInformation_ResearchSubject", - ToType: "MedicationAdministration", + "ImagingStudy|derivedFrom_ImagingStudy|MedicationStatement": { + FromType: "ImagingStudy", + EdgeLabel: "derivedFrom_ImagingStudy", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -29865,16 +29565,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "ResearchSubject/*", + "ImagingStudy/*", }, }, - "MedicationAdministration|supportingInformation_Substance|Substance": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_Substance", - ToType: "Substance", + "MedicationStatement|derivedFrom_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_FamilyMemberHistory", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -29882,16 +29582,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Substance/*", + "FamilyMemberHistory/*", }, }, - "Substance|supportingInformation_Substance|MedicationAdministration": { - FromType: "Substance", - EdgeLabel: "supportingInformation_Substance", - ToType: "MedicationAdministration", + "FamilyMemberHistory|derivedFrom_FamilyMemberHistory|MedicationStatement": { + FromType: "FamilyMemberHistory", + EdgeLabel: "derivedFrom_FamilyMemberHistory", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -29899,16 +29599,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "Substance/*", + "FamilyMemberHistory/*", }, }, - "MedicationAdministration|supportingInformation_SubstanceDefinition|SubstanceDefinition": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_SubstanceDefinition", - ToType: "SubstanceDefinition", + "MedicationStatement|derivedFrom_BodyStructure|BodyStructure": { + FromType: "MedicationStatement", + EdgeLabel: "derivedFrom_BodyStructure", + ToType: "BodyStructure", Direction: []string{ "outbound", }, @@ -29916,16 +29616,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "BodyStructure/*", }, }, - "SubstanceDefinition|supportingInformation_SubstanceDefinition|MedicationAdministration": { - FromType: "SubstanceDefinition", - EdgeLabel: "supportingInformation_SubstanceDefinition", - ToType: "MedicationAdministration", + "BodyStructure|derivedFrom_BodyStructure|MedicationStatement": { + FromType: "BodyStructure", + EdgeLabel: "derivedFrom_BodyStructure", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -29933,16 +29633,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "derivedFrom_medication_statement", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "BodyStructure/*", }, }, - "MedicationAdministration|supportingInformation_Specimen|Specimen": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_Specimen", - ToType: "Specimen", + "MedicationStatement|informationSource_Patient|Patient": { + FromType: "MedicationStatement", + EdgeLabel: "informationSource_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -29950,16 +29650,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "informationSource_medication_statement", }, RegexMatch: []string{ - "Specimen/*", + "Patient/*", }, }, - "Specimen|supportingInformation_Specimen|MedicationAdministration": { - FromType: "Specimen", - EdgeLabel: "supportingInformation_Specimen", - ToType: "MedicationAdministration", + "Patient|informationSource_Patient|MedicationStatement": { + FromType: "Patient", + EdgeLabel: "informationSource_Patient", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -29967,16 +29667,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "informationSource_medication_statement", }, RegexMatch: []string{ - "Specimen/*", + "Patient/*", }, }, - "MedicationAdministration|supportingInformation_Observation|Observation": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_Observation", - ToType: "Observation", + "MedicationStatement|informationSource_Practitioner|Practitioner": { + FromType: "MedicationStatement", + EdgeLabel: "informationSource_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -29984,16 +29684,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "informationSource_medication_statement", }, RegexMatch: []string{ - "Observation/*", + "Practitioner/*", }, }, - "Observation|supportingInformation_Observation|MedicationAdministration": { - FromType: "Observation", - EdgeLabel: "supportingInformation_Observation", - ToType: "MedicationAdministration", + "Practitioner|informationSource_Practitioner|MedicationStatement": { + FromType: "Practitioner", + EdgeLabel: "informationSource_Practitioner", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30001,16 +29701,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "informationSource_medication_statement", }, RegexMatch: []string{ - "Observation/*", + "Practitioner/*", }, }, - "MedicationAdministration|supportingInformation_DiagnosticReport|DiagnosticReport": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_DiagnosticReport", - ToType: "DiagnosticReport", + "MedicationStatement|informationSource_PractitionerRole|PractitionerRole": { + FromType: "MedicationStatement", + EdgeLabel: "informationSource_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -30018,16 +29718,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "informationSource_medication_statement", }, RegexMatch: []string{ - "DiagnosticReport/*", + "PractitionerRole/*", }, }, - "DiagnosticReport|supportingInformation_DiagnosticReport|MedicationAdministration": { - FromType: "DiagnosticReport", - EdgeLabel: "supportingInformation_DiagnosticReport", - ToType: "MedicationAdministration", + "PractitionerRole|informationSource_PractitionerRole|MedicationStatement": { + FromType: "PractitionerRole", + EdgeLabel: "informationSource_PractitionerRole", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30035,16 +29735,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "informationSource_medication_statement", }, RegexMatch: []string{ - "DiagnosticReport/*", + "PractitionerRole/*", }, }, - "MedicationAdministration|supportingInformation_Condition|Condition": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_Condition", - ToType: "Condition", + "MedicationStatement|informationSource_Organization|Organization": { + FromType: "MedicationStatement", + EdgeLabel: "informationSource_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -30052,16 +29752,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "informationSource_medication_statement", }, RegexMatch: []string{ - "Condition/*", + "Organization/*", }, }, - "Condition|supportingInformation_Condition|MedicationAdministration": { - FromType: "Condition", - EdgeLabel: "supportingInformation_Condition", - ToType: "MedicationAdministration", + "Organization|informationSource_Organization|MedicationStatement": { + FromType: "Organization", + EdgeLabel: "informationSource_Organization", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30069,16 +29769,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "informationSource_medication_statement", }, RegexMatch: []string{ - "Condition/*", + "Organization/*", }, }, - "MedicationAdministration|supportingInformation_Medication|Medication": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_Medication", - ToType: "Medication", + "MedicationStatement|partOf_Procedure|Procedure": { + FromType: "MedicationStatement", + EdgeLabel: "partOf_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -30086,16 +29786,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "partOf_medication_statement", }, RegexMatch: []string{ - "Medication/*", + "Procedure/*", }, }, - "Medication|supportingInformation_Medication|MedicationAdministration": { - FromType: "Medication", - EdgeLabel: "supportingInformation_Medication", - ToType: "MedicationAdministration", + "Procedure|partOf_Procedure|MedicationStatement": { + FromType: "Procedure", + EdgeLabel: "partOf_Procedure", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30103,16 +29803,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "partOf_medication_statement", }, RegexMatch: []string{ - "Medication/*", + "Procedure/*", }, }, - "MedicationAdministration|supportingInformation_MedicationAdministration|MedicationAdministration": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_MedicationAdministration", - ToType: "MedicationAdministration", + "MedicationStatement|partOf_MedicationStatement|MedicationStatement": { + FromType: "MedicationStatement", + EdgeLabel: "partOf_MedicationStatement", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30120,16 +29820,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "partOf_medication_statement", }, RegexMatch: []string{ - "MedicationAdministration/*", + "MedicationStatement/*", }, }, - "MedicationAdministration|supportingInformation_MedicationStatement|MedicationStatement": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_MedicationStatement", - ToType: "MedicationStatement", + "MedicationStatement|relatedClinicalInformation_Observation|Observation": { + FromType: "MedicationStatement", + EdgeLabel: "relatedClinicalInformation_Observation", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -30137,16 +29837,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "relatedClinicalInformation_medication_statement", }, RegexMatch: []string{ - "MedicationStatement/*", + "Observation/*", }, }, - "MedicationStatement|supportingInformation_MedicationStatement|MedicationAdministration": { - FromType: "MedicationStatement", - EdgeLabel: "supportingInformation_MedicationStatement", - ToType: "MedicationAdministration", + "Observation|relatedClinicalInformation_Observation|MedicationStatement": { + FromType: "Observation", + EdgeLabel: "relatedClinicalInformation_Observation", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30154,16 +29854,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "relatedClinicalInformation_medication_statement", }, RegexMatch: []string{ - "MedicationStatement/*", + "Observation/*", }, }, - "MedicationAdministration|supportingInformation_MedicationRequest|MedicationRequest": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_MedicationRequest", - ToType: "MedicationRequest", + "MedicationStatement|relatedClinicalInformation_Condition|Condition": { + FromType: "MedicationStatement", + EdgeLabel: "relatedClinicalInformation_Condition", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -30171,16 +29871,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "relatedClinicalInformation_medication_statement", }, RegexMatch: []string{ - "MedicationRequest/*", + "Condition/*", }, }, - "MedicationRequest|supportingInformation_MedicationRequest|MedicationAdministration": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_MedicationRequest", - ToType: "MedicationAdministration", + "Condition|relatedClinicalInformation_Condition|MedicationStatement": { + FromType: "Condition", + EdgeLabel: "relatedClinicalInformation_Condition", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30188,253 +29888,117 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_administration", + "relatedClinicalInformation_medication_statement", }, RegexMatch: []string{ - "MedicationRequest/*", + "Condition/*", }, }, - "MedicationAdministration|supportingInformation_Procedure|Procedure": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_Procedure", - ToType: "Procedure", + "MedicationStatement|subject_Patient|Patient": { + FromType: "MedicationStatement", + EdgeLabel: "subject_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "supportingInformation_medication_administration", + "subject_medication_statement", }, RegexMatch: []string{ - "Procedure/*", + "Patient/*", }, }, - "Procedure|supportingInformation_Procedure|MedicationAdministration": { - FromType: "Procedure", - EdgeLabel: "supportingInformation_Procedure", - ToType: "MedicationAdministration", + "Patient|subject_Patient|MedicationStatement": { + FromType: "Patient", + EdgeLabel: "subject_Patient", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "supportingInformation_medication_administration", + "subject_medication_statement", }, RegexMatch: []string{ - "Procedure/*", + "Patient/*", }, }, - "MedicationAdministration|supportingInformation_DocumentReference|DocumentReference": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_DocumentReference", - ToType: "DocumentReference", + "MedicationStatement|subject_Group|Group": { + FromType: "MedicationStatement", + EdgeLabel: "subject_Group", + ToType: "Group", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "supportingInformation_medication_administration", + "subject_medication_statement", }, RegexMatch: []string{ - "DocumentReference/*", + "Group/*", }, }, - "DocumentReference|supportingInformation_DocumentReference|MedicationAdministration": { - FromType: "DocumentReference", - EdgeLabel: "supportingInformation_DocumentReference", - ToType: "MedicationAdministration", + "Group|subject_Group|MedicationStatement": { + FromType: "Group", + EdgeLabel: "subject_Group", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "supportingInformation_medication_administration", + "subject_medication_statement", }, RegexMatch: []string{ - "DocumentReference/*", + "Group/*", }, }, - "MedicationAdministration|supportingInformation_Task|Task": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_Task", - ToType: "Task", + "MedicationStatement|medication_reference_Organization|Organization": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "supportingInformation_medication_administration", + "codeable_reference", }, RegexMatch: []string{ - "Task/*", + "Organization/*", }, }, - "Task|supportingInformation_Task|MedicationAdministration": { - FromType: "Task", - EdgeLabel: "supportingInformation_Task", - ToType: "MedicationAdministration", + "Organization|medication_reference_Organization|MedicationStatement": { + FromType: "Organization", + EdgeLabel: "medication_reference_Organization", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "supportingInformation_medication_administration", + "codeable_reference", }, RegexMatch: []string{ - "Task/*", + "Organization/*", }, }, - "MedicationAdministration|supportingInformation_ImagingStudy|ImagingStudy": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_administration", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|supportingInformation_ImagingStudy|MedicationAdministration": { - FromType: "ImagingStudy", - EdgeLabel: "supportingInformation_ImagingStudy", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_administration", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "MedicationAdministration|supportingInformation_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_FamilyMemberHistory", - ToType: "FamilyMemberHistory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_administration", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "FamilyMemberHistory|supportingInformation_FamilyMemberHistory|MedicationAdministration": { - FromType: "FamilyMemberHistory", - EdgeLabel: "supportingInformation_FamilyMemberHistory", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_administration", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "MedicationAdministration|supportingInformation_BodyStructure|BodyStructure": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_administration", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|supportingInformation_BodyStructure|MedicationAdministration": { - FromType: "BodyStructure", - EdgeLabel: "supportingInformation_BodyStructure", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_administration", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "MedicationAdministration|device_reference_Organization|Organization": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|device_reference_Organization|MedicationAdministration": { - FromType: "Organization", - EdgeLabel: "device_reference_Organization", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "MedicationAdministration|device_reference_Group|Group": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_Group", + "MedicationStatement|medication_reference_Group|Group": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_Group", ToType: "Group", Direction: []string{ "outbound", @@ -30449,10 +30013,10 @@ var Traversals = map[string]Traversal{ "Group/*", }, }, - "Group|device_reference_Group|MedicationAdministration": { + "Group|medication_reference_Group|MedicationStatement": { FromType: "Group", - EdgeLabel: "device_reference_Group", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_Group", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30466,9 +30030,9 @@ var Traversals = map[string]Traversal{ "Group/*", }, }, - "MedicationAdministration|device_reference_Practitioner|Practitioner": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_Practitioner", + "MedicationStatement|medication_reference_Practitioner|Practitioner": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", @@ -30483,10 +30047,10 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "Practitioner|device_reference_Practitioner|MedicationAdministration": { + "Practitioner|medication_reference_Practitioner|MedicationStatement": { FromType: "Practitioner", - EdgeLabel: "device_reference_Practitioner", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_Practitioner", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30500,9 +30064,9 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "MedicationAdministration|device_reference_PractitionerRole|PractitionerRole": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_PractitionerRole", + "MedicationStatement|medication_reference_PractitionerRole|PractitionerRole": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", @@ -30517,10 +30081,10 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "PractitionerRole|device_reference_PractitionerRole|MedicationAdministration": { + "PractitionerRole|medication_reference_PractitionerRole|MedicationStatement": { FromType: "PractitionerRole", - EdgeLabel: "device_reference_PractitionerRole", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_PractitionerRole", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30534,9 +30098,9 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "MedicationAdministration|device_reference_ResearchStudy|ResearchStudy": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_ResearchStudy", + "MedicationStatement|medication_reference_ResearchStudy|ResearchStudy": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -30551,10 +30115,10 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "ResearchStudy|device_reference_ResearchStudy|MedicationAdministration": { + "ResearchStudy|medication_reference_ResearchStudy|MedicationStatement": { FromType: "ResearchStudy", - EdgeLabel: "device_reference_ResearchStudy", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_ResearchStudy", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30568,9 +30132,9 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "MedicationAdministration|device_reference_Patient|Patient": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_Patient", + "MedicationStatement|medication_reference_Patient|Patient": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -30585,10 +30149,10 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "Patient|device_reference_Patient|MedicationAdministration": { + "Patient|medication_reference_Patient|MedicationStatement": { FromType: "Patient", - EdgeLabel: "device_reference_Patient", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_Patient", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30602,9 +30166,9 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "MedicationAdministration|device_reference_ResearchSubject|ResearchSubject": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_ResearchSubject", + "MedicationStatement|medication_reference_ResearchSubject|ResearchSubject": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -30619,10 +30183,10 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "ResearchSubject|device_reference_ResearchSubject|MedicationAdministration": { + "ResearchSubject|medication_reference_ResearchSubject|MedicationStatement": { FromType: "ResearchSubject", - EdgeLabel: "device_reference_ResearchSubject", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_ResearchSubject", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30636,9 +30200,9 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "MedicationAdministration|device_reference_Substance|Substance": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_Substance", + "MedicationStatement|medication_reference_Substance|Substance": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -30653,10 +30217,10 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "Substance|device_reference_Substance|MedicationAdministration": { + "Substance|medication_reference_Substance|MedicationStatement": { FromType: "Substance", - EdgeLabel: "device_reference_Substance", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_Substance", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30670,9 +30234,9 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "MedicationAdministration|device_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_SubstanceDefinition", + "MedicationStatement|medication_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -30687,10 +30251,10 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|device_reference_SubstanceDefinition|MedicationAdministration": { + "SubstanceDefinition|medication_reference_SubstanceDefinition|MedicationStatement": { FromType: "SubstanceDefinition", - EdgeLabel: "device_reference_SubstanceDefinition", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_SubstanceDefinition", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30704,9 +30268,9 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "MedicationAdministration|device_reference_Specimen|Specimen": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_Specimen", + "MedicationStatement|medication_reference_Specimen|Specimen": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -30721,10 +30285,10 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "Specimen|device_reference_Specimen|MedicationAdministration": { + "Specimen|medication_reference_Specimen|MedicationStatement": { FromType: "Specimen", - EdgeLabel: "device_reference_Specimen", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_Specimen", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30738,9 +30302,9 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "MedicationAdministration|device_reference_Observation|Observation": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_Observation", + "MedicationStatement|medication_reference_Observation|Observation": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -30755,10 +30319,10 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "Observation|device_reference_Observation|MedicationAdministration": { + "Observation|medication_reference_Observation|MedicationStatement": { FromType: "Observation", - EdgeLabel: "device_reference_Observation", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_Observation", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30772,9 +30336,9 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "MedicationAdministration|device_reference_DiagnosticReport|DiagnosticReport": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_DiagnosticReport", + "MedicationStatement|medication_reference_DiagnosticReport|DiagnosticReport": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -30789,10 +30353,10 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "DiagnosticReport|device_reference_DiagnosticReport|MedicationAdministration": { + "DiagnosticReport|medication_reference_DiagnosticReport|MedicationStatement": { FromType: "DiagnosticReport", - EdgeLabel: "device_reference_DiagnosticReport", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_DiagnosticReport", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30806,9 +30370,9 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "MedicationAdministration|device_reference_Condition|Condition": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_Condition", + "MedicationStatement|medication_reference_Condition|Condition": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -30823,10 +30387,10 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "Condition|device_reference_Condition|MedicationAdministration": { + "Condition|medication_reference_Condition|MedicationStatement": { FromType: "Condition", - EdgeLabel: "device_reference_Condition", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_Condition", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30840,9 +30404,9 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "MedicationAdministration|device_reference_Medication|Medication": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_Medication", + "MedicationStatement|medication_reference_Medication|Medication": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -30857,10 +30421,10 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "Medication|device_reference_Medication|MedicationAdministration": { + "Medication|medication_reference_Medication|MedicationStatement": { FromType: "Medication", - EdgeLabel: "device_reference_Medication", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_Medication", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30874,9 +30438,9 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "MedicationAdministration|device_reference_MedicationAdministration|MedicationAdministration": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_MedicationAdministration", + "MedicationStatement|medication_reference_MedicationAdministration|MedicationAdministration": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -30891,9 +30455,9 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "MedicationAdministration|device_reference_MedicationStatement|MedicationStatement": { + "MedicationAdministration|medication_reference_MedicationAdministration|MedicationStatement": { FromType: "MedicationAdministration", - EdgeLabel: "device_reference_MedicationStatement", + EdgeLabel: "medication_reference_MedicationAdministration", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -30905,13 +30469,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "MedicationStatement/*", + "MedicationAdministration/*", }, }, - "MedicationStatement|device_reference_MedicationStatement|MedicationAdministration": { + "MedicationStatement|medication_reference_MedicationStatement|MedicationStatement": { FromType: "MedicationStatement", - EdgeLabel: "device_reference_MedicationStatement", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_MedicationStatement", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30925,9 +30489,9 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "MedicationAdministration|device_reference_MedicationRequest|MedicationRequest": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_MedicationRequest", + "MedicationStatement|medication_reference_MedicationRequest|MedicationRequest": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -30942,10 +30506,10 @@ var Traversals = map[string]Traversal{ "MedicationRequest/*", }, }, - "MedicationRequest|device_reference_MedicationRequest|MedicationAdministration": { + "MedicationRequest|medication_reference_MedicationRequest|MedicationStatement": { FromType: "MedicationRequest", - EdgeLabel: "device_reference_MedicationRequest", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_MedicationRequest", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30959,9 +30523,9 @@ var Traversals = map[string]Traversal{ "MedicationRequest/*", }, }, - "MedicationAdministration|device_reference_Procedure|Procedure": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_Procedure", + "MedicationStatement|medication_reference_Procedure|Procedure": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_Procedure", ToType: "Procedure", Direction: []string{ "outbound", @@ -30976,10 +30540,10 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "Procedure|device_reference_Procedure|MedicationAdministration": { + "Procedure|medication_reference_Procedure|MedicationStatement": { FromType: "Procedure", - EdgeLabel: "device_reference_Procedure", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_Procedure", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -30993,9 +30557,9 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "MedicationAdministration|device_reference_DocumentReference|DocumentReference": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_DocumentReference", + "MedicationStatement|medication_reference_DocumentReference|DocumentReference": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_DocumentReference", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -31010,10 +30574,10 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "DocumentReference|device_reference_DocumentReference|MedicationAdministration": { + "DocumentReference|medication_reference_DocumentReference|MedicationStatement": { FromType: "DocumentReference", - EdgeLabel: "device_reference_DocumentReference", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_DocumentReference", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31027,9 +30591,9 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "MedicationAdministration|device_reference_Task|Task": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_Task", + "MedicationStatement|medication_reference_Task|Task": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_Task", ToType: "Task", Direction: []string{ "outbound", @@ -31044,10 +30608,10 @@ var Traversals = map[string]Traversal{ "Task/*", }, }, - "Task|device_reference_Task|MedicationAdministration": { + "Task|medication_reference_Task|MedicationStatement": { FromType: "Task", - EdgeLabel: "device_reference_Task", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_Task", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31061,9 +30625,9 @@ var Traversals = map[string]Traversal{ "Task/*", }, }, - "MedicationAdministration|device_reference_ImagingStudy|ImagingStudy": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_ImagingStudy", + "MedicationStatement|medication_reference_ImagingStudy|ImagingStudy": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", @@ -31078,10 +30642,10 @@ var Traversals = map[string]Traversal{ "ImagingStudy/*", }, }, - "ImagingStudy|device_reference_ImagingStudy|MedicationAdministration": { + "ImagingStudy|medication_reference_ImagingStudy|MedicationStatement": { FromType: "ImagingStudy", - EdgeLabel: "device_reference_ImagingStudy", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_ImagingStudy", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31095,9 +30659,9 @@ var Traversals = map[string]Traversal{ "ImagingStudy/*", }, }, - "MedicationAdministration|device_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_FamilyMemberHistory", + "MedicationStatement|medication_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -31112,10 +30676,10 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|device_reference_FamilyMemberHistory|MedicationAdministration": { + "FamilyMemberHistory|medication_reference_FamilyMemberHistory|MedicationStatement": { FromType: "FamilyMemberHistory", - EdgeLabel: "device_reference_FamilyMemberHistory", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_FamilyMemberHistory", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31129,9 +30693,9 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "MedicationAdministration|device_reference_BodyStructure|BodyStructure": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_BodyStructure", + "MedicationStatement|medication_reference_BodyStructure|BodyStructure": { + FromType: "MedicationStatement", + EdgeLabel: "medication_reference_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", @@ -31146,10 +30710,10 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "BodyStructure|device_reference_BodyStructure|MedicationAdministration": { + "BodyStructure|medication_reference_BodyStructure|MedicationStatement": { FromType: "BodyStructure", - EdgeLabel: "device_reference_BodyStructure", - ToType: "MedicationAdministration", + EdgeLabel: "medication_reference_BodyStructure", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31163,10 +30727,10 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "MedicationAdministration|medication_reference_Organization|Organization": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_Organization", - ToType: "Organization", + "MedicationStatement|note_authorReference_Practitioner|Practitioner": { + FromType: "MedicationStatement", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -31174,16 +30738,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Organization/*", + "Practitioner/*", }, }, - "Organization|medication_reference_Organization|MedicationAdministration": { - FromType: "Organization", - EdgeLabel: "medication_reference_Organization", - ToType: "MedicationAdministration", + "Practitioner|note_authorReference_Practitioner|MedicationStatement": { + FromType: "Practitioner", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31191,16 +30755,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Organization/*", + "Practitioner/*", }, }, - "MedicationAdministration|medication_reference_Group|Group": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_Group", - ToType: "Group", + "MedicationStatement|note_authorReference_PractitionerRole|PractitionerRole": { + FromType: "MedicationStatement", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -31208,16 +30772,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Group/*", + "PractitionerRole/*", }, }, - "Group|medication_reference_Group|MedicationAdministration": { - FromType: "Group", - EdgeLabel: "medication_reference_Group", - ToType: "MedicationAdministration", + "PractitionerRole|note_authorReference_PractitionerRole|MedicationStatement": { + FromType: "PractitionerRole", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31225,16 +30789,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Group/*", + "PractitionerRole/*", }, }, - "MedicationAdministration|medication_reference_Practitioner|Practitioner": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_Practitioner", - ToType: "Practitioner", + "MedicationStatement|note_authorReference_Patient|Patient": { + FromType: "MedicationStatement", + EdgeLabel: "note_authorReference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -31242,16 +30806,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Practitioner/*", + "Patient/*", }, }, - "Practitioner|medication_reference_Practitioner|MedicationAdministration": { - FromType: "Practitioner", - EdgeLabel: "medication_reference_Practitioner", - ToType: "MedicationAdministration", + "Patient|note_authorReference_Patient|MedicationStatement": { + FromType: "Patient", + EdgeLabel: "note_authorReference_Patient", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31259,16 +30823,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Practitioner/*", + "Patient/*", }, }, - "MedicationAdministration|medication_reference_PractitionerRole|PractitionerRole": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_PractitionerRole", - ToType: "PractitionerRole", + "MedicationStatement|note_authorReference_Organization|Organization": { + FromType: "MedicationStatement", + EdgeLabel: "note_authorReference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -31276,16 +30840,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "PractitionerRole/*", + "Organization/*", }, }, - "PractitionerRole|medication_reference_PractitionerRole|MedicationAdministration": { - FromType: "PractitionerRole", - EdgeLabel: "medication_reference_PractitionerRole", - ToType: "MedicationAdministration", + "Organization|note_authorReference_Organization|MedicationStatement": { + FromType: "Organization", + EdgeLabel: "note_authorReference_Organization", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31293,16 +30857,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "PractitionerRole/*", + "Organization/*", }, }, - "MedicationAdministration|medication_reference_ResearchStudy|ResearchStudy": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_ResearchStudy", - ToType: "ResearchStudy", + "MedicationStatement|reason_reference_Organization|Organization": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -31313,13 +30877,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "ResearchStudy/*", + "Organization/*", }, }, - "ResearchStudy|medication_reference_ResearchStudy|MedicationAdministration": { - FromType: "ResearchStudy", - EdgeLabel: "medication_reference_ResearchStudy", - ToType: "MedicationAdministration", + "Organization|reason_reference_Organization|MedicationStatement": { + FromType: "Organization", + EdgeLabel: "reason_reference_Organization", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31330,13 +30894,149 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "ResearchStudy/*", + "Organization/*", }, }, - "MedicationAdministration|medication_reference_Patient|Patient": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_Patient", - ToType: "Patient", + "MedicationStatement|reason_reference_Group|Group": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_Group", + ToType: "Group", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "Group/*", + }, + }, + "Group|reason_reference_Group|MedicationStatement": { + FromType: "Group", + EdgeLabel: "reason_reference_Group", + ToType: "MedicationStatement", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "Group/*", + }, + }, + "MedicationStatement|reason_reference_Practitioner|Practitioner": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_Practitioner", + ToType: "Practitioner", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "Practitioner/*", + }, + }, + "Practitioner|reason_reference_Practitioner|MedicationStatement": { + FromType: "Practitioner", + EdgeLabel: "reason_reference_Practitioner", + ToType: "MedicationStatement", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "Practitioner/*", + }, + }, + "MedicationStatement|reason_reference_PractitionerRole|PractitionerRole": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_PractitionerRole", + ToType: "PractitionerRole", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "PractitionerRole/*", + }, + }, + "PractitionerRole|reason_reference_PractitionerRole|MedicationStatement": { + FromType: "PractitionerRole", + EdgeLabel: "reason_reference_PractitionerRole", + ToType: "MedicationStatement", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "PractitionerRole/*", + }, + }, + "MedicationStatement|reason_reference_ResearchStudy|ResearchStudy": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_ResearchStudy", + ToType: "ResearchStudy", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "ResearchStudy/*", + }, + }, + "ResearchStudy|reason_reference_ResearchStudy|MedicationStatement": { + FromType: "ResearchStudy", + EdgeLabel: "reason_reference_ResearchStudy", + ToType: "MedicationStatement", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "ResearchStudy/*", + }, + }, + "MedicationStatement|reason_reference_Patient|Patient": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -31350,10 +31050,10 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "Patient|medication_reference_Patient|MedicationAdministration": { + "Patient|reason_reference_Patient|MedicationStatement": { FromType: "Patient", - EdgeLabel: "medication_reference_Patient", - ToType: "MedicationAdministration", + EdgeLabel: "reason_reference_Patient", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31367,9 +31067,9 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "MedicationAdministration|medication_reference_ResearchSubject|ResearchSubject": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_ResearchSubject", + "MedicationStatement|reason_reference_ResearchSubject|ResearchSubject": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -31384,10 +31084,10 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "ResearchSubject|medication_reference_ResearchSubject|MedicationAdministration": { + "ResearchSubject|reason_reference_ResearchSubject|MedicationStatement": { FromType: "ResearchSubject", - EdgeLabel: "medication_reference_ResearchSubject", - ToType: "MedicationAdministration", + EdgeLabel: "reason_reference_ResearchSubject", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31401,9 +31101,9 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "MedicationAdministration|medication_reference_Substance|Substance": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_Substance", + "MedicationStatement|reason_reference_Substance|Substance": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -31418,10 +31118,10 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "Substance|medication_reference_Substance|MedicationAdministration": { + "Substance|reason_reference_Substance|MedicationStatement": { FromType: "Substance", - EdgeLabel: "medication_reference_Substance", - ToType: "MedicationAdministration", + EdgeLabel: "reason_reference_Substance", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31435,9 +31135,9 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "MedicationAdministration|medication_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_SubstanceDefinition", + "MedicationStatement|reason_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -31452,10 +31152,10 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|medication_reference_SubstanceDefinition|MedicationAdministration": { + "SubstanceDefinition|reason_reference_SubstanceDefinition|MedicationStatement": { FromType: "SubstanceDefinition", - EdgeLabel: "medication_reference_SubstanceDefinition", - ToType: "MedicationAdministration", + EdgeLabel: "reason_reference_SubstanceDefinition", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31469,9 +31169,9 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "MedicationAdministration|medication_reference_Specimen|Specimen": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_Specimen", + "MedicationStatement|reason_reference_Specimen|Specimen": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -31486,10 +31186,10 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "Specimen|medication_reference_Specimen|MedicationAdministration": { + "Specimen|reason_reference_Specimen|MedicationStatement": { FromType: "Specimen", - EdgeLabel: "medication_reference_Specimen", - ToType: "MedicationAdministration", + EdgeLabel: "reason_reference_Specimen", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31503,9 +31203,9 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "MedicationAdministration|medication_reference_Observation|Observation": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_Observation", + "MedicationStatement|reason_reference_Observation|Observation": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -31520,10 +31220,10 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "Observation|medication_reference_Observation|MedicationAdministration": { + "Observation|reason_reference_Observation|MedicationStatement": { FromType: "Observation", - EdgeLabel: "medication_reference_Observation", - ToType: "MedicationAdministration", + EdgeLabel: "reason_reference_Observation", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31537,9 +31237,9 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "MedicationAdministration|medication_reference_DiagnosticReport|DiagnosticReport": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_DiagnosticReport", + "MedicationStatement|reason_reference_DiagnosticReport|DiagnosticReport": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -31554,10 +31254,10 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "DiagnosticReport|medication_reference_DiagnosticReport|MedicationAdministration": { + "DiagnosticReport|reason_reference_DiagnosticReport|MedicationStatement": { FromType: "DiagnosticReport", - EdgeLabel: "medication_reference_DiagnosticReport", - ToType: "MedicationAdministration", + EdgeLabel: "reason_reference_DiagnosticReport", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31571,9 +31271,9 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "MedicationAdministration|medication_reference_Condition|Condition": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_Condition", + "MedicationStatement|reason_reference_Condition|Condition": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -31588,10 +31288,10 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "Condition|medication_reference_Condition|MedicationAdministration": { + "Condition|reason_reference_Condition|MedicationStatement": { FromType: "Condition", - EdgeLabel: "medication_reference_Condition", - ToType: "MedicationAdministration", + EdgeLabel: "reason_reference_Condition", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31605,9 +31305,9 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "MedicationAdministration|medication_reference_Medication|Medication": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_Medication", + "MedicationStatement|reason_reference_Medication|Medication": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -31622,10 +31322,10 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "Medication|medication_reference_Medication|MedicationAdministration": { + "Medication|reason_reference_Medication|MedicationStatement": { FromType: "Medication", - EdgeLabel: "medication_reference_Medication", - ToType: "MedicationAdministration", + EdgeLabel: "reason_reference_Medication", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31639,9 +31339,9 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "MedicationAdministration|medication_reference_MedicationAdministration|MedicationAdministration": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_MedicationAdministration", + "MedicationStatement|reason_reference_MedicationAdministration|MedicationAdministration": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -31656,9 +31356,9 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "MedicationAdministration|medication_reference_MedicationStatement|MedicationStatement": { + "MedicationAdministration|reason_reference_MedicationAdministration|MedicationStatement": { FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_MedicationStatement", + EdgeLabel: "reason_reference_MedicationAdministration", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -31670,13 +31370,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "MedicationStatement/*", + "MedicationAdministration/*", }, }, - "MedicationStatement|medication_reference_MedicationStatement|MedicationAdministration": { + "MedicationStatement|reason_reference_MedicationStatement|MedicationStatement": { FromType: "MedicationStatement", - EdgeLabel: "medication_reference_MedicationStatement", - ToType: "MedicationAdministration", + EdgeLabel: "reason_reference_MedicationStatement", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31690,9 +31390,9 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "MedicationAdministration|medication_reference_MedicationRequest|MedicationRequest": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_MedicationRequest", + "MedicationStatement|reason_reference_MedicationRequest|MedicationRequest": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -31707,10 +31407,10 @@ var Traversals = map[string]Traversal{ "MedicationRequest/*", }, }, - "MedicationRequest|medication_reference_MedicationRequest|MedicationAdministration": { + "MedicationRequest|reason_reference_MedicationRequest|MedicationStatement": { FromType: "MedicationRequest", - EdgeLabel: "medication_reference_MedicationRequest", - ToType: "MedicationAdministration", + EdgeLabel: "reason_reference_MedicationRequest", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31724,9 +31424,9 @@ var Traversals = map[string]Traversal{ "MedicationRequest/*", }, }, - "MedicationAdministration|medication_reference_Procedure|Procedure": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_Procedure", + "MedicationStatement|reason_reference_Procedure|Procedure": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_Procedure", ToType: "Procedure", Direction: []string{ "outbound", @@ -31741,10 +31441,10 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "Procedure|medication_reference_Procedure|MedicationAdministration": { + "Procedure|reason_reference_Procedure|MedicationStatement": { FromType: "Procedure", - EdgeLabel: "medication_reference_Procedure", - ToType: "MedicationAdministration", + EdgeLabel: "reason_reference_Procedure", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31758,9 +31458,9 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "MedicationAdministration|medication_reference_DocumentReference|DocumentReference": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_DocumentReference", + "MedicationStatement|reason_reference_DocumentReference|DocumentReference": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_DocumentReference", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -31775,10 +31475,10 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "DocumentReference|medication_reference_DocumentReference|MedicationAdministration": { + "DocumentReference|reason_reference_DocumentReference|MedicationStatement": { FromType: "DocumentReference", - EdgeLabel: "medication_reference_DocumentReference", - ToType: "MedicationAdministration", + EdgeLabel: "reason_reference_DocumentReference", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31792,9 +31492,9 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "MedicationAdministration|medication_reference_Task|Task": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_Task", + "MedicationStatement|reason_reference_Task|Task": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_Task", ToType: "Task", Direction: []string{ "outbound", @@ -31809,10 +31509,10 @@ var Traversals = map[string]Traversal{ "Task/*", }, }, - "Task|medication_reference_Task|MedicationAdministration": { + "Task|reason_reference_Task|MedicationStatement": { FromType: "Task", - EdgeLabel: "medication_reference_Task", - ToType: "MedicationAdministration", + EdgeLabel: "reason_reference_Task", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31826,9 +31526,9 @@ var Traversals = map[string]Traversal{ "Task/*", }, }, - "MedicationAdministration|medication_reference_ImagingStudy|ImagingStudy": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_ImagingStudy", + "MedicationStatement|reason_reference_ImagingStudy|ImagingStudy": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", @@ -31843,10 +31543,10 @@ var Traversals = map[string]Traversal{ "ImagingStudy/*", }, }, - "ImagingStudy|medication_reference_ImagingStudy|MedicationAdministration": { + "ImagingStudy|reason_reference_ImagingStudy|MedicationStatement": { FromType: "ImagingStudy", - EdgeLabel: "medication_reference_ImagingStudy", - ToType: "MedicationAdministration", + EdgeLabel: "reason_reference_ImagingStudy", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31860,9 +31560,9 @@ var Traversals = map[string]Traversal{ "ImagingStudy/*", }, }, - "MedicationAdministration|medication_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_FamilyMemberHistory", + "MedicationStatement|reason_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -31877,10 +31577,10 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|medication_reference_FamilyMemberHistory|MedicationAdministration": { + "FamilyMemberHistory|reason_reference_FamilyMemberHistory|MedicationStatement": { FromType: "FamilyMemberHistory", - EdgeLabel: "medication_reference_FamilyMemberHistory", - ToType: "MedicationAdministration", + EdgeLabel: "reason_reference_FamilyMemberHistory", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31894,9 +31594,9 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "MedicationAdministration|medication_reference_BodyStructure|BodyStructure": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_BodyStructure", + "MedicationStatement|reason_reference_BodyStructure|BodyStructure": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", @@ -31911,10 +31611,10 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "BodyStructure|medication_reference_BodyStructure|MedicationAdministration": { + "BodyStructure|reason_reference_BodyStructure|MedicationStatement": { FromType: "BodyStructure", - EdgeLabel: "medication_reference_BodyStructure", - ToType: "MedicationAdministration", + EdgeLabel: "reason_reference_BodyStructure", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -31928,44 +31628,44 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "MedicationAdministration|note_authorReference_Practitioner|Practitioner": { - FromType: "MedicationAdministration", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "Practitioner", + "Observation|basedOn_MedicationRequest|MedicationRequest": { + FromType: "Observation", + EdgeLabel: "basedOn_MedicationRequest", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "annotation", + "basedOn_observation", }, RegexMatch: []string{ - "Practitioner/*", + "MedicationRequest/*", }, }, - "Practitioner|note_authorReference_Practitioner|MedicationAdministration": { - FromType: "Practitioner", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "MedicationAdministration", + "MedicationRequest|basedOn_MedicationRequest|Observation": { + FromType: "MedicationRequest", + EdgeLabel: "basedOn_MedicationRequest", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "annotation", + "basedOn_observation", }, RegexMatch: []string{ - "Practitioner/*", + "MedicationRequest/*", }, }, - "MedicationAdministration|note_authorReference_PractitionerRole|PractitionerRole": { - FromType: "MedicationAdministration", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "PractitionerRole", + "Observation|bodyStructure|BodyStructure": { + FromType: "Observation", + EdgeLabel: "bodyStructure", + ToType: "BodyStructure", Direction: []string{ "outbound", }, @@ -31973,16 +31673,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "observation", }, RegexMatch: []string{ - "PractitionerRole/*", + "BodyStructure/*", }, }, - "PractitionerRole|note_authorReference_PractitionerRole|MedicationAdministration": { - FromType: "PractitionerRole", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "MedicationAdministration", + "BodyStructure|bodyStructure|Observation": { + FromType: "BodyStructure", + EdgeLabel: "bodyStructure", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -31990,1154 +31690,1154 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "observation", }, RegexMatch: []string{ - "PractitionerRole/*", + "BodyStructure/*", }, }, - "MedicationAdministration|note_authorReference_Patient|Patient": { - FromType: "MedicationAdministration", - EdgeLabel: "note_authorReference_Patient", - ToType: "Patient", + "Observation|derivedFrom_DocumentReference|DocumentReference": { + FromType: "Observation", + EdgeLabel: "derivedFrom_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "annotation", + "derivedFrom_observation", }, RegexMatch: []string{ - "Patient/*", + "DocumentReference/*", }, }, - "Patient|note_authorReference_Patient|MedicationAdministration": { - FromType: "Patient", - EdgeLabel: "note_authorReference_Patient", - ToType: "MedicationAdministration", + "DocumentReference|derivedFrom_DocumentReference|Observation": { + FromType: "DocumentReference", + EdgeLabel: "derivedFrom_DocumentReference", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "annotation", + "derivedFrom_observation", }, RegexMatch: []string{ - "Patient/*", + "DocumentReference/*", }, }, - "MedicationAdministration|note_authorReference_Organization|Organization": { - FromType: "MedicationAdministration", - EdgeLabel: "note_authorReference_Organization", - ToType: "Organization", + "Observation|derivedFrom_ImagingStudy|ImagingStudy": { + FromType: "Observation", + EdgeLabel: "derivedFrom_ImagingStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "annotation", + "derivedFrom_observation", }, RegexMatch: []string{ - "Organization/*", + "ImagingStudy/*", }, }, - "Organization|note_authorReference_Organization|MedicationAdministration": { - FromType: "Organization", - EdgeLabel: "note_authorReference_Organization", - ToType: "MedicationAdministration", + "ImagingStudy|derivedFrom_ImagingStudy|Observation": { + FromType: "ImagingStudy", + EdgeLabel: "derivedFrom_ImagingStudy", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "annotation", + "derivedFrom_observation", }, RegexMatch: []string{ - "Organization/*", + "ImagingStudy/*", }, }, - "MedicationAdministration|reason_reference_Organization|Organization": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_Organization", + "Observation|derivedFrom_Observation|Observation": { + FromType: "Observation", + EdgeLabel: "derivedFrom_Observation", + ToType: "Observation", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_many", + }, + Backref: []string{ + "derivedFrom_observation", + }, + RegexMatch: []string{ + "Observation/*", + }, + }, + "Observation|focus_Organization|Organization": { + FromType: "Observation", + EdgeLabel: "focus_Organization", ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Organization/*", }, }, - "Organization|reason_reference_Organization|MedicationAdministration": { + "Organization|focus_Organization|Observation": { FromType: "Organization", - EdgeLabel: "reason_reference_Organization", - ToType: "MedicationAdministration", + EdgeLabel: "focus_Organization", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Organization/*", }, }, - "MedicationAdministration|reason_reference_Group|Group": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_Group", + "Observation|focus_Group|Group": { + FromType: "Observation", + EdgeLabel: "focus_Group", ToType: "Group", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Group/*", }, }, - "Group|reason_reference_Group|MedicationAdministration": { + "Group|focus_Group|Observation": { FromType: "Group", - EdgeLabel: "reason_reference_Group", - ToType: "MedicationAdministration", + EdgeLabel: "focus_Group", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Group/*", }, }, - "MedicationAdministration|reason_reference_Practitioner|Practitioner": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_Practitioner", + "Observation|focus_Practitioner|Practitioner": { + FromType: "Observation", + EdgeLabel: "focus_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Practitioner|reason_reference_Practitioner|MedicationAdministration": { + "Practitioner|focus_Practitioner|Observation": { FromType: "Practitioner", - EdgeLabel: "reason_reference_Practitioner", - ToType: "MedicationAdministration", + EdgeLabel: "focus_Practitioner", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Practitioner/*", }, }, - "MedicationAdministration|reason_reference_PractitionerRole|PractitionerRole": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_PractitionerRole", + "Observation|focus_PractitionerRole|PractitionerRole": { + FromType: "Observation", + EdgeLabel: "focus_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "PractitionerRole|reason_reference_PractitionerRole|MedicationAdministration": { + "PractitionerRole|focus_PractitionerRole|Observation": { FromType: "PractitionerRole", - EdgeLabel: "reason_reference_PractitionerRole", - ToType: "MedicationAdministration", + EdgeLabel: "focus_PractitionerRole", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "MedicationAdministration|reason_reference_ResearchStudy|ResearchStudy": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_ResearchStudy", + "Observation|focus_ResearchStudy|ResearchStudy": { + FromType: "Observation", + EdgeLabel: "focus_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "ResearchStudy|reason_reference_ResearchStudy|MedicationAdministration": { + "ResearchStudy|focus_ResearchStudy|Observation": { FromType: "ResearchStudy", - EdgeLabel: "reason_reference_ResearchStudy", - ToType: "MedicationAdministration", + EdgeLabel: "focus_ResearchStudy", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "MedicationAdministration|reason_reference_Patient|Patient": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_Patient", + "Observation|focus_Patient|Patient": { + FromType: "Observation", + EdgeLabel: "focus_Patient", ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|reason_reference_Patient|MedicationAdministration": { + "Patient|focus_Patient|Observation": { FromType: "Patient", - EdgeLabel: "reason_reference_Patient", - ToType: "MedicationAdministration", + EdgeLabel: "focus_Patient", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Patient/*", }, }, - "MedicationAdministration|reason_reference_ResearchSubject|ResearchSubject": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_ResearchSubject", + "Observation|focus_ResearchSubject|ResearchSubject": { + FromType: "Observation", + EdgeLabel: "focus_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "ResearchSubject|reason_reference_ResearchSubject|MedicationAdministration": { + "ResearchSubject|focus_ResearchSubject|Observation": { FromType: "ResearchSubject", - EdgeLabel: "reason_reference_ResearchSubject", - ToType: "MedicationAdministration", + EdgeLabel: "focus_ResearchSubject", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "MedicationAdministration|reason_reference_Substance|Substance": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_Substance", + "Observation|focus_Substance|Substance": { + FromType: "Observation", + EdgeLabel: "focus_Substance", ToType: "Substance", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Substance/*", }, }, - "Substance|reason_reference_Substance|MedicationAdministration": { + "Substance|focus_Substance|Observation": { FromType: "Substance", - EdgeLabel: "reason_reference_Substance", - ToType: "MedicationAdministration", + EdgeLabel: "focus_Substance", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Substance/*", }, }, - "MedicationAdministration|reason_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_SubstanceDefinition", + "Observation|focus_SubstanceDefinition|SubstanceDefinition": { + FromType: "Observation", + EdgeLabel: "focus_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|reason_reference_SubstanceDefinition|MedicationAdministration": { + "SubstanceDefinition|focus_SubstanceDefinition|Observation": { FromType: "SubstanceDefinition", - EdgeLabel: "reason_reference_SubstanceDefinition", - ToType: "MedicationAdministration", + EdgeLabel: "focus_SubstanceDefinition", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "MedicationAdministration|reason_reference_Specimen|Specimen": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_Specimen", + "Observation|focus_Specimen|Specimen": { + FromType: "Observation", + EdgeLabel: "focus_Specimen", ToType: "Specimen", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Specimen/*", }, }, - "Specimen|reason_reference_Specimen|MedicationAdministration": { + "Specimen|focus_Specimen|Observation": { FromType: "Specimen", - EdgeLabel: "reason_reference_Specimen", - ToType: "MedicationAdministration", + EdgeLabel: "focus_Specimen", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Specimen/*", }, }, - "MedicationAdministration|reason_reference_Observation|Observation": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_Observation", + "Observation|focus_Observation|Observation": { + FromType: "Observation", + EdgeLabel: "focus_Observation", ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Observation/*", }, }, - "Observation|reason_reference_Observation|MedicationAdministration": { + "Observation|focus_DiagnosticReport|DiagnosticReport": { FromType: "Observation", - EdgeLabel: "reason_reference_Observation", - ToType: "MedicationAdministration", + EdgeLabel: "focus_DiagnosticReport", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ - "Observation/*", + "DiagnosticReport/*", }, }, - "MedicationAdministration|reason_reference_DiagnosticReport|DiagnosticReport": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_DiagnosticReport", - ToType: "DiagnosticReport", + "DiagnosticReport|focus_DiagnosticReport|Observation": { + FromType: "DiagnosticReport", + EdgeLabel: "focus_DiagnosticReport", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "DiagnosticReport|reason_reference_DiagnosticReport|MedicationAdministration": { - FromType: "DiagnosticReport", - EdgeLabel: "reason_reference_DiagnosticReport", - ToType: "MedicationAdministration", + "Observation|focus_Condition|Condition": { + FromType: "Observation", + EdgeLabel: "focus_Condition", + ToType: "Condition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Condition/*", }, }, - "MedicationAdministration|reason_reference_Condition|Condition": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_Condition", - ToType: "Condition", + "Condition|focus_Condition|Observation": { + FromType: "Condition", + EdgeLabel: "focus_Condition", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Condition/*", }, }, - "Condition|reason_reference_Condition|MedicationAdministration": { - FromType: "Condition", - EdgeLabel: "reason_reference_Condition", - ToType: "MedicationAdministration", + "Observation|focus_Medication|Medication": { + FromType: "Observation", + EdgeLabel: "focus_Medication", + ToType: "Medication", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ - "Condition/*", + "Medication/*", }, }, - "MedicationAdministration|reason_reference_Medication|Medication": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_Medication", - ToType: "Medication", + "Medication|focus_Medication|Observation": { + FromType: "Medication", + EdgeLabel: "focus_Medication", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Medication/*", }, }, - "Medication|reason_reference_Medication|MedicationAdministration": { - FromType: "Medication", - EdgeLabel: "reason_reference_Medication", + "Observation|focus_MedicationAdministration|MedicationAdministration": { + FromType: "Observation", + EdgeLabel: "focus_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ - "Medication/*", + "MedicationAdministration/*", }, }, - "MedicationAdministration|reason_reference_MedicationAdministration|MedicationAdministration": { + "MedicationAdministration|focus_MedicationAdministration|Observation": { FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_MedicationAdministration", - ToType: "MedicationAdministration", + EdgeLabel: "focus_MedicationAdministration", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "MedicationAdministration|reason_reference_MedicationStatement|MedicationStatement": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_MedicationStatement", + "Observation|focus_MedicationStatement|MedicationStatement": { + FromType: "Observation", + EdgeLabel: "focus_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "MedicationStatement|reason_reference_MedicationStatement|MedicationAdministration": { + "MedicationStatement|focus_MedicationStatement|Observation": { FromType: "MedicationStatement", - EdgeLabel: "reason_reference_MedicationStatement", - ToType: "MedicationAdministration", + EdgeLabel: "focus_MedicationStatement", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "MedicationAdministration|reason_reference_MedicationRequest|MedicationRequest": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_MedicationRequest", + "Observation|focus_MedicationRequest|MedicationRequest": { + FromType: "Observation", + EdgeLabel: "focus_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "MedicationRequest|reason_reference_MedicationRequest|MedicationAdministration": { + "MedicationRequest|focus_MedicationRequest|Observation": { FromType: "MedicationRequest", - EdgeLabel: "reason_reference_MedicationRequest", - ToType: "MedicationAdministration", + EdgeLabel: "focus_MedicationRequest", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "MedicationAdministration|reason_reference_Procedure|Procedure": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_Procedure", + "Observation|focus_Procedure|Procedure": { + FromType: "Observation", + EdgeLabel: "focus_Procedure", ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Procedure/*", }, }, - "Procedure|reason_reference_Procedure|MedicationAdministration": { + "Procedure|focus_Procedure|Observation": { FromType: "Procedure", - EdgeLabel: "reason_reference_Procedure", - ToType: "MedicationAdministration", + EdgeLabel: "focus_Procedure", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Procedure/*", }, }, - "MedicationAdministration|reason_reference_DocumentReference|DocumentReference": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_DocumentReference", + "Observation|focus_DocumentReference|DocumentReference": { + FromType: "Observation", + EdgeLabel: "focus_DocumentReference", ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "DocumentReference/*", }, }, - "DocumentReference|reason_reference_DocumentReference|MedicationAdministration": { + "DocumentReference|focus_DocumentReference|Observation": { FromType: "DocumentReference", - EdgeLabel: "reason_reference_DocumentReference", - ToType: "MedicationAdministration", + EdgeLabel: "focus_DocumentReference", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "DocumentReference/*", }, }, - "MedicationAdministration|reason_reference_Task|Task": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_Task", + "Observation|focus_Task|Task": { + FromType: "Observation", + EdgeLabel: "focus_Task", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Task/*", }, }, - "Task|reason_reference_Task|MedicationAdministration": { + "Task|focus_Task|Observation": { FromType: "Task", - EdgeLabel: "reason_reference_Task", - ToType: "MedicationAdministration", + EdgeLabel: "focus_Task", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "Task/*", }, }, - "MedicationAdministration|reason_reference_ImagingStudy|ImagingStudy": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_ImagingStudy", + "Observation|focus_ImagingStudy|ImagingStudy": { + FromType: "Observation", + EdgeLabel: "focus_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "ImagingStudy/*", }, }, - "ImagingStudy|reason_reference_ImagingStudy|MedicationAdministration": { + "ImagingStudy|focus_ImagingStudy|Observation": { FromType: "ImagingStudy", - EdgeLabel: "reason_reference_ImagingStudy", - ToType: "MedicationAdministration", + EdgeLabel: "focus_ImagingStudy", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "ImagingStudy/*", }, }, - "MedicationAdministration|reason_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_FamilyMemberHistory", + "Observation|focus_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "Observation", + EdgeLabel: "focus_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|reason_reference_FamilyMemberHistory|MedicationAdministration": { + "FamilyMemberHistory|focus_FamilyMemberHistory|Observation": { FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_FamilyMemberHistory", - ToType: "MedicationAdministration", + EdgeLabel: "focus_FamilyMemberHistory", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "FamilyMemberHistory/*", }, }, - "MedicationAdministration|reason_reference_BodyStructure|BodyStructure": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_BodyStructure", + "Observation|focus_BodyStructure|BodyStructure": { + FromType: "Observation", + EdgeLabel: "focus_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "BodyStructure/*", }, }, - "BodyStructure|reason_reference_BodyStructure|MedicationAdministration": { + "BodyStructure|focus_BodyStructure|Observation": { FromType: "BodyStructure", - EdgeLabel: "reason_reference_BodyStructure", - ToType: "MedicationAdministration", + EdgeLabel: "focus_BodyStructure", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "focus_observation", }, RegexMatch: []string{ "BodyStructure/*", }, }, - "MedicationAdministrationPerformer|actor_reference_Organization|Organization": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_Organization", - ToType: "Organization", + "Observation|hasMember_Observation|Observation": { + FromType: "Observation", + EdgeLabel: "hasMember_Observation", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "hasMember_observation", }, RegexMatch: []string{ - "Organization/*", + "Observation/*", }, }, - "Organization|actor_reference_Organization|MedicationAdministrationPerformer": { - FromType: "Organization", - EdgeLabel: "actor_reference_Organization", - ToType: "MedicationAdministrationPerformer", + "Observation|partOf_MedicationAdministration|MedicationAdministration": { + FromType: "Observation", + EdgeLabel: "partOf_MedicationAdministration", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "partOf_observation", }, RegexMatch: []string{ - "Organization/*", + "MedicationAdministration/*", }, }, - "MedicationAdministrationPerformer|actor_reference_Group|Group": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_Group", - ToType: "Group", + "MedicationAdministration|partOf_MedicationAdministration|Observation": { + FromType: "MedicationAdministration", + EdgeLabel: "partOf_MedicationAdministration", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "partOf_observation", }, RegexMatch: []string{ - "Group/*", + "MedicationAdministration/*", }, }, - "Group|actor_reference_Group|MedicationAdministrationPerformer": { - FromType: "Group", - EdgeLabel: "actor_reference_Group", - ToType: "MedicationAdministrationPerformer", + "Observation|partOf_MedicationStatement|MedicationStatement": { + FromType: "Observation", + EdgeLabel: "partOf_MedicationStatement", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "partOf_observation", }, RegexMatch: []string{ - "Group/*", + "MedicationStatement/*", }, }, - "MedicationAdministrationPerformer|actor_reference_Practitioner|Practitioner": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_Practitioner", - ToType: "Practitioner", + "MedicationStatement|partOf_MedicationStatement|Observation": { + FromType: "MedicationStatement", + EdgeLabel: "partOf_MedicationStatement", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "partOf_observation", }, RegexMatch: []string{ - "Practitioner/*", + "MedicationStatement/*", }, }, - "Practitioner|actor_reference_Practitioner|MedicationAdministrationPerformer": { - FromType: "Practitioner", - EdgeLabel: "actor_reference_Practitioner", - ToType: "MedicationAdministrationPerformer", + "Observation|partOf_Procedure|Procedure": { + FromType: "Observation", + EdgeLabel: "partOf_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "partOf_observation", }, RegexMatch: []string{ - "Practitioner/*", + "Procedure/*", }, }, - "MedicationAdministrationPerformer|actor_reference_PractitionerRole|PractitionerRole": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_PractitionerRole", - ToType: "PractitionerRole", + "Procedure|partOf_Procedure|Observation": { + FromType: "Procedure", + EdgeLabel: "partOf_Procedure", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "partOf_observation", }, RegexMatch: []string{ - "PractitionerRole/*", + "Procedure/*", }, }, - "PractitionerRole|actor_reference_PractitionerRole|MedicationAdministrationPerformer": { - FromType: "PractitionerRole", - EdgeLabel: "actor_reference_PractitionerRole", - ToType: "MedicationAdministrationPerformer", + "Observation|partOf_ImagingStudy|ImagingStudy": { + FromType: "Observation", + EdgeLabel: "partOf_ImagingStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "partOf_observation", }, RegexMatch: []string{ - "PractitionerRole/*", + "ImagingStudy/*", }, }, - "MedicationAdministrationPerformer|actor_reference_ResearchStudy|ResearchStudy": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|actor_reference_ResearchStudy|MedicationAdministrationPerformer": { - FromType: "ResearchStudy", - EdgeLabel: "actor_reference_ResearchStudy", - ToType: "MedicationAdministrationPerformer", + "ImagingStudy|partOf_ImagingStudy|Observation": { + FromType: "ImagingStudy", + EdgeLabel: "partOf_ImagingStudy", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "partOf_observation", }, RegexMatch: []string{ - "ResearchStudy/*", + "ImagingStudy/*", }, }, - "MedicationAdministrationPerformer|actor_reference_Patient|Patient": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_Patient", - ToType: "Patient", + "Observation|performer_Practitioner|Practitioner": { + FromType: "Observation", + EdgeLabel: "performer_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "performer_observation", }, RegexMatch: []string{ - "Patient/*", + "Practitioner/*", }, }, - "Patient|actor_reference_Patient|MedicationAdministrationPerformer": { - FromType: "Patient", - EdgeLabel: "actor_reference_Patient", - ToType: "MedicationAdministrationPerformer", + "Practitioner|performer_Practitioner|Observation": { + FromType: "Practitioner", + EdgeLabel: "performer_Practitioner", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "performer_observation", }, RegexMatch: []string{ - "Patient/*", + "Practitioner/*", }, }, - "MedicationAdministrationPerformer|actor_reference_ResearchSubject|ResearchSubject": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_ResearchSubject", - ToType: "ResearchSubject", + "Observation|performer_PractitionerRole|PractitionerRole": { + FromType: "Observation", + EdgeLabel: "performer_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "performer_observation", }, RegexMatch: []string{ - "ResearchSubject/*", + "PractitionerRole/*", }, }, - "ResearchSubject|actor_reference_ResearchSubject|MedicationAdministrationPerformer": { - FromType: "ResearchSubject", - EdgeLabel: "actor_reference_ResearchSubject", - ToType: "MedicationAdministrationPerformer", + "PractitionerRole|performer_PractitionerRole|Observation": { + FromType: "PractitionerRole", + EdgeLabel: "performer_PractitionerRole", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "performer_observation", }, RegexMatch: []string{ - "ResearchSubject/*", + "PractitionerRole/*", }, }, - "MedicationAdministrationPerformer|actor_reference_Substance|Substance": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_Substance", - ToType: "Substance", + "Observation|performer_Organization|Organization": { + FromType: "Observation", + EdgeLabel: "performer_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "performer_observation", }, RegexMatch: []string{ - "Substance/*", + "Organization/*", }, }, - "Substance|actor_reference_Substance|MedicationAdministrationPerformer": { - FromType: "Substance", - EdgeLabel: "actor_reference_Substance", - ToType: "MedicationAdministrationPerformer", + "Organization|performer_Organization|Observation": { + FromType: "Organization", + EdgeLabel: "performer_Organization", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "performer_observation", }, RegexMatch: []string{ - "Substance/*", + "Organization/*", }, }, - "MedicationAdministrationPerformer|actor_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_SubstanceDefinition", - ToType: "SubstanceDefinition", + "Observation|performer_Patient|Patient": { + FromType: "Observation", + EdgeLabel: "performer_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "performer_observation", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "Patient/*", }, }, - "SubstanceDefinition|actor_reference_SubstanceDefinition|MedicationAdministrationPerformer": { - FromType: "SubstanceDefinition", - EdgeLabel: "actor_reference_SubstanceDefinition", - ToType: "MedicationAdministrationPerformer", + "Patient|performer_Patient|Observation": { + FromType: "Patient", + EdgeLabel: "performer_Patient", + ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "performer_observation", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "Patient/*", }, }, - "MedicationAdministrationPerformer|actor_reference_Specimen|Specimen": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_Specimen", + "Observation|specimen_Specimen|Specimen": { + FromType: "Observation", + EdgeLabel: "specimen_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -33146,16 +32846,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "specimen_observation", }, RegexMatch: []string{ "Specimen/*", }, }, - "Specimen|actor_reference_Specimen|MedicationAdministrationPerformer": { + "Specimen|specimen_Specimen|Observation": { FromType: "Specimen", - EdgeLabel: "actor_reference_Specimen", - ToType: "MedicationAdministrationPerformer", + EdgeLabel: "specimen_Specimen", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -33163,16 +32863,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "specimen_observation", }, RegexMatch: []string{ "Specimen/*", }, }, - "MedicationAdministrationPerformer|actor_reference_Observation|Observation": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_Observation", - ToType: "Observation", + "Observation|specimen_Group|Group": { + FromType: "Observation", + EdgeLabel: "specimen_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -33180,16 +32880,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "specimen_observation", }, RegexMatch: []string{ - "Observation/*", + "Group/*", }, }, - "Observation|actor_reference_Observation|MedicationAdministrationPerformer": { - FromType: "Observation", - EdgeLabel: "actor_reference_Observation", - ToType: "MedicationAdministrationPerformer", + "Group|specimen_Group|Observation": { + FromType: "Group", + EdgeLabel: "specimen_Group", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -33197,16 +32897,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "specimen_observation", }, RegexMatch: []string{ - "Observation/*", + "Group/*", }, }, - "MedicationAdministrationPerformer|actor_reference_DiagnosticReport|DiagnosticReport": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_DiagnosticReport", - ToType: "DiagnosticReport", + "Observation|subject_Patient|Patient": { + FromType: "Observation", + EdgeLabel: "subject_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -33214,16 +32914,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_observation", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Patient/*", }, }, - "DiagnosticReport|actor_reference_DiagnosticReport|MedicationAdministrationPerformer": { - FromType: "DiagnosticReport", - EdgeLabel: "actor_reference_DiagnosticReport", - ToType: "MedicationAdministrationPerformer", + "Patient|subject_Patient|Observation": { + FromType: "Patient", + EdgeLabel: "subject_Patient", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -33231,16 +32931,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_observation", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Patient/*", }, }, - "MedicationAdministrationPerformer|actor_reference_Condition|Condition": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_Condition", - ToType: "Condition", + "Observation|subject_Group|Group": { + FromType: "Observation", + EdgeLabel: "subject_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -33248,16 +32948,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_observation", }, RegexMatch: []string{ - "Condition/*", + "Group/*", }, }, - "Condition|actor_reference_Condition|MedicationAdministrationPerformer": { - FromType: "Condition", - EdgeLabel: "actor_reference_Condition", - ToType: "MedicationAdministrationPerformer", + "Group|subject_Group|Observation": { + FromType: "Group", + EdgeLabel: "subject_Group", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -33265,16 +32965,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_observation", }, RegexMatch: []string{ - "Condition/*", + "Group/*", }, }, - "MedicationAdministrationPerformer|actor_reference_Medication|Medication": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_Medication", - ToType: "Medication", + "Observation|subject_Organization|Organization": { + FromType: "Observation", + EdgeLabel: "subject_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -33282,16 +32982,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_observation", }, RegexMatch: []string{ - "Medication/*", + "Organization/*", }, }, - "Medication|actor_reference_Medication|MedicationAdministrationPerformer": { - FromType: "Medication", - EdgeLabel: "actor_reference_Medication", - ToType: "MedicationAdministrationPerformer", + "Organization|subject_Organization|Observation": { + FromType: "Organization", + EdgeLabel: "subject_Organization", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -33299,16 +32999,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_observation", }, RegexMatch: []string{ - "Medication/*", + "Organization/*", }, }, - "MedicationAdministrationPerformer|actor_reference_MedicationAdministration|MedicationAdministration": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_MedicationAdministration", - ToType: "MedicationAdministration", + "Observation|subject_Procedure|Procedure": { + FromType: "Observation", + EdgeLabel: "subject_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -33316,16 +33016,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_observation", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Procedure/*", }, }, - "MedicationAdministration|actor_reference_MedicationAdministration|MedicationAdministrationPerformer": { - FromType: "MedicationAdministration", - EdgeLabel: "actor_reference_MedicationAdministration", - ToType: "MedicationAdministrationPerformer", + "Procedure|subject_Procedure|Observation": { + FromType: "Procedure", + EdgeLabel: "subject_Procedure", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -33333,16 +33033,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_observation", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Procedure/*", }, }, - "MedicationAdministrationPerformer|actor_reference_MedicationStatement|MedicationStatement": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_MedicationStatement", - ToType: "MedicationStatement", + "Observation|subject_Practitioner|Practitioner": { + FromType: "Observation", + EdgeLabel: "subject_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -33350,16 +33050,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_observation", }, RegexMatch: []string{ - "MedicationStatement/*", + "Practitioner/*", }, }, - "MedicationStatement|actor_reference_MedicationStatement|MedicationAdministrationPerformer": { - FromType: "MedicationStatement", - EdgeLabel: "actor_reference_MedicationStatement", - ToType: "MedicationAdministrationPerformer", + "Practitioner|subject_Practitioner|Observation": { + FromType: "Practitioner", + EdgeLabel: "subject_Practitioner", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -33367,16 +33067,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_observation", }, RegexMatch: []string{ - "MedicationStatement/*", + "Practitioner/*", }, }, - "MedicationAdministrationPerformer|actor_reference_MedicationRequest|MedicationRequest": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_MedicationRequest", - ToType: "MedicationRequest", + "Observation|subject_Medication|Medication": { + FromType: "Observation", + EdgeLabel: "subject_Medication", + ToType: "Medication", Direction: []string{ "outbound", }, @@ -33384,16 +33084,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_observation", }, RegexMatch: []string{ - "MedicationRequest/*", + "Medication/*", }, }, - "MedicationRequest|actor_reference_MedicationRequest|MedicationAdministrationPerformer": { - FromType: "MedicationRequest", - EdgeLabel: "actor_reference_MedicationRequest", - ToType: "MedicationAdministrationPerformer", + "Medication|subject_Medication|Observation": { + FromType: "Medication", + EdgeLabel: "subject_Medication", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -33401,16 +33101,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_observation", }, RegexMatch: []string{ - "MedicationRequest/*", + "Medication/*", }, }, - "MedicationAdministrationPerformer|actor_reference_Procedure|Procedure": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_Procedure", - ToType: "Procedure", + "Observation|subject_Substance|Substance": { + FromType: "Observation", + EdgeLabel: "subject_Substance", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -33418,16 +33118,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_observation", }, RegexMatch: []string{ - "Procedure/*", + "Substance/*", }, }, - "Procedure|actor_reference_Procedure|MedicationAdministrationPerformer": { - FromType: "Procedure", - EdgeLabel: "actor_reference_Procedure", - ToType: "MedicationAdministrationPerformer", + "Substance|subject_Substance|Observation": { + FromType: "Substance", + EdgeLabel: "subject_Substance", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -33435,16 +33135,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "subject_observation", }, RegexMatch: []string{ - "Procedure/*", + "Substance/*", }, }, - "MedicationAdministrationPerformer|actor_reference_DocumentReference|DocumentReference": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_DocumentReference", - ToType: "DocumentReference", + "Observation|note_authorReference_Practitioner|Practitioner": { + FromType: "Observation", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -33452,16 +33152,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "DocumentReference/*", + "Practitioner/*", }, }, - "DocumentReference|actor_reference_DocumentReference|MedicationAdministrationPerformer": { - FromType: "DocumentReference", - EdgeLabel: "actor_reference_DocumentReference", - ToType: "MedicationAdministrationPerformer", + "Practitioner|note_authorReference_Practitioner|Observation": { + FromType: "Practitioner", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -33469,16 +33169,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "DocumentReference/*", + "Practitioner/*", }, }, - "MedicationAdministrationPerformer|actor_reference_Task|Task": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_Task", - ToType: "Task", + "Observation|note_authorReference_PractitionerRole|PractitionerRole": { + FromType: "Observation", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -33486,16 +33186,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Task/*", + "PractitionerRole/*", }, }, - "Task|actor_reference_Task|MedicationAdministrationPerformer": { - FromType: "Task", - EdgeLabel: "actor_reference_Task", - ToType: "MedicationAdministrationPerformer", + "PractitionerRole|note_authorReference_PractitionerRole|Observation": { + FromType: "PractitionerRole", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -33503,16 +33203,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Task/*", + "PractitionerRole/*", }, }, - "MedicationAdministrationPerformer|actor_reference_ImagingStudy|ImagingStudy": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_ImagingStudy", - ToType: "ImagingStudy", + "Observation|note_authorReference_Patient|Patient": { + FromType: "Observation", + EdgeLabel: "note_authorReference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -33520,16 +33220,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "ImagingStudy/*", + "Patient/*", }, }, - "ImagingStudy|actor_reference_ImagingStudy|MedicationAdministrationPerformer": { - FromType: "ImagingStudy", - EdgeLabel: "actor_reference_ImagingStudy", - ToType: "MedicationAdministrationPerformer", + "Patient|note_authorReference_Patient|Observation": { + FromType: "Patient", + EdgeLabel: "note_authorReference_Patient", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -33537,16 +33237,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "ImagingStudy/*", + "Patient/*", }, }, - "MedicationAdministrationPerformer|actor_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", + "Observation|note_authorReference_Organization|Organization": { + FromType: "Observation", + EdgeLabel: "note_authorReference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -33554,16 +33254,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Organization/*", }, }, - "FamilyMemberHistory|actor_reference_FamilyMemberHistory|MedicationAdministrationPerformer": { - FromType: "FamilyMemberHistory", - EdgeLabel: "actor_reference_FamilyMemberHistory", - ToType: "MedicationAdministrationPerformer", + "Organization|note_authorReference_Organization|Observation": { + FromType: "Organization", + EdgeLabel: "note_authorReference_Organization", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -33571,16 +33271,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Organization/*", }, }, - "MedicationAdministrationPerformer|actor_reference_BodyStructure|BodyStructure": { - FromType: "MedicationAdministrationPerformer", - EdgeLabel: "actor_reference_BodyStructure", - ToType: "BodyStructure", + "Observation|triggeredBy_observation|Observation": { + FromType: "Observation", + EdgeLabel: "triggeredBy_observation", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -33588,16 +33288,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "observation_triggered_by", }, RegexMatch: []string{ - "BodyStructure/*", + "Observation/*", }, }, - "BodyStructure|actor_reference_BodyStructure|MedicationAdministrationPerformer": { - FromType: "BodyStructure", - EdgeLabel: "actor_reference_BodyStructure", - ToType: "MedicationAdministrationPerformer", + "Organization|partOf|Organization": { + FromType: "Organization", + EdgeLabel: "partOf", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -33605,15 +33305,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "organization", }, RegexMatch: []string{ - "BodyStructure/*", + "Organization/*", }, }, - "MedicationIngredient|item_reference_Organization|Organization": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_Organization", + "Organization|contact_organization|Organization": { + FromType: "Organization", + EdgeLabel: "contact_organization", ToType: "Organization", Direction: []string{ "outbound", @@ -33622,16 +33322,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "extended_contact_detail", }, RegexMatch: []string{ "Organization/*", }, }, - "Organization|item_reference_Organization|MedicationIngredient": { + "Organization|qualification_issuer|Organization": { FromType: "Organization", - EdgeLabel: "item_reference_Organization", - ToType: "MedicationIngredient", + EdgeLabel: "qualification_issuer", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -33639,118 +33339,118 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "organization_qualification", }, RegexMatch: []string{ "Organization/*", }, }, - "MedicationIngredient|item_reference_Group|Group": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_Group", - ToType: "Group", + "Patient|generalPractitioner_Organization|Organization": { + FromType: "Patient", + EdgeLabel: "generalPractitioner_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "generalPractitioner_patient", }, RegexMatch: []string{ - "Group/*", + "Organization/*", }, }, - "Group|item_reference_Group|MedicationIngredient": { - FromType: "Group", - EdgeLabel: "item_reference_Group", - ToType: "MedicationIngredient", + "Organization|generalPractitioner_Organization|Patient": { + FromType: "Organization", + EdgeLabel: "generalPractitioner_Organization", + ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "generalPractitioner_patient", }, RegexMatch: []string{ - "Group/*", + "Organization/*", }, }, - "MedicationIngredient|item_reference_Practitioner|Practitioner": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_Practitioner", + "Patient|generalPractitioner_Practitioner|Practitioner": { + FromType: "Patient", + EdgeLabel: "generalPractitioner_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "generalPractitioner_patient", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Practitioner|item_reference_Practitioner|MedicationIngredient": { + "Practitioner|generalPractitioner_Practitioner|Patient": { FromType: "Practitioner", - EdgeLabel: "item_reference_Practitioner", - ToType: "MedicationIngredient", + EdgeLabel: "generalPractitioner_Practitioner", + ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "generalPractitioner_patient", }, RegexMatch: []string{ "Practitioner/*", }, }, - "MedicationIngredient|item_reference_PractitionerRole|PractitionerRole": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_PractitionerRole", + "Patient|generalPractitioner_PractitionerRole|PractitionerRole": { + FromType: "Patient", + EdgeLabel: "generalPractitioner_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "generalPractitioner_patient", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "PractitionerRole|item_reference_PractitionerRole|MedicationIngredient": { + "PractitionerRole|generalPractitioner_PractitionerRole|Patient": { FromType: "PractitionerRole", - EdgeLabel: "item_reference_PractitionerRole", - ToType: "MedicationIngredient", + EdgeLabel: "generalPractitioner_PractitionerRole", + ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "generalPractitioner_patient", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "MedicationIngredient|item_reference_ResearchStudy|ResearchStudy": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_ResearchStudy", - ToType: "ResearchStudy", + "Patient|managingOrganization|Organization": { + FromType: "Patient", + EdgeLabel: "managingOrganization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -33758,16 +33458,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "managingOrganization_patient", }, RegexMatch: []string{ - "ResearchStudy/*", + "Organization/*", }, }, - "ResearchStudy|item_reference_ResearchStudy|MedicationIngredient": { - FromType: "ResearchStudy", - EdgeLabel: "item_reference_ResearchStudy", - ToType: "MedicationIngredient", + "Organization|managingOrganization|Patient": { + FromType: "Organization", + EdgeLabel: "managingOrganization", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -33775,16 +33475,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "managingOrganization_patient", }, RegexMatch: []string{ - "ResearchStudy/*", + "Organization/*", }, }, - "MedicationIngredient|item_reference_Patient|Patient": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_Patient", - ToType: "Patient", + "Patient|contact_organization|Organization": { + FromType: "Patient", + EdgeLabel: "contact_organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -33792,16 +33492,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "patient_contact", }, RegexMatch: []string{ - "Patient/*", + "Organization/*", }, }, - "Patient|item_reference_Patient|MedicationIngredient": { - FromType: "Patient", - EdgeLabel: "item_reference_Patient", - ToType: "MedicationIngredient", + "Organization|contact_organization|Patient": { + FromType: "Organization", + EdgeLabel: "contact_organization", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -33809,16 +33509,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "patient_contact", }, RegexMatch: []string{ - "Patient/*", + "Organization/*", }, }, - "MedicationIngredient|item_reference_ResearchSubject|ResearchSubject": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_ResearchSubject", - ToType: "ResearchSubject", + "Patient|link_other_Patient|Patient": { + FromType: "Patient", + EdgeLabel: "link_other_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -33826,16 +33526,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "patient_link", }, RegexMatch: []string{ - "ResearchSubject/*", + "Patient/*", }, }, - "ResearchSubject|item_reference_ResearchSubject|MedicationIngredient": { - FromType: "ResearchSubject", - EdgeLabel: "item_reference_ResearchSubject", - ToType: "MedicationIngredient", + "Practitioner|qualification_issuer|Organization": { + FromType: "Practitioner", + EdgeLabel: "qualification_issuer", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -33843,16 +33543,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "practitioner_qualification", }, RegexMatch: []string{ - "ResearchSubject/*", + "Organization/*", }, }, - "MedicationIngredient|item_reference_Substance|Substance": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_Substance", - ToType: "Substance", + "Organization|qualification_issuer|Practitioner": { + FromType: "Organization", + EdgeLabel: "qualification_issuer", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -33860,16 +33560,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "practitioner_qualification", }, RegexMatch: []string{ - "Substance/*", + "Organization/*", }, }, - "Substance|item_reference_Substance|MedicationIngredient": { - FromType: "Substance", - EdgeLabel: "item_reference_Substance", - ToType: "MedicationIngredient", + "PractitionerRole|organization|Organization": { + FromType: "PractitionerRole", + EdgeLabel: "organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -33877,16 +33577,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "practitioner_role", }, RegexMatch: []string{ - "Substance/*", + "Organization/*", }, }, - "MedicationIngredient|item_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_SubstanceDefinition", - ToType: "SubstanceDefinition", + "Organization|organization|PractitionerRole": { + FromType: "Organization", + EdgeLabel: "organization", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -33894,16 +33594,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "practitioner_role", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "Organization/*", }, }, - "SubstanceDefinition|item_reference_SubstanceDefinition|MedicationIngredient": { - FromType: "SubstanceDefinition", - EdgeLabel: "item_reference_SubstanceDefinition", - ToType: "MedicationIngredient", + "PractitionerRole|practitioner|Practitioner": { + FromType: "PractitionerRole", + EdgeLabel: "practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -33911,16 +33611,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "practitioner_role", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "Practitioner/*", }, }, - "MedicationIngredient|item_reference_Specimen|Specimen": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_Specimen", - ToType: "Specimen", + "Practitioner|practitioner|PractitionerRole": { + FromType: "Practitioner", + EdgeLabel: "practitioner", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -33928,16 +33628,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "practitioner_role", }, RegexMatch: []string{ - "Specimen/*", + "Practitioner/*", }, }, - "Specimen|item_reference_Specimen|MedicationIngredient": { - FromType: "Specimen", - EdgeLabel: "item_reference_Specimen", - ToType: "MedicationIngredient", + "PractitionerRole|contact_organization|Organization": { + FromType: "PractitionerRole", + EdgeLabel: "contact_organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -33945,16 +33645,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "extended_contact_detail", }, RegexMatch: []string{ - "Specimen/*", + "Organization/*", }, }, - "MedicationIngredient|item_reference_Observation|Observation": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_Observation", - ToType: "Observation", + "Organization|contact_organization|PractitionerRole": { + FromType: "Organization", + EdgeLabel: "contact_organization", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -33962,16 +33662,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "extended_contact_detail", }, RegexMatch: []string{ - "Observation/*", + "Organization/*", }, }, - "Observation|item_reference_Observation|MedicationIngredient": { - FromType: "Observation", - EdgeLabel: "item_reference_Observation", - ToType: "MedicationIngredient", + "Procedure|focus_Patient|Patient": { + FromType: "Procedure", + EdgeLabel: "focus_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -33979,16 +33679,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "focus_procedure", }, RegexMatch: []string{ - "Observation/*", + "Patient/*", }, }, - "MedicationIngredient|item_reference_DiagnosticReport|DiagnosticReport": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_DiagnosticReport", - ToType: "DiagnosticReport", + "Patient|focus_Patient|Procedure": { + FromType: "Patient", + EdgeLabel: "focus_Patient", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -33996,16 +33696,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "focus_procedure", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Patient/*", }, }, - "DiagnosticReport|item_reference_DiagnosticReport|MedicationIngredient": { - FromType: "DiagnosticReport", - EdgeLabel: "item_reference_DiagnosticReport", - ToType: "MedicationIngredient", + "Procedure|focus_Group|Group": { + FromType: "Procedure", + EdgeLabel: "focus_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -34013,16 +33713,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "focus_procedure", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Group/*", }, }, - "MedicationIngredient|item_reference_Condition|Condition": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_Condition", - ToType: "Condition", + "Group|focus_Group|Procedure": { + FromType: "Group", + EdgeLabel: "focus_Group", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -34030,16 +33730,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "focus_procedure", }, RegexMatch: []string{ - "Condition/*", + "Group/*", }, }, - "Condition|item_reference_Condition|MedicationIngredient": { - FromType: "Condition", - EdgeLabel: "item_reference_Condition", - ToType: "MedicationIngredient", + "Procedure|focus_Practitioner|Practitioner": { + FromType: "Procedure", + EdgeLabel: "focus_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -34047,16 +33747,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "focus_procedure", }, RegexMatch: []string{ - "Condition/*", + "Practitioner/*", }, }, - "MedicationIngredient|item_reference_Medication|Medication": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_Medication", - ToType: "Medication", + "Practitioner|focus_Practitioner|Procedure": { + FromType: "Practitioner", + EdgeLabel: "focus_Practitioner", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -34064,16 +33764,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "focus_procedure", }, RegexMatch: []string{ - "Medication/*", + "Practitioner/*", }, }, - "Medication|item_reference_Medication|MedicationIngredient": { - FromType: "Medication", - EdgeLabel: "item_reference_Medication", - ToType: "MedicationIngredient", + "Procedure|focus_Organization|Organization": { + FromType: "Procedure", + EdgeLabel: "focus_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -34081,16 +33781,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "focus_procedure", }, RegexMatch: []string{ - "Medication/*", + "Organization/*", }, }, - "MedicationIngredient|item_reference_MedicationAdministration|MedicationAdministration": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_MedicationAdministration", - ToType: "MedicationAdministration", + "Organization|focus_Organization|Procedure": { + FromType: "Organization", + EdgeLabel: "focus_Organization", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -34098,16 +33798,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "focus_procedure", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Organization/*", }, }, - "MedicationAdministration|item_reference_MedicationAdministration|MedicationIngredient": { - FromType: "MedicationAdministration", - EdgeLabel: "item_reference_MedicationAdministration", - ToType: "MedicationIngredient", + "Procedure|focus_PractitionerRole|PractitionerRole": { + FromType: "Procedure", + EdgeLabel: "focus_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -34115,16 +33815,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "focus_procedure", }, RegexMatch: []string{ - "MedicationAdministration/*", + "PractitionerRole/*", }, }, - "MedicationIngredient|item_reference_MedicationStatement|MedicationStatement": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_MedicationStatement", - ToType: "MedicationStatement", + "PractitionerRole|focus_PractitionerRole|Procedure": { + FromType: "PractitionerRole", + EdgeLabel: "focus_PractitionerRole", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -34132,16 +33832,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "focus_procedure", }, RegexMatch: []string{ - "MedicationStatement/*", + "PractitionerRole/*", }, }, - "MedicationStatement|item_reference_MedicationStatement|MedicationIngredient": { - FromType: "MedicationStatement", - EdgeLabel: "item_reference_MedicationStatement", - ToType: "MedicationIngredient", + "Procedure|focus_Specimen|Specimen": { + FromType: "Procedure", + EdgeLabel: "focus_Specimen", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -34149,16 +33849,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "focus_procedure", }, RegexMatch: []string{ - "MedicationStatement/*", + "Specimen/*", }, }, - "MedicationIngredient|item_reference_MedicationRequest|MedicationRequest": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_MedicationRequest", - ToType: "MedicationRequest", + "Specimen|focus_Specimen|Procedure": { + FromType: "Specimen", + EdgeLabel: "focus_Specimen", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -34166,84 +33866,101 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "focus_procedure", }, RegexMatch: []string{ - "MedicationRequest/*", + "Specimen/*", }, }, - "MedicationRequest|item_reference_MedicationRequest|MedicationIngredient": { - FromType: "MedicationRequest", - EdgeLabel: "item_reference_MedicationRequest", - ToType: "MedicationIngredient", + "Procedure|partOf_Procedure|Procedure": { + FromType: "Procedure", + EdgeLabel: "partOf_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "partOf_procedure", }, RegexMatch: []string{ - "MedicationRequest/*", + "Procedure/*", + }, + }, + "Procedure|partOf_Observation|Observation": { + FromType: "Procedure", + EdgeLabel: "partOf_Observation", + ToType: "Observation", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_many", + }, + Backref: []string{ + "partOf_procedure", + }, + RegexMatch: []string{ + "Observation/*", }, }, - "MedicationIngredient|item_reference_Procedure|Procedure": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_Procedure", + "Observation|partOf_Observation|Procedure": { + FromType: "Observation", + EdgeLabel: "partOf_Observation", ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "partOf_procedure", }, RegexMatch: []string{ - "Procedure/*", + "Observation/*", }, }, - "Procedure|item_reference_Procedure|MedicationIngredient": { + "Procedure|partOf_MedicationAdministration|MedicationAdministration": { FromType: "Procedure", - EdgeLabel: "item_reference_Procedure", - ToType: "MedicationIngredient", + EdgeLabel: "partOf_MedicationAdministration", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "partOf_procedure", }, RegexMatch: []string{ - "Procedure/*", + "MedicationAdministration/*", }, }, - "MedicationIngredient|item_reference_DocumentReference|DocumentReference": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_DocumentReference", - ToType: "DocumentReference", + "MedicationAdministration|partOf_MedicationAdministration|Procedure": { + FromType: "MedicationAdministration", + EdgeLabel: "partOf_MedicationAdministration", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "partOf_procedure", }, RegexMatch: []string{ - "DocumentReference/*", + "MedicationAdministration/*", }, }, - "DocumentReference|item_reference_DocumentReference|MedicationIngredient": { - FromType: "DocumentReference", - EdgeLabel: "item_reference_DocumentReference", - ToType: "MedicationIngredient", + "Procedure|recorder_Patient|Patient": { + FromType: "Procedure", + EdgeLabel: "recorder_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -34251,16 +33968,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "recorder_procedure", }, RegexMatch: []string{ - "DocumentReference/*", + "Patient/*", }, }, - "MedicationIngredient|item_reference_Task|Task": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_Task", - ToType: "Task", + "Patient|recorder_Patient|Procedure": { + FromType: "Patient", + EdgeLabel: "recorder_Patient", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -34268,16 +33985,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "recorder_procedure", }, RegexMatch: []string{ - "Task/*", + "Patient/*", }, }, - "Task|item_reference_Task|MedicationIngredient": { - FromType: "Task", - EdgeLabel: "item_reference_Task", - ToType: "MedicationIngredient", + "Procedure|recorder_Practitioner|Practitioner": { + FromType: "Procedure", + EdgeLabel: "recorder_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -34285,16 +34002,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "recorder_procedure", }, RegexMatch: []string{ - "Task/*", + "Practitioner/*", }, }, - "MedicationIngredient|item_reference_ImagingStudy|ImagingStudy": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_ImagingStudy", - ToType: "ImagingStudy", + "Practitioner|recorder_Practitioner|Procedure": { + FromType: "Practitioner", + EdgeLabel: "recorder_Practitioner", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -34302,16 +34019,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "recorder_procedure", }, RegexMatch: []string{ - "ImagingStudy/*", + "Practitioner/*", }, }, - "ImagingStudy|item_reference_ImagingStudy|MedicationIngredient": { - FromType: "ImagingStudy", - EdgeLabel: "item_reference_ImagingStudy", - ToType: "MedicationIngredient", + "Procedure|recorder_PractitionerRole|PractitionerRole": { + FromType: "Procedure", + EdgeLabel: "recorder_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -34319,16 +34036,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "recorder_procedure", }, RegexMatch: []string{ - "ImagingStudy/*", + "PractitionerRole/*", }, }, - "MedicationIngredient|item_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", + "PractitionerRole|recorder_PractitionerRole|Procedure": { + FromType: "PractitionerRole", + EdgeLabel: "recorder_PractitionerRole", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -34336,67 +34053,67 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "recorder_procedure", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "PractitionerRole/*", }, }, - "FamilyMemberHistory|item_reference_FamilyMemberHistory|MedicationIngredient": { - FromType: "FamilyMemberHistory", - EdgeLabel: "item_reference_FamilyMemberHistory", - ToType: "MedicationIngredient", + "Procedure|report_DiagnosticReport|DiagnosticReport": { + FromType: "Procedure", + EdgeLabel: "report_DiagnosticReport", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "report_procedure", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "DiagnosticReport/*", }, }, - "MedicationIngredient|item_reference_BodyStructure|BodyStructure": { - FromType: "MedicationIngredient", - EdgeLabel: "item_reference_BodyStructure", - ToType: "BodyStructure", + "DiagnosticReport|report_DiagnosticReport|Procedure": { + FromType: "DiagnosticReport", + EdgeLabel: "report_DiagnosticReport", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "report_procedure", }, RegexMatch: []string{ - "BodyStructure/*", + "DiagnosticReport/*", }, }, - "BodyStructure|item_reference_BodyStructure|MedicationIngredient": { - FromType: "BodyStructure", - EdgeLabel: "item_reference_BodyStructure", - ToType: "MedicationIngredient", + "Procedure|report_DocumentReference|DocumentReference": { + FromType: "Procedure", + EdgeLabel: "report_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "report_procedure", }, RegexMatch: []string{ - "BodyStructure/*", + "DocumentReference/*", }, }, - "MedicationRequest|basedOn_MedicationRequest|MedicationRequest": { - FromType: "MedicationRequest", - EdgeLabel: "basedOn_MedicationRequest", - ToType: "MedicationRequest", + "DocumentReference|report_DocumentReference|Procedure": { + FromType: "DocumentReference", + EdgeLabel: "report_DocumentReference", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -34404,577 +34121,560 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "basedOn_medication_request", + "report_procedure", }, RegexMatch: []string{ - "MedicationRequest/*", + "DocumentReference/*", }, }, - "MedicationRequest|informationSource_Patient|Patient": { - FromType: "MedicationRequest", - EdgeLabel: "informationSource_Patient", + "Procedure|reportedReference_Patient|Patient": { + FromType: "Procedure", + EdgeLabel: "reportedReference_Patient", ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "informationSource_medication_request", + "reportedReference_procedure", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|informationSource_Patient|MedicationRequest": { + "Patient|reportedReference_Patient|Procedure": { FromType: "Patient", - EdgeLabel: "informationSource_Patient", - ToType: "MedicationRequest", + EdgeLabel: "reportedReference_Patient", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "informationSource_medication_request", + "reportedReference_procedure", }, RegexMatch: []string{ "Patient/*", }, }, - "MedicationRequest|informationSource_Practitioner|Practitioner": { - FromType: "MedicationRequest", - EdgeLabel: "informationSource_Practitioner", + "Procedure|reportedReference_Practitioner|Practitioner": { + FromType: "Procedure", + EdgeLabel: "reportedReference_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "informationSource_medication_request", + "reportedReference_procedure", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Practitioner|informationSource_Practitioner|MedicationRequest": { + "Practitioner|reportedReference_Practitioner|Procedure": { FromType: "Practitioner", - EdgeLabel: "informationSource_Practitioner", - ToType: "MedicationRequest", + EdgeLabel: "reportedReference_Practitioner", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "informationSource_medication_request", + "reportedReference_procedure", }, RegexMatch: []string{ "Practitioner/*", }, }, - "MedicationRequest|informationSource_PractitionerRole|PractitionerRole": { - FromType: "MedicationRequest", - EdgeLabel: "informationSource_PractitionerRole", + "Procedure|reportedReference_PractitionerRole|PractitionerRole": { + FromType: "Procedure", + EdgeLabel: "reportedReference_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "informationSource_medication_request", + "reportedReference_procedure", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "PractitionerRole|informationSource_PractitionerRole|MedicationRequest": { + "PractitionerRole|reportedReference_PractitionerRole|Procedure": { FromType: "PractitionerRole", - EdgeLabel: "informationSource_PractitionerRole", - ToType: "MedicationRequest", + EdgeLabel: "reportedReference_PractitionerRole", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "informationSource_medication_request", + "reportedReference_procedure", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "MedicationRequest|informationSource_Organization|Organization": { - FromType: "MedicationRequest", - EdgeLabel: "informationSource_Organization", + "Procedure|reportedReference_Organization|Organization": { + FromType: "Procedure", + EdgeLabel: "reportedReference_Organization", ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "informationSource_medication_request", + "reportedReference_procedure", }, RegexMatch: []string{ "Organization/*", }, }, - "Organization|informationSource_Organization|MedicationRequest": { + "Organization|reportedReference_Organization|Procedure": { FromType: "Organization", - EdgeLabel: "informationSource_Organization", - ToType: "MedicationRequest", + EdgeLabel: "reportedReference_Organization", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "informationSource_medication_request", + "reportedReference_procedure", }, RegexMatch: []string{ "Organization/*", }, }, - "MedicationRequest|performer_Practitioner|Practitioner": { - FromType: "MedicationRequest", - EdgeLabel: "performer_Practitioner", - ToType: "Practitioner", + "Procedure|subject_Patient|Patient": { + FromType: "Procedure", + EdgeLabel: "subject_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "performer_medication_request", + "subject_procedure", }, RegexMatch: []string{ - "Practitioner/*", + "Patient/*", }, }, - "Practitioner|performer_Practitioner|MedicationRequest": { - FromType: "Practitioner", - EdgeLabel: "performer_Practitioner", - ToType: "MedicationRequest", + "Patient|subject_Patient|Procedure": { + FromType: "Patient", + EdgeLabel: "subject_Patient", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "performer_medication_request", + "subject_procedure", }, RegexMatch: []string{ - "Practitioner/*", + "Patient/*", }, }, - "MedicationRequest|performer_PractitionerRole|PractitionerRole": { - FromType: "MedicationRequest", - EdgeLabel: "performer_PractitionerRole", - ToType: "PractitionerRole", + "Procedure|subject_Group|Group": { + FromType: "Procedure", + EdgeLabel: "subject_Group", + ToType: "Group", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "performer_medication_request", + "subject_procedure", }, RegexMatch: []string{ - "PractitionerRole/*", + "Group/*", }, }, - "PractitionerRole|performer_PractitionerRole|MedicationRequest": { - FromType: "PractitionerRole", - EdgeLabel: "performer_PractitionerRole", - ToType: "MedicationRequest", + "Group|subject_Group|Procedure": { + FromType: "Group", + EdgeLabel: "subject_Group", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "performer_medication_request", + "subject_procedure", }, RegexMatch: []string{ - "PractitionerRole/*", + "Group/*", }, }, - "MedicationRequest|performer_Organization|Organization": { - FromType: "MedicationRequest", - EdgeLabel: "performer_Organization", - ToType: "Organization", + "Procedure|subject_Practitioner|Practitioner": { + FromType: "Procedure", + EdgeLabel: "subject_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "performer_medication_request", + "subject_procedure", }, RegexMatch: []string{ - "Organization/*", + "Practitioner/*", }, }, - "Organization|performer_Organization|MedicationRequest": { - FromType: "Organization", - EdgeLabel: "performer_Organization", - ToType: "MedicationRequest", + "Practitioner|subject_Practitioner|Procedure": { + FromType: "Practitioner", + EdgeLabel: "subject_Practitioner", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "performer_medication_request", + "subject_procedure", }, RegexMatch: []string{ - "Organization/*", + "Practitioner/*", }, }, - "MedicationRequest|performer_Patient|Patient": { - FromType: "MedicationRequest", - EdgeLabel: "performer_Patient", - ToType: "Patient", + "Procedure|subject_Organization|Organization": { + FromType: "Procedure", + EdgeLabel: "subject_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "performer_medication_request", + "subject_procedure", }, RegexMatch: []string{ - "Patient/*", + "Organization/*", }, }, - "Patient|performer_Patient|MedicationRequest": { - FromType: "Patient", - EdgeLabel: "performer_Patient", - ToType: "MedicationRequest", + "Organization|subject_Organization|Procedure": { + FromType: "Organization", + EdgeLabel: "subject_Organization", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "performer_medication_request", + "subject_procedure", }, RegexMatch: []string{ - "Patient/*", + "Organization/*", }, }, - "MedicationRequest|priorPrescription|MedicationRequest": { - FromType: "MedicationRequest", - EdgeLabel: "priorPrescription", - ToType: "MedicationRequest", + "Procedure|supportingInfo_Organization|Organization": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "priorPrescription_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "MedicationRequest/*", + "Organization/*", }, }, - "MedicationRequest|recorder_Practitioner|Practitioner": { - FromType: "MedicationRequest", - EdgeLabel: "recorder_Practitioner", - ToType: "Practitioner", + "Organization|supportingInfo_Organization|Procedure": { + FromType: "Organization", + EdgeLabel: "supportingInfo_Organization", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "recorder_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Practitioner/*", + "Organization/*", }, }, - "Practitioner|recorder_Practitioner|MedicationRequest": { - FromType: "Practitioner", - EdgeLabel: "recorder_Practitioner", - ToType: "MedicationRequest", + "Procedure|supportingInfo_Group|Group": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_Group", + ToType: "Group", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "recorder_medication_request", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "MedicationRequest|recorder_PractitionerRole|PractitionerRole": { - FromType: "MedicationRequest", - EdgeLabel: "recorder_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "recorder_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "PractitionerRole/*", + "Group/*", }, }, - "PractitionerRole|recorder_PractitionerRole|MedicationRequest": { - FromType: "PractitionerRole", - EdgeLabel: "recorder_PractitionerRole", - ToType: "MedicationRequest", + "Group|supportingInfo_Group|Procedure": { + FromType: "Group", + EdgeLabel: "supportingInfo_Group", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "recorder_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "PractitionerRole/*", + "Group/*", }, }, - "MedicationRequest|requester_Practitioner|Practitioner": { - FromType: "MedicationRequest", - EdgeLabel: "requester_Practitioner", + "Procedure|supportingInfo_Practitioner|Practitioner": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "requester_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Practitioner|requester_Practitioner|MedicationRequest": { + "Practitioner|supportingInfo_Practitioner|Procedure": { FromType: "Practitioner", - EdgeLabel: "requester_Practitioner", - ToType: "MedicationRequest", + EdgeLabel: "supportingInfo_Practitioner", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "requester_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ "Practitioner/*", }, }, - "MedicationRequest|requester_PractitionerRole|PractitionerRole": { - FromType: "MedicationRequest", - EdgeLabel: "requester_PractitionerRole", + "Procedure|supportingInfo_PractitionerRole|PractitionerRole": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "requester_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "PractitionerRole|requester_PractitionerRole|MedicationRequest": { + "PractitionerRole|supportingInfo_PractitionerRole|Procedure": { FromType: "PractitionerRole", - EdgeLabel: "requester_PractitionerRole", - ToType: "MedicationRequest", + EdgeLabel: "supportingInfo_PractitionerRole", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "requester_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "MedicationRequest|requester_Organization|Organization": { - FromType: "MedicationRequest", - EdgeLabel: "requester_Organization", - ToType: "Organization", + "Procedure|supportingInfo_ResearchStudy|ResearchStudy": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_ResearchStudy", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "requester_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Organization/*", + "ResearchStudy/*", }, }, - "Organization|requester_Organization|MedicationRequest": { - FromType: "Organization", - EdgeLabel: "requester_Organization", - ToType: "MedicationRequest", + "ResearchStudy|supportingInfo_ResearchStudy|Procedure": { + FromType: "ResearchStudy", + EdgeLabel: "supportingInfo_ResearchStudy", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "requester_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Organization/*", + "ResearchStudy/*", }, }, - "MedicationRequest|requester_Patient|Patient": { - FromType: "MedicationRequest", - EdgeLabel: "requester_Patient", + "Procedure|supportingInfo_Patient|Patient": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_Patient", ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "requester_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|requester_Patient|MedicationRequest": { + "Patient|supportingInfo_Patient|Procedure": { FromType: "Patient", - EdgeLabel: "requester_Patient", - ToType: "MedicationRequest", + EdgeLabel: "supportingInfo_Patient", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "requester_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ "Patient/*", }, }, - "MedicationRequest|subject_Patient|Patient": { - FromType: "MedicationRequest", - EdgeLabel: "subject_Patient", - ToType: "Patient", + "Procedure|supportingInfo_ResearchSubject|ResearchSubject": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_ResearchSubject", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "subject_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Patient/*", + "ResearchSubject/*", }, }, - "Patient|subject_Patient|MedicationRequest": { - FromType: "Patient", - EdgeLabel: "subject_Patient", - ToType: "MedicationRequest", + "ResearchSubject|supportingInfo_ResearchSubject|Procedure": { + FromType: "ResearchSubject", + EdgeLabel: "supportingInfo_ResearchSubject", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "subject_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Patient/*", + "ResearchSubject/*", }, }, - "MedicationRequest|subject_Group|Group": { - FromType: "MedicationRequest", - EdgeLabel: "subject_Group", - ToType: "Group", + "Procedure|supportingInfo_Substance|Substance": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_Substance", + ToType: "Substance", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "subject_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Group/*", + "Substance/*", }, }, - "Group|subject_Group|MedicationRequest": { - FromType: "Group", - EdgeLabel: "subject_Group", - ToType: "MedicationRequest", + "Substance|supportingInfo_Substance|Procedure": { + FromType: "Substance", + EdgeLabel: "supportingInfo_Substance", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "subject_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Group/*", + "Substance/*", }, }, - "MedicationRequest|supportingInformation_Organization|Organization": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_Organization", - ToType: "Organization", + "Procedure|supportingInfo_SubstanceDefinition|SubstanceDefinition": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_SubstanceDefinition", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, @@ -34982,16 +34682,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Organization/*", + "SubstanceDefinition/*", }, }, - "Organization|supportingInformation_Organization|MedicationRequest": { - FromType: "Organization", - EdgeLabel: "supportingInformation_Organization", - ToType: "MedicationRequest", + "SubstanceDefinition|supportingInfo_SubstanceDefinition|Procedure": { + FromType: "SubstanceDefinition", + EdgeLabel: "supportingInfo_SubstanceDefinition", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -34999,16 +34699,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Organization/*", + "SubstanceDefinition/*", }, }, - "MedicationRequest|supportingInformation_Group|Group": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_Group", - ToType: "Group", + "Procedure|supportingInfo_Specimen|Specimen": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_Specimen", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -35016,16 +34716,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Group/*", + "Specimen/*", }, }, - "Group|supportingInformation_Group|MedicationRequest": { - FromType: "Group", - EdgeLabel: "supportingInformation_Group", - ToType: "MedicationRequest", + "Specimen|supportingInfo_Specimen|Procedure": { + FromType: "Specimen", + EdgeLabel: "supportingInfo_Specimen", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35033,16 +34733,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Group/*", + "Specimen/*", }, }, - "MedicationRequest|supportingInformation_Practitioner|Practitioner": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_Practitioner", - ToType: "Practitioner", + "Procedure|supportingInfo_Observation|Observation": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_Observation", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -35050,16 +34750,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Practitioner/*", + "Observation/*", }, }, - "Practitioner|supportingInformation_Practitioner|MedicationRequest": { - FromType: "Practitioner", - EdgeLabel: "supportingInformation_Practitioner", - ToType: "MedicationRequest", + "Observation|supportingInfo_Observation|Procedure": { + FromType: "Observation", + EdgeLabel: "supportingInfo_Observation", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35067,16 +34767,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Practitioner/*", + "Observation/*", }, }, - "MedicationRequest|supportingInformation_PractitionerRole|PractitionerRole": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_PractitionerRole", - ToType: "PractitionerRole", + "Procedure|supportingInfo_DiagnosticReport|DiagnosticReport": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_DiagnosticReport", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -35084,16 +34784,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "PractitionerRole/*", + "DiagnosticReport/*", }, }, - "PractitionerRole|supportingInformation_PractitionerRole|MedicationRequest": { - FromType: "PractitionerRole", - EdgeLabel: "supportingInformation_PractitionerRole", - ToType: "MedicationRequest", + "DiagnosticReport|supportingInfo_DiagnosticReport|Procedure": { + FromType: "DiagnosticReport", + EdgeLabel: "supportingInfo_DiagnosticReport", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35101,16 +34801,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "PractitionerRole/*", + "DiagnosticReport/*", }, }, - "MedicationRequest|supportingInformation_ResearchStudy|ResearchStudy": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_ResearchStudy", - ToType: "ResearchStudy", + "Procedure|supportingInfo_Condition|Condition": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_Condition", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -35118,16 +34818,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "ResearchStudy/*", + "Condition/*", }, }, - "ResearchStudy|supportingInformation_ResearchStudy|MedicationRequest": { - FromType: "ResearchStudy", - EdgeLabel: "supportingInformation_ResearchStudy", - ToType: "MedicationRequest", + "Condition|supportingInfo_Condition|Procedure": { + FromType: "Condition", + EdgeLabel: "supportingInfo_Condition", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35135,16 +34835,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "ResearchStudy/*", + "Condition/*", }, }, - "MedicationRequest|supportingInformation_Patient|Patient": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_Patient", - ToType: "Patient", + "Procedure|supportingInfo_Medication|Medication": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_Medication", + ToType: "Medication", Direction: []string{ "outbound", }, @@ -35152,16 +34852,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Patient/*", + "Medication/*", }, }, - "Patient|supportingInformation_Patient|MedicationRequest": { - FromType: "Patient", - EdgeLabel: "supportingInformation_Patient", - ToType: "MedicationRequest", + "Medication|supportingInfo_Medication|Procedure": { + FromType: "Medication", + EdgeLabel: "supportingInfo_Medication", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35169,16 +34869,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Patient/*", + "Medication/*", }, }, - "MedicationRequest|supportingInformation_ResearchSubject|ResearchSubject": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_ResearchSubject", - ToType: "ResearchSubject", + "Procedure|supportingInfo_MedicationAdministration|MedicationAdministration": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_MedicationAdministration", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -35186,16 +34886,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "ResearchSubject/*", + "MedicationAdministration/*", }, }, - "ResearchSubject|supportingInformation_ResearchSubject|MedicationRequest": { - FromType: "ResearchSubject", - EdgeLabel: "supportingInformation_ResearchSubject", - ToType: "MedicationRequest", + "MedicationAdministration|supportingInfo_MedicationAdministration|Procedure": { + FromType: "MedicationAdministration", + EdgeLabel: "supportingInfo_MedicationAdministration", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35203,16 +34903,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "ResearchSubject/*", + "MedicationAdministration/*", }, }, - "MedicationRequest|supportingInformation_Substance|Substance": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_Substance", - ToType: "Substance", + "Procedure|supportingInfo_MedicationStatement|MedicationStatement": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_MedicationStatement", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -35220,16 +34920,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Substance/*", + "MedicationStatement/*", }, }, - "Substance|supportingInformation_Substance|MedicationRequest": { - FromType: "Substance", - EdgeLabel: "supportingInformation_Substance", - ToType: "MedicationRequest", + "MedicationStatement|supportingInfo_MedicationStatement|Procedure": { + FromType: "MedicationStatement", + EdgeLabel: "supportingInfo_MedicationStatement", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35237,16 +34937,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Substance/*", + "MedicationStatement/*", }, }, - "MedicationRequest|supportingInformation_SubstanceDefinition|SubstanceDefinition": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_SubstanceDefinition", - ToType: "SubstanceDefinition", + "Procedure|supportingInfo_MedicationRequest|MedicationRequest": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_MedicationRequest", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -35254,16 +34954,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "MedicationRequest/*", }, }, - "SubstanceDefinition|supportingInformation_SubstanceDefinition|MedicationRequest": { - FromType: "SubstanceDefinition", - EdgeLabel: "supportingInformation_SubstanceDefinition", - ToType: "MedicationRequest", + "MedicationRequest|supportingInfo_MedicationRequest|Procedure": { + FromType: "MedicationRequest", + EdgeLabel: "supportingInfo_MedicationRequest", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35271,16 +34971,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "MedicationRequest/*", }, }, - "MedicationRequest|supportingInformation_Specimen|Specimen": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_Specimen", - ToType: "Specimen", + "Procedure|supportingInfo_Procedure|Procedure": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35288,16 +34988,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Specimen/*", + "Procedure/*", }, }, - "Specimen|supportingInformation_Specimen|MedicationRequest": { - FromType: "Specimen", - EdgeLabel: "supportingInformation_Specimen", - ToType: "MedicationRequest", + "Procedure|supportingInfo_DocumentReference|DocumentReference": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -35305,16 +35005,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Specimen/*", + "DocumentReference/*", }, }, - "MedicationRequest|supportingInformation_Observation|Observation": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_Observation", - ToType: "Observation", + "DocumentReference|supportingInfo_DocumentReference|Procedure": { + FromType: "DocumentReference", + EdgeLabel: "supportingInfo_DocumentReference", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35322,16 +35022,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Observation/*", + "DocumentReference/*", }, }, - "Observation|supportingInformation_Observation|MedicationRequest": { - FromType: "Observation", - EdgeLabel: "supportingInformation_Observation", - ToType: "MedicationRequest", + "Procedure|supportingInfo_Task|Task": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_Task", + ToType: "Task", Direction: []string{ "outbound", }, @@ -35339,16 +35039,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Observation/*", + "Task/*", }, }, - "MedicationRequest|supportingInformation_DiagnosticReport|DiagnosticReport": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_DiagnosticReport", - ToType: "DiagnosticReport", + "Task|supportingInfo_Task|Procedure": { + FromType: "Task", + EdgeLabel: "supportingInfo_Task", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35356,16 +35056,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Task/*", }, }, - "DiagnosticReport|supportingInformation_DiagnosticReport|MedicationRequest": { - FromType: "DiagnosticReport", - EdgeLabel: "supportingInformation_DiagnosticReport", - ToType: "MedicationRequest", + "Procedure|supportingInfo_ImagingStudy|ImagingStudy": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_ImagingStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -35373,16 +35073,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "DiagnosticReport/*", + "ImagingStudy/*", }, }, - "MedicationRequest|supportingInformation_Condition|Condition": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_Condition", - ToType: "Condition", + "ImagingStudy|supportingInfo_ImagingStudy|Procedure": { + FromType: "ImagingStudy", + EdgeLabel: "supportingInfo_ImagingStudy", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35390,16 +35090,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Condition/*", + "ImagingStudy/*", }, }, - "Condition|supportingInformation_Condition|MedicationRequest": { - FromType: "Condition", - EdgeLabel: "supportingInformation_Condition", - ToType: "MedicationRequest", + "Procedure|supportingInfo_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_FamilyMemberHistory", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -35407,16 +35107,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Condition/*", + "FamilyMemberHistory/*", }, }, - "MedicationRequest|supportingInformation_Medication|Medication": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_Medication", - ToType: "Medication", + "FamilyMemberHistory|supportingInfo_FamilyMemberHistory|Procedure": { + FromType: "FamilyMemberHistory", + EdgeLabel: "supportingInfo_FamilyMemberHistory", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35424,16 +35124,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ - "Medication/*", + "FamilyMemberHistory/*", }, }, - "Medication|supportingInformation_Medication|MedicationRequest": { - FromType: "Medication", - EdgeLabel: "supportingInformation_Medication", - ToType: "MedicationRequest", + "Procedure|supportingInfo_BodyStructure|BodyStructure": { + FromType: "Procedure", + EdgeLabel: "supportingInfo_BodyStructure", + ToType: "BodyStructure", Direction: []string{ "outbound", }, @@ -35441,288 +35141,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "MedicationRequest|supportingInformation_MedicationAdministration|MedicationAdministration": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_request", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|supportingInformation_MedicationAdministration|MedicationRequest": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInformation_MedicationAdministration", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_request", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationRequest|supportingInformation_MedicationStatement|MedicationStatement": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_request", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|supportingInformation_MedicationStatement|MedicationRequest": { - FromType: "MedicationStatement", - EdgeLabel: "supportingInformation_MedicationStatement", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_request", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationRequest|supportingInformation_MedicationRequest|MedicationRequest": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_MedicationRequest", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_request", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationRequest|supportingInformation_Procedure|Procedure": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_request", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|supportingInformation_Procedure|MedicationRequest": { - FromType: "Procedure", - EdgeLabel: "supportingInformation_Procedure", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_request", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "MedicationRequest|supportingInformation_DocumentReference|DocumentReference": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_request", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|supportingInformation_DocumentReference|MedicationRequest": { - FromType: "DocumentReference", - EdgeLabel: "supportingInformation_DocumentReference", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_request", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "MedicationRequest|supportingInformation_Task|Task": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_Task", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_request", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Task|supportingInformation_Task|MedicationRequest": { - FromType: "Task", - EdgeLabel: "supportingInformation_Task", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_request", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "MedicationRequest|supportingInformation_ImagingStudy|ImagingStudy": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_request", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|supportingInformation_ImagingStudy|MedicationRequest": { - FromType: "ImagingStudy", - EdgeLabel: "supportingInformation_ImagingStudy", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_request", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "MedicationRequest|supportingInformation_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_FamilyMemberHistory", - ToType: "FamilyMemberHistory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_request", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "FamilyMemberHistory|supportingInformation_FamilyMemberHistory|MedicationRequest": { - FromType: "FamilyMemberHistory", - EdgeLabel: "supportingInformation_FamilyMemberHistory", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_request", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "MedicationRequest|supportingInformation_BodyStructure|BodyStructure": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInformation_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ "BodyStructure/*", }, }, - "BodyStructure|supportingInformation_BodyStructure|MedicationRequest": { + "BodyStructure|supportingInfo_BodyStructure|Procedure": { FromType: "BodyStructure", - EdgeLabel: "supportingInformation_BodyStructure", - ToType: "MedicationRequest", + EdgeLabel: "supportingInfo_BodyStructure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35730,15 +35158,15 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "supportingInformation_medication_request", + "supportingInfo_procedure", }, RegexMatch: []string{ "BodyStructure/*", }, }, - "MedicationRequest|device_reference_Organization|Organization": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_Organization", + "Procedure|complication_reference_Organization|Organization": { + FromType: "Procedure", + EdgeLabel: "complication_reference_Organization", ToType: "Organization", Direction: []string{ "outbound", @@ -35753,10 +35181,10 @@ var Traversals = map[string]Traversal{ "Organization/*", }, }, - "Organization|device_reference_Organization|MedicationRequest": { + "Organization|complication_reference_Organization|Procedure": { FromType: "Organization", - EdgeLabel: "device_reference_Organization", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_Organization", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35770,9 +35198,9 @@ var Traversals = map[string]Traversal{ "Organization/*", }, }, - "MedicationRequest|device_reference_Group|Group": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_Group", + "Procedure|complication_reference_Group|Group": { + FromType: "Procedure", + EdgeLabel: "complication_reference_Group", ToType: "Group", Direction: []string{ "outbound", @@ -35787,10 +35215,10 @@ var Traversals = map[string]Traversal{ "Group/*", }, }, - "Group|device_reference_Group|MedicationRequest": { + "Group|complication_reference_Group|Procedure": { FromType: "Group", - EdgeLabel: "device_reference_Group", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_Group", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35804,9 +35232,9 @@ var Traversals = map[string]Traversal{ "Group/*", }, }, - "MedicationRequest|device_reference_Practitioner|Practitioner": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_Practitioner", + "Procedure|complication_reference_Practitioner|Practitioner": { + FromType: "Procedure", + EdgeLabel: "complication_reference_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", @@ -35821,10 +35249,10 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "Practitioner|device_reference_Practitioner|MedicationRequest": { + "Practitioner|complication_reference_Practitioner|Procedure": { FromType: "Practitioner", - EdgeLabel: "device_reference_Practitioner", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_Practitioner", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35838,9 +35266,9 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "MedicationRequest|device_reference_PractitionerRole|PractitionerRole": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_PractitionerRole", + "Procedure|complication_reference_PractitionerRole|PractitionerRole": { + FromType: "Procedure", + EdgeLabel: "complication_reference_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", @@ -35855,10 +35283,10 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "PractitionerRole|device_reference_PractitionerRole|MedicationRequest": { + "PractitionerRole|complication_reference_PractitionerRole|Procedure": { FromType: "PractitionerRole", - EdgeLabel: "device_reference_PractitionerRole", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_PractitionerRole", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35872,9 +35300,9 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "MedicationRequest|device_reference_ResearchStudy|ResearchStudy": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_ResearchStudy", + "Procedure|complication_reference_ResearchStudy|ResearchStudy": { + FromType: "Procedure", + EdgeLabel: "complication_reference_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -35889,10 +35317,10 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "ResearchStudy|device_reference_ResearchStudy|MedicationRequest": { + "ResearchStudy|complication_reference_ResearchStudy|Procedure": { FromType: "ResearchStudy", - EdgeLabel: "device_reference_ResearchStudy", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_ResearchStudy", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35906,9 +35334,9 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "MedicationRequest|device_reference_Patient|Patient": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_Patient", + "Procedure|complication_reference_Patient|Patient": { + FromType: "Procedure", + EdgeLabel: "complication_reference_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -35923,10 +35351,10 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "Patient|device_reference_Patient|MedicationRequest": { + "Patient|complication_reference_Patient|Procedure": { FromType: "Patient", - EdgeLabel: "device_reference_Patient", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_Patient", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35940,9 +35368,9 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "MedicationRequest|device_reference_ResearchSubject|ResearchSubject": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_ResearchSubject", + "Procedure|complication_reference_ResearchSubject|ResearchSubject": { + FromType: "Procedure", + EdgeLabel: "complication_reference_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -35957,10 +35385,10 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "ResearchSubject|device_reference_ResearchSubject|MedicationRequest": { + "ResearchSubject|complication_reference_ResearchSubject|Procedure": { FromType: "ResearchSubject", - EdgeLabel: "device_reference_ResearchSubject", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_ResearchSubject", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -35974,9 +35402,9 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "MedicationRequest|device_reference_Substance|Substance": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_Substance", + "Procedure|complication_reference_Substance|Substance": { + FromType: "Procedure", + EdgeLabel: "complication_reference_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -35991,10 +35419,10 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "Substance|device_reference_Substance|MedicationRequest": { + "Substance|complication_reference_Substance|Procedure": { FromType: "Substance", - EdgeLabel: "device_reference_Substance", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_Substance", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -36008,9 +35436,9 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "MedicationRequest|device_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_SubstanceDefinition", + "Procedure|complication_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "Procedure", + EdgeLabel: "complication_reference_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -36025,10 +35453,10 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|device_reference_SubstanceDefinition|MedicationRequest": { + "SubstanceDefinition|complication_reference_SubstanceDefinition|Procedure": { FromType: "SubstanceDefinition", - EdgeLabel: "device_reference_SubstanceDefinition", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_SubstanceDefinition", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -36042,9 +35470,9 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "MedicationRequest|device_reference_Specimen|Specimen": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_Specimen", + "Procedure|complication_reference_Specimen|Specimen": { + FromType: "Procedure", + EdgeLabel: "complication_reference_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -36059,10 +35487,10 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "Specimen|device_reference_Specimen|MedicationRequest": { + "Specimen|complication_reference_Specimen|Procedure": { FromType: "Specimen", - EdgeLabel: "device_reference_Specimen", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_Specimen", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -36076,9 +35504,9 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "MedicationRequest|device_reference_Observation|Observation": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_Observation", + "Procedure|complication_reference_Observation|Observation": { + FromType: "Procedure", + EdgeLabel: "complication_reference_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -36093,10 +35521,10 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "Observation|device_reference_Observation|MedicationRequest": { + "Observation|complication_reference_Observation|Procedure": { FromType: "Observation", - EdgeLabel: "device_reference_Observation", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_Observation", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -36110,9 +35538,9 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "MedicationRequest|device_reference_DiagnosticReport|DiagnosticReport": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_DiagnosticReport", + "Procedure|complication_reference_DiagnosticReport|DiagnosticReport": { + FromType: "Procedure", + EdgeLabel: "complication_reference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -36127,10 +35555,10 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "DiagnosticReport|device_reference_DiagnosticReport|MedicationRequest": { + "DiagnosticReport|complication_reference_DiagnosticReport|Procedure": { FromType: "DiagnosticReport", - EdgeLabel: "device_reference_DiagnosticReport", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_DiagnosticReport", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -36144,9 +35572,9 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "MedicationRequest|device_reference_Condition|Condition": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_Condition", + "Procedure|complication_reference_Condition|Condition": { + FromType: "Procedure", + EdgeLabel: "complication_reference_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -36161,10 +35589,10 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "Condition|device_reference_Condition|MedicationRequest": { + "Condition|complication_reference_Condition|Procedure": { FromType: "Condition", - EdgeLabel: "device_reference_Condition", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_Condition", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -36178,9 +35606,9 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "MedicationRequest|device_reference_Medication|Medication": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_Medication", + "Procedure|complication_reference_Medication|Medication": { + FromType: "Procedure", + EdgeLabel: "complication_reference_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -36195,10 +35623,10 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "Medication|device_reference_Medication|MedicationRequest": { + "Medication|complication_reference_Medication|Procedure": { FromType: "Medication", - EdgeLabel: "device_reference_Medication", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_Medication", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -36212,9 +35640,9 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "MedicationRequest|device_reference_MedicationAdministration|MedicationAdministration": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_MedicationAdministration", + "Procedure|complication_reference_MedicationAdministration|MedicationAdministration": { + FromType: "Procedure", + EdgeLabel: "complication_reference_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -36229,10 +35657,10 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "MedicationAdministration|device_reference_MedicationAdministration|MedicationRequest": { + "MedicationAdministration|complication_reference_MedicationAdministration|Procedure": { FromType: "MedicationAdministration", - EdgeLabel: "device_reference_MedicationAdministration", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_MedicationAdministration", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -36246,9 +35674,9 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "MedicationRequest|device_reference_MedicationStatement|MedicationStatement": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_MedicationStatement", + "Procedure|complication_reference_MedicationStatement|MedicationStatement": { + FromType: "Procedure", + EdgeLabel: "complication_reference_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -36263,10 +35691,10 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "MedicationStatement|device_reference_MedicationStatement|MedicationRequest": { + "MedicationStatement|complication_reference_MedicationStatement|Procedure": { FromType: "MedicationStatement", - EdgeLabel: "device_reference_MedicationStatement", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_MedicationStatement", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -36280,9 +35708,9 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "MedicationRequest|device_reference_MedicationRequest|MedicationRequest": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_MedicationRequest", + "Procedure|complication_reference_MedicationRequest|MedicationRequest": { + FromType: "Procedure", + EdgeLabel: "complication_reference_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -36297,9 +35725,9 @@ var Traversals = map[string]Traversal{ "MedicationRequest/*", }, }, - "MedicationRequest|device_reference_Procedure|Procedure": { + "MedicationRequest|complication_reference_MedicationRequest|Procedure": { FromType: "MedicationRequest", - EdgeLabel: "device_reference_Procedure", + EdgeLabel: "complication_reference_MedicationRequest", ToType: "Procedure", Direction: []string{ "outbound", @@ -36311,13 +35739,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Procedure/*", + "MedicationRequest/*", }, }, - "Procedure|device_reference_Procedure|MedicationRequest": { + "Procedure|complication_reference_Procedure|Procedure": { FromType: "Procedure", - EdgeLabel: "device_reference_Procedure", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -36331,9 +35759,9 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "MedicationRequest|device_reference_DocumentReference|DocumentReference": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_DocumentReference", + "Procedure|complication_reference_DocumentReference|DocumentReference": { + FromType: "Procedure", + EdgeLabel: "complication_reference_DocumentReference", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -36348,10 +35776,10 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "DocumentReference|device_reference_DocumentReference|MedicationRequest": { + "DocumentReference|complication_reference_DocumentReference|Procedure": { FromType: "DocumentReference", - EdgeLabel: "device_reference_DocumentReference", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_DocumentReference", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -36365,9 +35793,9 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "MedicationRequest|device_reference_Task|Task": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_Task", + "Procedure|complication_reference_Task|Task": { + FromType: "Procedure", + EdgeLabel: "complication_reference_Task", ToType: "Task", Direction: []string{ "outbound", @@ -36382,10 +35810,10 @@ var Traversals = map[string]Traversal{ "Task/*", }, }, - "Task|device_reference_Task|MedicationRequest": { + "Task|complication_reference_Task|Procedure": { FromType: "Task", - EdgeLabel: "device_reference_Task", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_Task", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -36399,9 +35827,9 @@ var Traversals = map[string]Traversal{ "Task/*", }, }, - "MedicationRequest|device_reference_ImagingStudy|ImagingStudy": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_ImagingStudy", + "Procedure|complication_reference_ImagingStudy|ImagingStudy": { + FromType: "Procedure", + EdgeLabel: "complication_reference_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", @@ -36416,10 +35844,10 @@ var Traversals = map[string]Traversal{ "ImagingStudy/*", }, }, - "ImagingStudy|device_reference_ImagingStudy|MedicationRequest": { + "ImagingStudy|complication_reference_ImagingStudy|Procedure": { FromType: "ImagingStudy", - EdgeLabel: "device_reference_ImagingStudy", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_ImagingStudy", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -36433,9 +35861,9 @@ var Traversals = map[string]Traversal{ "ImagingStudy/*", }, }, - "MedicationRequest|device_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_FamilyMemberHistory", + "Procedure|complication_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "Procedure", + EdgeLabel: "complication_reference_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -36450,10 +35878,10 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|device_reference_FamilyMemberHistory|MedicationRequest": { + "FamilyMemberHistory|complication_reference_FamilyMemberHistory|Procedure": { FromType: "FamilyMemberHistory", - EdgeLabel: "device_reference_FamilyMemberHistory", - ToType: "MedicationRequest", + EdgeLabel: "complication_reference_FamilyMemberHistory", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -36467,9 +35895,9 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "MedicationRequest|device_reference_BodyStructure|BodyStructure": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_BodyStructure", + "Procedure|complication_reference_BodyStructure|BodyStructure": { + FromType: "Procedure", + EdgeLabel: "complication_reference_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", @@ -36483,19131 +35911,333 @@ var Traversals = map[string]Traversal{ RegexMatch: []string{ "BodyStructure/*", }, - }, - "BodyStructure|device_reference_BodyStructure|MedicationRequest": { - FromType: "BodyStructure", - EdgeLabel: "device_reference_BodyStructure", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "MedicationRequest|dispenseRequest_dispenser|Organization": { - FromType: "MedicationRequest", - EdgeLabel: "dispenseRequest_dispenser", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "medication_request_dispense_request", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|dispenseRequest_dispenser|MedicationRequest": { - FromType: "Organization", - EdgeLabel: "dispenseRequest_dispenser", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "medication_request_dispense_request", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "MedicationRequest|medication_reference_Organization|Organization": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|medication_reference_Organization|MedicationRequest": { - FromType: "Organization", - EdgeLabel: "medication_reference_Organization", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "MedicationRequest|medication_reference_Group|Group": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|medication_reference_Group|MedicationRequest": { - FromType: "Group", - EdgeLabel: "medication_reference_Group", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "MedicationRequest|medication_reference_Practitioner|Practitioner": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|medication_reference_Practitioner|MedicationRequest": { - FromType: "Practitioner", - EdgeLabel: "medication_reference_Practitioner", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "MedicationRequest|medication_reference_PractitionerRole|PractitionerRole": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|medication_reference_PractitionerRole|MedicationRequest": { - FromType: "PractitionerRole", - EdgeLabel: "medication_reference_PractitionerRole", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "MedicationRequest|medication_reference_ResearchStudy|ResearchStudy": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|medication_reference_ResearchStudy|MedicationRequest": { - FromType: "ResearchStudy", - EdgeLabel: "medication_reference_ResearchStudy", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "MedicationRequest|medication_reference_Patient|Patient": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|medication_reference_Patient|MedicationRequest": { - FromType: "Patient", - EdgeLabel: "medication_reference_Patient", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "MedicationRequest|medication_reference_ResearchSubject|ResearchSubject": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_ResearchSubject", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchSubject|medication_reference_ResearchSubject|MedicationRequest": { - FromType: "ResearchSubject", - EdgeLabel: "medication_reference_ResearchSubject", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "MedicationRequest|medication_reference_Substance|Substance": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|medication_reference_Substance|MedicationRequest": { - FromType: "Substance", - EdgeLabel: "medication_reference_Substance", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "MedicationRequest|medication_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_SubstanceDefinition", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|medication_reference_SubstanceDefinition|MedicationRequest": { - FromType: "SubstanceDefinition", - EdgeLabel: "medication_reference_SubstanceDefinition", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "MedicationRequest|medication_reference_Specimen|Specimen": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|medication_reference_Specimen|MedicationRequest": { - FromType: "Specimen", - EdgeLabel: "medication_reference_Specimen", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "MedicationRequest|medication_reference_Observation|Observation": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|medication_reference_Observation|MedicationRequest": { - FromType: "Observation", - EdgeLabel: "medication_reference_Observation", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "MedicationRequest|medication_reference_DiagnosticReport|DiagnosticReport": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|medication_reference_DiagnosticReport|MedicationRequest": { - FromType: "DiagnosticReport", - EdgeLabel: "medication_reference_DiagnosticReport", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "MedicationRequest|medication_reference_Condition|Condition": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_Condition", - ToType: "Condition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Condition|medication_reference_Condition|MedicationRequest": { - FromType: "Condition", - EdgeLabel: "medication_reference_Condition", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "MedicationRequest|medication_reference_Medication|Medication": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_Medication", - ToType: "Medication", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Medication|medication_reference_Medication|MedicationRequest": { - FromType: "Medication", - EdgeLabel: "medication_reference_Medication", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "MedicationRequest|medication_reference_MedicationAdministration|MedicationAdministration": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|medication_reference_MedicationAdministration|MedicationRequest": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_MedicationAdministration", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationRequest|medication_reference_MedicationStatement|MedicationStatement": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|medication_reference_MedicationStatement|MedicationRequest": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_MedicationStatement", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationRequest|medication_reference_MedicationRequest|MedicationRequest": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_MedicationRequest", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationRequest|medication_reference_Procedure|Procedure": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|medication_reference_Procedure|MedicationRequest": { - FromType: "Procedure", - EdgeLabel: "medication_reference_Procedure", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "MedicationRequest|medication_reference_DocumentReference|DocumentReference": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|medication_reference_DocumentReference|MedicationRequest": { - FromType: "DocumentReference", - EdgeLabel: "medication_reference_DocumentReference", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "MedicationRequest|medication_reference_Task|Task": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_Task", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Task|medication_reference_Task|MedicationRequest": { - FromType: "Task", - EdgeLabel: "medication_reference_Task", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "MedicationRequest|medication_reference_ImagingStudy|ImagingStudy": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|medication_reference_ImagingStudy|MedicationRequest": { - FromType: "ImagingStudy", - EdgeLabel: "medication_reference_ImagingStudy", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "MedicationRequest|medication_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "FamilyMemberHistory|medication_reference_FamilyMemberHistory|MedicationRequest": { - FromType: "FamilyMemberHistory", - EdgeLabel: "medication_reference_FamilyMemberHistory", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "MedicationRequest|medication_reference_BodyStructure|BodyStructure": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|medication_reference_BodyStructure|MedicationRequest": { - FromType: "BodyStructure", - EdgeLabel: "medication_reference_BodyStructure", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "MedicationRequest|note_authorReference_Practitioner|Practitioner": { - FromType: "MedicationRequest", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|note_authorReference_Practitioner|MedicationRequest": { - FromType: "Practitioner", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "MedicationRequest|note_authorReference_PractitionerRole|PractitionerRole": { - FromType: "MedicationRequest", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|note_authorReference_PractitionerRole|MedicationRequest": { - FromType: "PractitionerRole", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "MedicationRequest|note_authorReference_Patient|Patient": { - FromType: "MedicationRequest", - EdgeLabel: "note_authorReference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|note_authorReference_Patient|MedicationRequest": { - FromType: "Patient", - EdgeLabel: "note_authorReference_Patient", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "MedicationRequest|note_authorReference_Organization|Organization": { - FromType: "MedicationRequest", - EdgeLabel: "note_authorReference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|note_authorReference_Organization|MedicationRequest": { - FromType: "Organization", - EdgeLabel: "note_authorReference_Organization", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "MedicationRequest|reason_reference_Organization|Organization": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|reason_reference_Organization|MedicationRequest": { - FromType: "Organization", - EdgeLabel: "reason_reference_Organization", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "MedicationRequest|reason_reference_Group|Group": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|reason_reference_Group|MedicationRequest": { - FromType: "Group", - EdgeLabel: "reason_reference_Group", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "MedicationRequest|reason_reference_Practitioner|Practitioner": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|reason_reference_Practitioner|MedicationRequest": { - FromType: "Practitioner", - EdgeLabel: "reason_reference_Practitioner", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "MedicationRequest|reason_reference_PractitionerRole|PractitionerRole": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|reason_reference_PractitionerRole|MedicationRequest": { - FromType: "PractitionerRole", - EdgeLabel: "reason_reference_PractitionerRole", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "MedicationRequest|reason_reference_ResearchStudy|ResearchStudy": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|reason_reference_ResearchStudy|MedicationRequest": { - FromType: "ResearchStudy", - EdgeLabel: "reason_reference_ResearchStudy", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "MedicationRequest|reason_reference_Patient|Patient": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|reason_reference_Patient|MedicationRequest": { - FromType: "Patient", - EdgeLabel: "reason_reference_Patient", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "MedicationRequest|reason_reference_ResearchSubject|ResearchSubject": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_ResearchSubject", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchSubject|reason_reference_ResearchSubject|MedicationRequest": { - FromType: "ResearchSubject", - EdgeLabel: "reason_reference_ResearchSubject", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "MedicationRequest|reason_reference_Substance|Substance": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|reason_reference_Substance|MedicationRequest": { - FromType: "Substance", - EdgeLabel: "reason_reference_Substance", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "MedicationRequest|reason_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_SubstanceDefinition", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|reason_reference_SubstanceDefinition|MedicationRequest": { - FromType: "SubstanceDefinition", - EdgeLabel: "reason_reference_SubstanceDefinition", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "MedicationRequest|reason_reference_Specimen|Specimen": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|reason_reference_Specimen|MedicationRequest": { - FromType: "Specimen", - EdgeLabel: "reason_reference_Specimen", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "MedicationRequest|reason_reference_Observation|Observation": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|reason_reference_Observation|MedicationRequest": { - FromType: "Observation", - EdgeLabel: "reason_reference_Observation", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "MedicationRequest|reason_reference_DiagnosticReport|DiagnosticReport": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|reason_reference_DiagnosticReport|MedicationRequest": { - FromType: "DiagnosticReport", - EdgeLabel: "reason_reference_DiagnosticReport", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "MedicationRequest|reason_reference_Condition|Condition": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_Condition", - ToType: "Condition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Condition|reason_reference_Condition|MedicationRequest": { - FromType: "Condition", - EdgeLabel: "reason_reference_Condition", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "MedicationRequest|reason_reference_Medication|Medication": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_Medication", - ToType: "Medication", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Medication|reason_reference_Medication|MedicationRequest": { - FromType: "Medication", - EdgeLabel: "reason_reference_Medication", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "MedicationRequest|reason_reference_MedicationAdministration|MedicationAdministration": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|reason_reference_MedicationAdministration|MedicationRequest": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_MedicationAdministration", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationRequest|reason_reference_MedicationStatement|MedicationStatement": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|reason_reference_MedicationStatement|MedicationRequest": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_MedicationStatement", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationRequest|reason_reference_MedicationRequest|MedicationRequest": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_MedicationRequest", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationRequest|reason_reference_Procedure|Procedure": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|reason_reference_Procedure|MedicationRequest": { - FromType: "Procedure", - EdgeLabel: "reason_reference_Procedure", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "MedicationRequest|reason_reference_DocumentReference|DocumentReference": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|reason_reference_DocumentReference|MedicationRequest": { - FromType: "DocumentReference", - EdgeLabel: "reason_reference_DocumentReference", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "MedicationRequest|reason_reference_Task|Task": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_Task", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Task|reason_reference_Task|MedicationRequest": { - FromType: "Task", - EdgeLabel: "reason_reference_Task", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "MedicationRequest|reason_reference_ImagingStudy|ImagingStudy": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|reason_reference_ImagingStudy|MedicationRequest": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_ImagingStudy", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "MedicationRequest|reason_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "FamilyMemberHistory|reason_reference_FamilyMemberHistory|MedicationRequest": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_FamilyMemberHistory", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "MedicationRequest|reason_reference_BodyStructure|BodyStructure": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|reason_reference_BodyStructure|MedicationRequest": { - FromType: "BodyStructure", - EdgeLabel: "reason_reference_BodyStructure", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "MedicationRequestDispenseRequest|dispenser|Organization": { - FromType: "MedicationRequestDispenseRequest", - EdgeLabel: "dispenser", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "medication_request_dispense_request", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|dispenser|MedicationRequestDispenseRequest": { - FromType: "Organization", - EdgeLabel: "dispenser", - ToType: "MedicationRequestDispenseRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "medication_request_dispense_request", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "MedicationRequestDispenseRequest|dispenserInstruction_authorReference_Practitioner|Practitioner": { - FromType: "MedicationRequestDispenseRequest", - EdgeLabel: "dispenserInstruction_authorReference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|dispenserInstruction_authorReference_Practitioner|MedicationRequestDispenseRequest": { - FromType: "Practitioner", - EdgeLabel: "dispenserInstruction_authorReference_Practitioner", - ToType: "MedicationRequestDispenseRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "MedicationRequestDispenseRequest|dispenserInstruction_authorReference_PractitionerRole|PractitionerRole": { - FromType: "MedicationRequestDispenseRequest", - EdgeLabel: "dispenserInstruction_authorReference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|dispenserInstruction_authorReference_PractitionerRole|MedicationRequestDispenseRequest": { - FromType: "PractitionerRole", - EdgeLabel: "dispenserInstruction_authorReference_PractitionerRole", - ToType: "MedicationRequestDispenseRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "MedicationRequestDispenseRequest|dispenserInstruction_authorReference_Patient|Patient": { - FromType: "MedicationRequestDispenseRequest", - EdgeLabel: "dispenserInstruction_authorReference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|dispenserInstruction_authorReference_Patient|MedicationRequestDispenseRequest": { - FromType: "Patient", - EdgeLabel: "dispenserInstruction_authorReference_Patient", - ToType: "MedicationRequestDispenseRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "MedicationRequestDispenseRequest|dispenserInstruction_authorReference_Organization|Organization": { - FromType: "MedicationRequestDispenseRequest", - EdgeLabel: "dispenserInstruction_authorReference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|dispenserInstruction_authorReference_Organization|MedicationRequestDispenseRequest": { - FromType: "Organization", - EdgeLabel: "dispenserInstruction_authorReference_Organization", - ToType: "MedicationRequestDispenseRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "MedicationStatement|derivedFrom_Organization|Organization": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|derivedFrom_Organization|MedicationStatement": { - FromType: "Organization", - EdgeLabel: "derivedFrom_Organization", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "MedicationStatement|derivedFrom_Group|Group": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|derivedFrom_Group|MedicationStatement": { - FromType: "Group", - EdgeLabel: "derivedFrom_Group", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "MedicationStatement|derivedFrom_Practitioner|Practitioner": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|derivedFrom_Practitioner|MedicationStatement": { - FromType: "Practitioner", - EdgeLabel: "derivedFrom_Practitioner", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "MedicationStatement|derivedFrom_PractitionerRole|PractitionerRole": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|derivedFrom_PractitionerRole|MedicationStatement": { - FromType: "PractitionerRole", - EdgeLabel: "derivedFrom_PractitionerRole", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "MedicationStatement|derivedFrom_ResearchStudy|ResearchStudy": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|derivedFrom_ResearchStudy|MedicationStatement": { - FromType: "ResearchStudy", - EdgeLabel: "derivedFrom_ResearchStudy", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "MedicationStatement|derivedFrom_Patient|Patient": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|derivedFrom_Patient|MedicationStatement": { - FromType: "Patient", - EdgeLabel: "derivedFrom_Patient", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "MedicationStatement|derivedFrom_ResearchSubject|ResearchSubject": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_ResearchSubject", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchSubject|derivedFrom_ResearchSubject|MedicationStatement": { - FromType: "ResearchSubject", - EdgeLabel: "derivedFrom_ResearchSubject", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "MedicationStatement|derivedFrom_Substance|Substance": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|derivedFrom_Substance|MedicationStatement": { - FromType: "Substance", - EdgeLabel: "derivedFrom_Substance", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "MedicationStatement|derivedFrom_SubstanceDefinition|SubstanceDefinition": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_SubstanceDefinition", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|derivedFrom_SubstanceDefinition|MedicationStatement": { - FromType: "SubstanceDefinition", - EdgeLabel: "derivedFrom_SubstanceDefinition", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "MedicationStatement|derivedFrom_Specimen|Specimen": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|derivedFrom_Specimen|MedicationStatement": { - FromType: "Specimen", - EdgeLabel: "derivedFrom_Specimen", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "MedicationStatement|derivedFrom_Observation|Observation": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|derivedFrom_Observation|MedicationStatement": { - FromType: "Observation", - EdgeLabel: "derivedFrom_Observation", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "MedicationStatement|derivedFrom_DiagnosticReport|DiagnosticReport": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|derivedFrom_DiagnosticReport|MedicationStatement": { - FromType: "DiagnosticReport", - EdgeLabel: "derivedFrom_DiagnosticReport", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "MedicationStatement|derivedFrom_Condition|Condition": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_Condition", - ToType: "Condition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Condition|derivedFrom_Condition|MedicationStatement": { - FromType: "Condition", - EdgeLabel: "derivedFrom_Condition", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "MedicationStatement|derivedFrom_Medication|Medication": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_Medication", - ToType: "Medication", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Medication|derivedFrom_Medication|MedicationStatement": { - FromType: "Medication", - EdgeLabel: "derivedFrom_Medication", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "MedicationStatement|derivedFrom_MedicationAdministration|MedicationAdministration": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|derivedFrom_MedicationAdministration|MedicationStatement": { - FromType: "MedicationAdministration", - EdgeLabel: "derivedFrom_MedicationAdministration", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationStatement|derivedFrom_MedicationStatement|MedicationStatement": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|derivedFrom_MedicationRequest|MedicationRequest": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_MedicationRequest", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationRequest|derivedFrom_MedicationRequest|MedicationStatement": { - FromType: "MedicationRequest", - EdgeLabel: "derivedFrom_MedicationRequest", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationStatement|derivedFrom_Procedure|Procedure": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|derivedFrom_Procedure|MedicationStatement": { - FromType: "Procedure", - EdgeLabel: "derivedFrom_Procedure", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "MedicationStatement|derivedFrom_DocumentReference|DocumentReference": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|derivedFrom_DocumentReference|MedicationStatement": { - FromType: "DocumentReference", - EdgeLabel: "derivedFrom_DocumentReference", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "MedicationStatement|derivedFrom_Task|Task": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_Task", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Task|derivedFrom_Task|MedicationStatement": { - FromType: "Task", - EdgeLabel: "derivedFrom_Task", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "MedicationStatement|derivedFrom_ImagingStudy|ImagingStudy": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|derivedFrom_ImagingStudy|MedicationStatement": { - FromType: "ImagingStudy", - EdgeLabel: "derivedFrom_ImagingStudy", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "MedicationStatement|derivedFrom_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_FamilyMemberHistory", - ToType: "FamilyMemberHistory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "FamilyMemberHistory|derivedFrom_FamilyMemberHistory|MedicationStatement": { - FromType: "FamilyMemberHistory", - EdgeLabel: "derivedFrom_FamilyMemberHistory", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "MedicationStatement|derivedFrom_BodyStructure|BodyStructure": { - FromType: "MedicationStatement", - EdgeLabel: "derivedFrom_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|derivedFrom_BodyStructure|MedicationStatement": { - FromType: "BodyStructure", - EdgeLabel: "derivedFrom_BodyStructure", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_medication_statement", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "MedicationStatement|informationSource_Patient|Patient": { - FromType: "MedicationStatement", - EdgeLabel: "informationSource_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "informationSource_medication_statement", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|informationSource_Patient|MedicationStatement": { - FromType: "Patient", - EdgeLabel: "informationSource_Patient", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "informationSource_medication_statement", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "MedicationStatement|informationSource_Practitioner|Practitioner": { - FromType: "MedicationStatement", - EdgeLabel: "informationSource_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "informationSource_medication_statement", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|informationSource_Practitioner|MedicationStatement": { - FromType: "Practitioner", - EdgeLabel: "informationSource_Practitioner", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "informationSource_medication_statement", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "MedicationStatement|informationSource_PractitionerRole|PractitionerRole": { - FromType: "MedicationStatement", - EdgeLabel: "informationSource_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "informationSource_medication_statement", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|informationSource_PractitionerRole|MedicationStatement": { - FromType: "PractitionerRole", - EdgeLabel: "informationSource_PractitionerRole", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "informationSource_medication_statement", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "MedicationStatement|informationSource_Organization|Organization": { - FromType: "MedicationStatement", - EdgeLabel: "informationSource_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "informationSource_medication_statement", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|informationSource_Organization|MedicationStatement": { - FromType: "Organization", - EdgeLabel: "informationSource_Organization", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "informationSource_medication_statement", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "MedicationStatement|partOf_Procedure|Procedure": { - FromType: "MedicationStatement", - EdgeLabel: "partOf_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "partOf_medication_statement", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|partOf_Procedure|MedicationStatement": { - FromType: "Procedure", - EdgeLabel: "partOf_Procedure", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "partOf_medication_statement", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "MedicationStatement|partOf_MedicationStatement|MedicationStatement": { - FromType: "MedicationStatement", - EdgeLabel: "partOf_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "partOf_medication_statement", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|relatedClinicalInformation_Observation|Observation": { - FromType: "MedicationStatement", - EdgeLabel: "relatedClinicalInformation_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "relatedClinicalInformation_medication_statement", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|relatedClinicalInformation_Observation|MedicationStatement": { - FromType: "Observation", - EdgeLabel: "relatedClinicalInformation_Observation", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "relatedClinicalInformation_medication_statement", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "MedicationStatement|relatedClinicalInformation_Condition|Condition": { - FromType: "MedicationStatement", - EdgeLabel: "relatedClinicalInformation_Condition", - ToType: "Condition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "relatedClinicalInformation_medication_statement", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Condition|relatedClinicalInformation_Condition|MedicationStatement": { - FromType: "Condition", - EdgeLabel: "relatedClinicalInformation_Condition", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "relatedClinicalInformation_medication_statement", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "MedicationStatement|subject_Patient|Patient": { - FromType: "MedicationStatement", - EdgeLabel: "subject_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_medication_statement", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|subject_Patient|MedicationStatement": { - FromType: "Patient", - EdgeLabel: "subject_Patient", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_medication_statement", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "MedicationStatement|subject_Group|Group": { - FromType: "MedicationStatement", - EdgeLabel: "subject_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_medication_statement", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|subject_Group|MedicationStatement": { - FromType: "Group", - EdgeLabel: "subject_Group", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_medication_statement", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "MedicationStatement|medication_reference_Organization|Organization": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|medication_reference_Organization|MedicationStatement": { - FromType: "Organization", - EdgeLabel: "medication_reference_Organization", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "MedicationStatement|medication_reference_Group|Group": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|medication_reference_Group|MedicationStatement": { - FromType: "Group", - EdgeLabel: "medication_reference_Group", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "MedicationStatement|medication_reference_Practitioner|Practitioner": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|medication_reference_Practitioner|MedicationStatement": { - FromType: "Practitioner", - EdgeLabel: "medication_reference_Practitioner", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "MedicationStatement|medication_reference_PractitionerRole|PractitionerRole": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|medication_reference_PractitionerRole|MedicationStatement": { - FromType: "PractitionerRole", - EdgeLabel: "medication_reference_PractitionerRole", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "MedicationStatement|medication_reference_ResearchStudy|ResearchStudy": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|medication_reference_ResearchStudy|MedicationStatement": { - FromType: "ResearchStudy", - EdgeLabel: "medication_reference_ResearchStudy", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "MedicationStatement|medication_reference_Patient|Patient": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|medication_reference_Patient|MedicationStatement": { - FromType: "Patient", - EdgeLabel: "medication_reference_Patient", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "MedicationStatement|medication_reference_ResearchSubject|ResearchSubject": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_ResearchSubject", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchSubject|medication_reference_ResearchSubject|MedicationStatement": { - FromType: "ResearchSubject", - EdgeLabel: "medication_reference_ResearchSubject", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "MedicationStatement|medication_reference_Substance|Substance": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|medication_reference_Substance|MedicationStatement": { - FromType: "Substance", - EdgeLabel: "medication_reference_Substance", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "MedicationStatement|medication_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_SubstanceDefinition", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|medication_reference_SubstanceDefinition|MedicationStatement": { - FromType: "SubstanceDefinition", - EdgeLabel: "medication_reference_SubstanceDefinition", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "MedicationStatement|medication_reference_Specimen|Specimen": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|medication_reference_Specimen|MedicationStatement": { - FromType: "Specimen", - EdgeLabel: "medication_reference_Specimen", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "MedicationStatement|medication_reference_Observation|Observation": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|medication_reference_Observation|MedicationStatement": { - FromType: "Observation", - EdgeLabel: "medication_reference_Observation", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "MedicationStatement|medication_reference_DiagnosticReport|DiagnosticReport": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|medication_reference_DiagnosticReport|MedicationStatement": { - FromType: "DiagnosticReport", - EdgeLabel: "medication_reference_DiagnosticReport", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "MedicationStatement|medication_reference_Condition|Condition": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_Condition", - ToType: "Condition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Condition|medication_reference_Condition|MedicationStatement": { - FromType: "Condition", - EdgeLabel: "medication_reference_Condition", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "MedicationStatement|medication_reference_Medication|Medication": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_Medication", - ToType: "Medication", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Medication|medication_reference_Medication|MedicationStatement": { - FromType: "Medication", - EdgeLabel: "medication_reference_Medication", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "MedicationStatement|medication_reference_MedicationAdministration|MedicationAdministration": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|medication_reference_MedicationAdministration|MedicationStatement": { - FromType: "MedicationAdministration", - EdgeLabel: "medication_reference_MedicationAdministration", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationStatement|medication_reference_MedicationStatement|MedicationStatement": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|medication_reference_MedicationRequest|MedicationRequest": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_MedicationRequest", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationRequest|medication_reference_MedicationRequest|MedicationStatement": { - FromType: "MedicationRequest", - EdgeLabel: "medication_reference_MedicationRequest", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationStatement|medication_reference_Procedure|Procedure": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|medication_reference_Procedure|MedicationStatement": { - FromType: "Procedure", - EdgeLabel: "medication_reference_Procedure", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "MedicationStatement|medication_reference_DocumentReference|DocumentReference": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|medication_reference_DocumentReference|MedicationStatement": { - FromType: "DocumentReference", - EdgeLabel: "medication_reference_DocumentReference", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "MedicationStatement|medication_reference_Task|Task": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_Task", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Task|medication_reference_Task|MedicationStatement": { - FromType: "Task", - EdgeLabel: "medication_reference_Task", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "MedicationStatement|medication_reference_ImagingStudy|ImagingStudy": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|medication_reference_ImagingStudy|MedicationStatement": { - FromType: "ImagingStudy", - EdgeLabel: "medication_reference_ImagingStudy", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "MedicationStatement|medication_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "FamilyMemberHistory|medication_reference_FamilyMemberHistory|MedicationStatement": { - FromType: "FamilyMemberHistory", - EdgeLabel: "medication_reference_FamilyMemberHistory", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "MedicationStatement|medication_reference_BodyStructure|BodyStructure": { - FromType: "MedicationStatement", - EdgeLabel: "medication_reference_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|medication_reference_BodyStructure|MedicationStatement": { - FromType: "BodyStructure", - EdgeLabel: "medication_reference_BodyStructure", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "MedicationStatement|note_authorReference_Practitioner|Practitioner": { - FromType: "MedicationStatement", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|note_authorReference_Practitioner|MedicationStatement": { - FromType: "Practitioner", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "MedicationStatement|note_authorReference_PractitionerRole|PractitionerRole": { - FromType: "MedicationStatement", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|note_authorReference_PractitionerRole|MedicationStatement": { - FromType: "PractitionerRole", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "MedicationStatement|note_authorReference_Patient|Patient": { - FromType: "MedicationStatement", - EdgeLabel: "note_authorReference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|note_authorReference_Patient|MedicationStatement": { - FromType: "Patient", - EdgeLabel: "note_authorReference_Patient", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "MedicationStatement|note_authorReference_Organization|Organization": { - FromType: "MedicationStatement", - EdgeLabel: "note_authorReference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|note_authorReference_Organization|MedicationStatement": { - FromType: "Organization", - EdgeLabel: "note_authorReference_Organization", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "MedicationStatement|reason_reference_Organization|Organization": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|reason_reference_Organization|MedicationStatement": { - FromType: "Organization", - EdgeLabel: "reason_reference_Organization", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "MedicationStatement|reason_reference_Group|Group": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|reason_reference_Group|MedicationStatement": { - FromType: "Group", - EdgeLabel: "reason_reference_Group", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "MedicationStatement|reason_reference_Practitioner|Practitioner": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|reason_reference_Practitioner|MedicationStatement": { - FromType: "Practitioner", - EdgeLabel: "reason_reference_Practitioner", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "MedicationStatement|reason_reference_PractitionerRole|PractitionerRole": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|reason_reference_PractitionerRole|MedicationStatement": { - FromType: "PractitionerRole", - EdgeLabel: "reason_reference_PractitionerRole", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "MedicationStatement|reason_reference_ResearchStudy|ResearchStudy": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|reason_reference_ResearchStudy|MedicationStatement": { - FromType: "ResearchStudy", - EdgeLabel: "reason_reference_ResearchStudy", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "MedicationStatement|reason_reference_Patient|Patient": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|reason_reference_Patient|MedicationStatement": { - FromType: "Patient", - EdgeLabel: "reason_reference_Patient", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "MedicationStatement|reason_reference_ResearchSubject|ResearchSubject": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_ResearchSubject", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchSubject|reason_reference_ResearchSubject|MedicationStatement": { - FromType: "ResearchSubject", - EdgeLabel: "reason_reference_ResearchSubject", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "MedicationStatement|reason_reference_Substance|Substance": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|reason_reference_Substance|MedicationStatement": { - FromType: "Substance", - EdgeLabel: "reason_reference_Substance", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "MedicationStatement|reason_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_SubstanceDefinition", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|reason_reference_SubstanceDefinition|MedicationStatement": { - FromType: "SubstanceDefinition", - EdgeLabel: "reason_reference_SubstanceDefinition", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "MedicationStatement|reason_reference_Specimen|Specimen": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|reason_reference_Specimen|MedicationStatement": { - FromType: "Specimen", - EdgeLabel: "reason_reference_Specimen", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "MedicationStatement|reason_reference_Observation|Observation": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|reason_reference_Observation|MedicationStatement": { - FromType: "Observation", - EdgeLabel: "reason_reference_Observation", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "MedicationStatement|reason_reference_DiagnosticReport|DiagnosticReport": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|reason_reference_DiagnosticReport|MedicationStatement": { - FromType: "DiagnosticReport", - EdgeLabel: "reason_reference_DiagnosticReport", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "MedicationStatement|reason_reference_Condition|Condition": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_Condition", - ToType: "Condition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Condition|reason_reference_Condition|MedicationStatement": { - FromType: "Condition", - EdgeLabel: "reason_reference_Condition", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "MedicationStatement|reason_reference_Medication|Medication": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_Medication", - ToType: "Medication", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Medication|reason_reference_Medication|MedicationStatement": { - FromType: "Medication", - EdgeLabel: "reason_reference_Medication", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "MedicationStatement|reason_reference_MedicationAdministration|MedicationAdministration": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|reason_reference_MedicationAdministration|MedicationStatement": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_MedicationAdministration", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationStatement|reason_reference_MedicationStatement|MedicationStatement": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|reason_reference_MedicationRequest|MedicationRequest": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_MedicationRequest", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationRequest|reason_reference_MedicationRequest|MedicationStatement": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_MedicationRequest", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationStatement|reason_reference_Procedure|Procedure": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|reason_reference_Procedure|MedicationStatement": { - FromType: "Procedure", - EdgeLabel: "reason_reference_Procedure", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "MedicationStatement|reason_reference_DocumentReference|DocumentReference": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|reason_reference_DocumentReference|MedicationStatement": { - FromType: "DocumentReference", - EdgeLabel: "reason_reference_DocumentReference", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "MedicationStatement|reason_reference_Task|Task": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_Task", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Task|reason_reference_Task|MedicationStatement": { - FromType: "Task", - EdgeLabel: "reason_reference_Task", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "MedicationStatement|reason_reference_ImagingStudy|ImagingStudy": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|reason_reference_ImagingStudy|MedicationStatement": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_ImagingStudy", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "MedicationStatement|reason_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "FamilyMemberHistory|reason_reference_FamilyMemberHistory|MedicationStatement": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_FamilyMemberHistory", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "MedicationStatement|reason_reference_BodyStructure|BodyStructure": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|reason_reference_BodyStructure|MedicationStatement": { - FromType: "BodyStructure", - EdgeLabel: "reason_reference_BodyStructure", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "Observation|basedOn_MedicationRequest|MedicationRequest": { - FromType: "Observation", - EdgeLabel: "basedOn_MedicationRequest", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_observation", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationRequest|basedOn_MedicationRequest|Observation": { - FromType: "MedicationRequest", - EdgeLabel: "basedOn_MedicationRequest", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_observation", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "Observation|bodyStructure|BodyStructure": { - FromType: "Observation", - EdgeLabel: "bodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "observation", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|bodyStructure|Observation": { - FromType: "BodyStructure", - EdgeLabel: "bodyStructure", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "observation", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "Observation|derivedFrom_DocumentReference|DocumentReference": { - FromType: "Observation", - EdgeLabel: "derivedFrom_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_observation", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|derivedFrom_DocumentReference|Observation": { - FromType: "DocumentReference", - EdgeLabel: "derivedFrom_DocumentReference", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_observation", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "Observation|derivedFrom_ImagingStudy|ImagingStudy": { - FromType: "Observation", - EdgeLabel: "derivedFrom_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_observation", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|derivedFrom_ImagingStudy|Observation": { - FromType: "ImagingStudy", - EdgeLabel: "derivedFrom_ImagingStudy", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_observation", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "Observation|derivedFrom_Observation|Observation": { - FromType: "Observation", - EdgeLabel: "derivedFrom_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "derivedFrom_observation", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|focus_Organization|Organization": { - FromType: "Observation", - EdgeLabel: "focus_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|focus_Organization|Observation": { - FromType: "Organization", - EdgeLabel: "focus_Organization", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Observation|focus_Group|Group": { - FromType: "Observation", - EdgeLabel: "focus_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|focus_Group|Observation": { - FromType: "Group", - EdgeLabel: "focus_Group", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Observation|focus_Practitioner|Practitioner": { - FromType: "Observation", - EdgeLabel: "focus_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|focus_Practitioner|Observation": { - FromType: "Practitioner", - EdgeLabel: "focus_Practitioner", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Observation|focus_PractitionerRole|PractitionerRole": { - FromType: "Observation", - EdgeLabel: "focus_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|focus_PractitionerRole|Observation": { - FromType: "PractitionerRole", - EdgeLabel: "focus_PractitionerRole", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Observation|focus_ResearchStudy|ResearchStudy": { - FromType: "Observation", - EdgeLabel: "focus_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|focus_ResearchStudy|Observation": { - FromType: "ResearchStudy", - EdgeLabel: "focus_ResearchStudy", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "Observation|focus_Patient|Patient": { - FromType: "Observation", - EdgeLabel: "focus_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|focus_Patient|Observation": { - FromType: "Patient", - EdgeLabel: "focus_Patient", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Observation|focus_ResearchSubject|ResearchSubject": { - FromType: "Observation", - EdgeLabel: "focus_ResearchSubject", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchSubject|focus_ResearchSubject|Observation": { - FromType: "ResearchSubject", - EdgeLabel: "focus_ResearchSubject", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "Observation|focus_Substance|Substance": { - FromType: "Observation", - EdgeLabel: "focus_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|focus_Substance|Observation": { - FromType: "Substance", - EdgeLabel: "focus_Substance", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Observation|focus_SubstanceDefinition|SubstanceDefinition": { - FromType: "Observation", - EdgeLabel: "focus_SubstanceDefinition", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|focus_SubstanceDefinition|Observation": { - FromType: "SubstanceDefinition", - EdgeLabel: "focus_SubstanceDefinition", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "Observation|focus_Specimen|Specimen": { - FromType: "Observation", - EdgeLabel: "focus_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|focus_Specimen|Observation": { - FromType: "Specimen", - EdgeLabel: "focus_Specimen", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Observation|focus_Observation|Observation": { - FromType: "Observation", - EdgeLabel: "focus_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|focus_DiagnosticReport|DiagnosticReport": { - FromType: "Observation", - EdgeLabel: "focus_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|focus_DiagnosticReport|Observation": { - FromType: "DiagnosticReport", - EdgeLabel: "focus_DiagnosticReport", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "Observation|focus_Condition|Condition": { - FromType: "Observation", - EdgeLabel: "focus_Condition", - ToType: "Condition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Condition|focus_Condition|Observation": { - FromType: "Condition", - EdgeLabel: "focus_Condition", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Observation|focus_Medication|Medication": { - FromType: "Observation", - EdgeLabel: "focus_Medication", - ToType: "Medication", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Medication|focus_Medication|Observation": { - FromType: "Medication", - EdgeLabel: "focus_Medication", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Observation|focus_MedicationAdministration|MedicationAdministration": { - FromType: "Observation", - EdgeLabel: "focus_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|focus_MedicationAdministration|Observation": { - FromType: "MedicationAdministration", - EdgeLabel: "focus_MedicationAdministration", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "Observation|focus_MedicationStatement|MedicationStatement": { - FromType: "Observation", - EdgeLabel: "focus_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|focus_MedicationStatement|Observation": { - FromType: "MedicationStatement", - EdgeLabel: "focus_MedicationStatement", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "Observation|focus_MedicationRequest|MedicationRequest": { - FromType: "Observation", - EdgeLabel: "focus_MedicationRequest", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationRequest|focus_MedicationRequest|Observation": { - FromType: "MedicationRequest", - EdgeLabel: "focus_MedicationRequest", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "Observation|focus_Procedure|Procedure": { - FromType: "Observation", - EdgeLabel: "focus_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|focus_Procedure|Observation": { - FromType: "Procedure", - EdgeLabel: "focus_Procedure", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Observation|focus_DocumentReference|DocumentReference": { - FromType: "Observation", - EdgeLabel: "focus_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|focus_DocumentReference|Observation": { - FromType: "DocumentReference", - EdgeLabel: "focus_DocumentReference", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "Observation|focus_Task|Task": { - FromType: "Observation", - EdgeLabel: "focus_Task", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Task|focus_Task|Observation": { - FromType: "Task", - EdgeLabel: "focus_Task", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Observation|focus_ImagingStudy|ImagingStudy": { - FromType: "Observation", - EdgeLabel: "focus_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|focus_ImagingStudy|Observation": { - FromType: "ImagingStudy", - EdgeLabel: "focus_ImagingStudy", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "Observation|focus_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "Observation", - EdgeLabel: "focus_FamilyMemberHistory", - ToType: "FamilyMemberHistory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "FamilyMemberHistory|focus_FamilyMemberHistory|Observation": { - FromType: "FamilyMemberHistory", - EdgeLabel: "focus_FamilyMemberHistory", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "Observation|focus_BodyStructure|BodyStructure": { - FromType: "Observation", - EdgeLabel: "focus_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|focus_BodyStructure|Observation": { - FromType: "BodyStructure", - EdgeLabel: "focus_BodyStructure", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "focus_observation", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "Observation|hasMember_Observation|Observation": { - FromType: "Observation", - EdgeLabel: "hasMember_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "hasMember_observation", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|partOf_MedicationAdministration|MedicationAdministration": { - FromType: "Observation", - EdgeLabel: "partOf_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "partOf_observation", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|partOf_MedicationAdministration|Observation": { - FromType: "MedicationAdministration", - EdgeLabel: "partOf_MedicationAdministration", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "partOf_observation", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "Observation|partOf_MedicationStatement|MedicationStatement": { - FromType: "Observation", - EdgeLabel: "partOf_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "partOf_observation", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|partOf_MedicationStatement|Observation": { - FromType: "MedicationStatement", - EdgeLabel: "partOf_MedicationStatement", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "partOf_observation", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "Observation|partOf_Procedure|Procedure": { - FromType: "Observation", - EdgeLabel: "partOf_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "partOf_observation", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|partOf_Procedure|Observation": { - FromType: "Procedure", - EdgeLabel: "partOf_Procedure", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "partOf_observation", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Observation|partOf_ImagingStudy|ImagingStudy": { - FromType: "Observation", - EdgeLabel: "partOf_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "partOf_observation", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|partOf_ImagingStudy|Observation": { - FromType: "ImagingStudy", - EdgeLabel: "partOf_ImagingStudy", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "partOf_observation", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "Observation|performer_Practitioner|Practitioner": { - FromType: "Observation", - EdgeLabel: "performer_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "performer_observation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|performer_Practitioner|Observation": { - FromType: "Practitioner", - EdgeLabel: "performer_Practitioner", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "performer_observation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Observation|performer_PractitionerRole|PractitionerRole": { - FromType: "Observation", - EdgeLabel: "performer_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "performer_observation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|performer_PractitionerRole|Observation": { - FromType: "PractitionerRole", - EdgeLabel: "performer_PractitionerRole", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "performer_observation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Observation|performer_Organization|Organization": { - FromType: "Observation", - EdgeLabel: "performer_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "performer_observation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|performer_Organization|Observation": { - FromType: "Organization", - EdgeLabel: "performer_Organization", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "performer_observation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Observation|performer_Patient|Patient": { - FromType: "Observation", - EdgeLabel: "performer_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "performer_observation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|performer_Patient|Observation": { - FromType: "Patient", - EdgeLabel: "performer_Patient", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "performer_observation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Observation|specimen_Specimen|Specimen": { - FromType: "Observation", - EdgeLabel: "specimen_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_observation", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|specimen_Specimen|Observation": { - FromType: "Specimen", - EdgeLabel: "specimen_Specimen", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_observation", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Observation|specimen_Group|Group": { - FromType: "Observation", - EdgeLabel: "specimen_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_observation", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|specimen_Group|Observation": { - FromType: "Group", - EdgeLabel: "specimen_Group", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_observation", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Observation|subject_Patient|Patient": { - FromType: "Observation", - EdgeLabel: "subject_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_observation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|subject_Patient|Observation": { - FromType: "Patient", - EdgeLabel: "subject_Patient", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_observation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Observation|subject_Group|Group": { - FromType: "Observation", - EdgeLabel: "subject_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_observation", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|subject_Group|Observation": { - FromType: "Group", - EdgeLabel: "subject_Group", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_observation", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Observation|subject_Organization|Organization": { - FromType: "Observation", - EdgeLabel: "subject_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_observation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|subject_Organization|Observation": { - FromType: "Organization", - EdgeLabel: "subject_Organization", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_observation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Observation|subject_Procedure|Procedure": { - FromType: "Observation", - EdgeLabel: "subject_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_observation", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|subject_Procedure|Observation": { - FromType: "Procedure", - EdgeLabel: "subject_Procedure", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_observation", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Observation|subject_Practitioner|Practitioner": { - FromType: "Observation", - EdgeLabel: "subject_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_observation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|subject_Practitioner|Observation": { - FromType: "Practitioner", - EdgeLabel: "subject_Practitioner", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_observation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Observation|subject_Medication|Medication": { - FromType: "Observation", - EdgeLabel: "subject_Medication", - ToType: "Medication", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_observation", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Medication|subject_Medication|Observation": { - FromType: "Medication", - EdgeLabel: "subject_Medication", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_observation", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Observation|subject_Substance|Substance": { - FromType: "Observation", - EdgeLabel: "subject_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_observation", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|subject_Substance|Observation": { - FromType: "Substance", - EdgeLabel: "subject_Substance", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_observation", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Observation|note_authorReference_Practitioner|Practitioner": { - FromType: "Observation", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|note_authorReference_Practitioner|Observation": { - FromType: "Practitioner", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Observation|note_authorReference_PractitionerRole|PractitionerRole": { - FromType: "Observation", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|note_authorReference_PractitionerRole|Observation": { - FromType: "PractitionerRole", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Observation|note_authorReference_Patient|Patient": { - FromType: "Observation", - EdgeLabel: "note_authorReference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|note_authorReference_Patient|Observation": { - FromType: "Patient", - EdgeLabel: "note_authorReference_Patient", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Observation|note_authorReference_Organization|Organization": { - FromType: "Observation", - EdgeLabel: "note_authorReference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|note_authorReference_Organization|Observation": { - FromType: "Organization", - EdgeLabel: "note_authorReference_Organization", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Observation|triggeredBy_observation|Observation": { - FromType: "Observation", - EdgeLabel: "triggeredBy_observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "observation_triggered_by", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "ObservationTriggeredBy|observation|Observation": { - FromType: "ObservationTriggeredBy", - EdgeLabel: "observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "observation_triggered_by", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|observation|ObservationTriggeredBy": { - FromType: "Observation", - EdgeLabel: "observation", - ToType: "ObservationTriggeredBy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "observation_triggered_by", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Organization|partOf|Organization": { - FromType: "Organization", - EdgeLabel: "partOf", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "organization", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|contact_organization|Organization": { - FromType: "Organization", - EdgeLabel: "contact_organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "extended_contact_detail", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|qualification_issuer|Organization": { - FromType: "Organization", - EdgeLabel: "qualification_issuer", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "organization_qualification", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "OrganizationQualification|issuer|Organization": { - FromType: "OrganizationQualification", - EdgeLabel: "issuer", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "organization_qualification", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|issuer|OrganizationQualification": { - FromType: "Organization", - EdgeLabel: "issuer", - ToType: "OrganizationQualification", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "organization_qualification", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Patient|generalPractitioner_Organization|Organization": { - FromType: "Patient", - EdgeLabel: "generalPractitioner_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "generalPractitioner_patient", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|generalPractitioner_Organization|Patient": { - FromType: "Organization", - EdgeLabel: "generalPractitioner_Organization", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "generalPractitioner_patient", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Patient|generalPractitioner_Practitioner|Practitioner": { - FromType: "Patient", - EdgeLabel: "generalPractitioner_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "generalPractitioner_patient", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|generalPractitioner_Practitioner|Patient": { - FromType: "Practitioner", - EdgeLabel: "generalPractitioner_Practitioner", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "generalPractitioner_patient", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Patient|generalPractitioner_PractitionerRole|PractitionerRole": { - FromType: "Patient", - EdgeLabel: "generalPractitioner_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "generalPractitioner_patient", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|generalPractitioner_PractitionerRole|Patient": { - FromType: "PractitionerRole", - EdgeLabel: "generalPractitioner_PractitionerRole", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "generalPractitioner_patient", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Patient|managingOrganization|Organization": { - FromType: "Patient", - EdgeLabel: "managingOrganization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "managingOrganization_patient", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|managingOrganization|Patient": { - FromType: "Organization", - EdgeLabel: "managingOrganization", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "managingOrganization_patient", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Patient|contact_organization|Organization": { - FromType: "Patient", - EdgeLabel: "contact_organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "patient_contact", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|contact_organization|Patient": { - FromType: "Organization", - EdgeLabel: "contact_organization", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "patient_contact", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Patient|link_other_Patient|Patient": { - FromType: "Patient", - EdgeLabel: "link_other_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "patient_link", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "PatientContact|organization|Organization": { - FromType: "PatientContact", - EdgeLabel: "organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "patient_contact", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|organization|PatientContact": { - FromType: "Organization", - EdgeLabel: "organization", - ToType: "PatientContact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "patient_contact", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "PatientLink|other_Patient|Patient": { - FromType: "PatientLink", - EdgeLabel: "other_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "patient_link", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|other_Patient|PatientLink": { - FromType: "Patient", - EdgeLabel: "other_Patient", - ToType: "PatientLink", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "patient_link", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Practitioner|qualification_issuer|Organization": { - FromType: "Practitioner", - EdgeLabel: "qualification_issuer", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "practitioner_qualification", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|qualification_issuer|Practitioner": { - FromType: "Organization", - EdgeLabel: "qualification_issuer", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "practitioner_qualification", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "PractitionerQualification|issuer|Organization": { - FromType: "PractitionerQualification", - EdgeLabel: "issuer", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "practitioner_qualification", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|issuer|PractitionerQualification": { - FromType: "Organization", - EdgeLabel: "issuer", - ToType: "PractitionerQualification", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "practitioner_qualification", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "PractitionerRole|organization|Organization": { - FromType: "PractitionerRole", - EdgeLabel: "organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "practitioner_role", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|organization|PractitionerRole": { - FromType: "Organization", - EdgeLabel: "organization", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "practitioner_role", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "PractitionerRole|practitioner|Practitioner": { - FromType: "PractitionerRole", - EdgeLabel: "practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "practitioner_role", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|practitioner|PractitionerRole": { - FromType: "Practitioner", - EdgeLabel: "practitioner", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "practitioner_role", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "PractitionerRole|contact_organization|Organization": { - FromType: "PractitionerRole", - EdgeLabel: "contact_organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "extended_contact_detail", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|contact_organization|PractitionerRole": { - FromType: "Organization", - EdgeLabel: "contact_organization", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "extended_contact_detail", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Procedure|focus_Patient|Patient": { - FromType: "Procedure", - EdgeLabel: "focus_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "focus_procedure", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|focus_Patient|Procedure": { - FromType: "Patient", - EdgeLabel: "focus_Patient", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "focus_procedure", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Procedure|focus_Group|Group": { - FromType: "Procedure", - EdgeLabel: "focus_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "focus_procedure", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|focus_Group|Procedure": { - FromType: "Group", - EdgeLabel: "focus_Group", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "focus_procedure", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Procedure|focus_Practitioner|Practitioner": { - FromType: "Procedure", - EdgeLabel: "focus_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "focus_procedure", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|focus_Practitioner|Procedure": { - FromType: "Practitioner", - EdgeLabel: "focus_Practitioner", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "focus_procedure", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Procedure|focus_Organization|Organization": { - FromType: "Procedure", - EdgeLabel: "focus_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "focus_procedure", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|focus_Organization|Procedure": { - FromType: "Organization", - EdgeLabel: "focus_Organization", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "focus_procedure", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Procedure|focus_PractitionerRole|PractitionerRole": { - FromType: "Procedure", - EdgeLabel: "focus_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "focus_procedure", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|focus_PractitionerRole|Procedure": { - FromType: "PractitionerRole", - EdgeLabel: "focus_PractitionerRole", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "focus_procedure", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Procedure|focus_Specimen|Specimen": { - FromType: "Procedure", - EdgeLabel: "focus_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "focus_procedure", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|focus_Specimen|Procedure": { - FromType: "Specimen", - EdgeLabel: "focus_Specimen", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "focus_procedure", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Procedure|partOf_Procedure|Procedure": { - FromType: "Procedure", - EdgeLabel: "partOf_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "partOf_procedure", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|partOf_Observation|Observation": { - FromType: "Procedure", - EdgeLabel: "partOf_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "partOf_procedure", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|partOf_Observation|Procedure": { - FromType: "Observation", - EdgeLabel: "partOf_Observation", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "partOf_procedure", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Procedure|partOf_MedicationAdministration|MedicationAdministration": { - FromType: "Procedure", - EdgeLabel: "partOf_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "partOf_procedure", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|partOf_MedicationAdministration|Procedure": { - FromType: "MedicationAdministration", - EdgeLabel: "partOf_MedicationAdministration", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "partOf_procedure", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "Procedure|recorder_Patient|Patient": { - FromType: "Procedure", - EdgeLabel: "recorder_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "recorder_procedure", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|recorder_Patient|Procedure": { - FromType: "Patient", - EdgeLabel: "recorder_Patient", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "recorder_procedure", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Procedure|recorder_Practitioner|Practitioner": { - FromType: "Procedure", - EdgeLabel: "recorder_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "recorder_procedure", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|recorder_Practitioner|Procedure": { - FromType: "Practitioner", - EdgeLabel: "recorder_Practitioner", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "recorder_procedure", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Procedure|recorder_PractitionerRole|PractitionerRole": { - FromType: "Procedure", - EdgeLabel: "recorder_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "recorder_procedure", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|recorder_PractitionerRole|Procedure": { - FromType: "PractitionerRole", - EdgeLabel: "recorder_PractitionerRole", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "recorder_procedure", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Procedure|report_DiagnosticReport|DiagnosticReport": { - FromType: "Procedure", - EdgeLabel: "report_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "report_procedure", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|report_DiagnosticReport|Procedure": { - FromType: "DiagnosticReport", - EdgeLabel: "report_DiagnosticReport", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "report_procedure", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "Procedure|report_DocumentReference|DocumentReference": { - FromType: "Procedure", - EdgeLabel: "report_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "report_procedure", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|report_DocumentReference|Procedure": { - FromType: "DocumentReference", - EdgeLabel: "report_DocumentReference", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "report_procedure", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "Procedure|reportedReference_Patient|Patient": { - FromType: "Procedure", - EdgeLabel: "reportedReference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "reportedReference_procedure", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|reportedReference_Patient|Procedure": { - FromType: "Patient", - EdgeLabel: "reportedReference_Patient", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "reportedReference_procedure", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Procedure|reportedReference_Practitioner|Practitioner": { - FromType: "Procedure", - EdgeLabel: "reportedReference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "reportedReference_procedure", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|reportedReference_Practitioner|Procedure": { - FromType: "Practitioner", - EdgeLabel: "reportedReference_Practitioner", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "reportedReference_procedure", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Procedure|reportedReference_PractitionerRole|PractitionerRole": { - FromType: "Procedure", - EdgeLabel: "reportedReference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "reportedReference_procedure", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|reportedReference_PractitionerRole|Procedure": { - FromType: "PractitionerRole", - EdgeLabel: "reportedReference_PractitionerRole", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "reportedReference_procedure", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Procedure|reportedReference_Organization|Organization": { - FromType: "Procedure", - EdgeLabel: "reportedReference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "reportedReference_procedure", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|reportedReference_Organization|Procedure": { - FromType: "Organization", - EdgeLabel: "reportedReference_Organization", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "reportedReference_procedure", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Procedure|subject_Patient|Patient": { - FromType: "Procedure", - EdgeLabel: "subject_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_procedure", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|subject_Patient|Procedure": { - FromType: "Patient", - EdgeLabel: "subject_Patient", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_procedure", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Procedure|subject_Group|Group": { - FromType: "Procedure", - EdgeLabel: "subject_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_procedure", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|subject_Group|Procedure": { - FromType: "Group", - EdgeLabel: "subject_Group", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_procedure", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Procedure|subject_Practitioner|Practitioner": { - FromType: "Procedure", - EdgeLabel: "subject_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_procedure", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|subject_Practitioner|Procedure": { - FromType: "Practitioner", - EdgeLabel: "subject_Practitioner", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_procedure", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Procedure|subject_Organization|Organization": { - FromType: "Procedure", - EdgeLabel: "subject_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_procedure", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|subject_Organization|Procedure": { - FromType: "Organization", - EdgeLabel: "subject_Organization", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "subject_procedure", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Procedure|supportingInfo_Organization|Organization": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|supportingInfo_Organization|Procedure": { - FromType: "Organization", - EdgeLabel: "supportingInfo_Organization", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Procedure|supportingInfo_Group|Group": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|supportingInfo_Group|Procedure": { - FromType: "Group", - EdgeLabel: "supportingInfo_Group", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Procedure|supportingInfo_Practitioner|Practitioner": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|supportingInfo_Practitioner|Procedure": { - FromType: "Practitioner", - EdgeLabel: "supportingInfo_Practitioner", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Procedure|supportingInfo_PractitionerRole|PractitionerRole": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|supportingInfo_PractitionerRole|Procedure": { - FromType: "PractitionerRole", - EdgeLabel: "supportingInfo_PractitionerRole", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Procedure|supportingInfo_ResearchStudy|ResearchStudy": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|supportingInfo_ResearchStudy|Procedure": { - FromType: "ResearchStudy", - EdgeLabel: "supportingInfo_ResearchStudy", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "Procedure|supportingInfo_Patient|Patient": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|supportingInfo_Patient|Procedure": { - FromType: "Patient", - EdgeLabel: "supportingInfo_Patient", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Procedure|supportingInfo_ResearchSubject|ResearchSubject": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_ResearchSubject", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchSubject|supportingInfo_ResearchSubject|Procedure": { - FromType: "ResearchSubject", - EdgeLabel: "supportingInfo_ResearchSubject", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "Procedure|supportingInfo_Substance|Substance": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|supportingInfo_Substance|Procedure": { - FromType: "Substance", - EdgeLabel: "supportingInfo_Substance", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Procedure|supportingInfo_SubstanceDefinition|SubstanceDefinition": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_SubstanceDefinition", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|supportingInfo_SubstanceDefinition|Procedure": { - FromType: "SubstanceDefinition", - EdgeLabel: "supportingInfo_SubstanceDefinition", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "Procedure|supportingInfo_Specimen|Specimen": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|supportingInfo_Specimen|Procedure": { - FromType: "Specimen", - EdgeLabel: "supportingInfo_Specimen", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Procedure|supportingInfo_Observation|Observation": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|supportingInfo_Observation|Procedure": { - FromType: "Observation", - EdgeLabel: "supportingInfo_Observation", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Procedure|supportingInfo_DiagnosticReport|DiagnosticReport": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|supportingInfo_DiagnosticReport|Procedure": { - FromType: "DiagnosticReport", - EdgeLabel: "supportingInfo_DiagnosticReport", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "Procedure|supportingInfo_Condition|Condition": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_Condition", - ToType: "Condition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Condition|supportingInfo_Condition|Procedure": { - FromType: "Condition", - EdgeLabel: "supportingInfo_Condition", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Procedure|supportingInfo_Medication|Medication": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_Medication", - ToType: "Medication", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Medication|supportingInfo_Medication|Procedure": { - FromType: "Medication", - EdgeLabel: "supportingInfo_Medication", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Procedure|supportingInfo_MedicationAdministration|MedicationAdministration": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|supportingInfo_MedicationAdministration|Procedure": { - FromType: "MedicationAdministration", - EdgeLabel: "supportingInfo_MedicationAdministration", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "Procedure|supportingInfo_MedicationStatement|MedicationStatement": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|supportingInfo_MedicationStatement|Procedure": { - FromType: "MedicationStatement", - EdgeLabel: "supportingInfo_MedicationStatement", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "Procedure|supportingInfo_MedicationRequest|MedicationRequest": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_MedicationRequest", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationRequest|supportingInfo_MedicationRequest|Procedure": { - FromType: "MedicationRequest", - EdgeLabel: "supportingInfo_MedicationRequest", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "Procedure|supportingInfo_Procedure|Procedure": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|supportingInfo_DocumentReference|DocumentReference": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|supportingInfo_DocumentReference|Procedure": { - FromType: "DocumentReference", - EdgeLabel: "supportingInfo_DocumentReference", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "Procedure|supportingInfo_Task|Task": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_Task", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Task|supportingInfo_Task|Procedure": { - FromType: "Task", - EdgeLabel: "supportingInfo_Task", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Procedure|supportingInfo_ImagingStudy|ImagingStudy": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|supportingInfo_ImagingStudy|Procedure": { - FromType: "ImagingStudy", - EdgeLabel: "supportingInfo_ImagingStudy", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "Procedure|supportingInfo_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_FamilyMemberHistory", - ToType: "FamilyMemberHistory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "FamilyMemberHistory|supportingInfo_FamilyMemberHistory|Procedure": { - FromType: "FamilyMemberHistory", - EdgeLabel: "supportingInfo_FamilyMemberHistory", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "Procedure|supportingInfo_BodyStructure|BodyStructure": { - FromType: "Procedure", - EdgeLabel: "supportingInfo_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|supportingInfo_BodyStructure|Procedure": { - FromType: "BodyStructure", - EdgeLabel: "supportingInfo_BodyStructure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supportingInfo_procedure", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "Procedure|complication_reference_Organization|Organization": { - FromType: "Procedure", - EdgeLabel: "complication_reference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|complication_reference_Organization|Procedure": { - FromType: "Organization", - EdgeLabel: "complication_reference_Organization", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Procedure|complication_reference_Group|Group": { - FromType: "Procedure", - EdgeLabel: "complication_reference_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|complication_reference_Group|Procedure": { - FromType: "Group", - EdgeLabel: "complication_reference_Group", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Procedure|complication_reference_Practitioner|Practitioner": { - FromType: "Procedure", - EdgeLabel: "complication_reference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|complication_reference_Practitioner|Procedure": { - FromType: "Practitioner", - EdgeLabel: "complication_reference_Practitioner", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Procedure|complication_reference_PractitionerRole|PractitionerRole": { - FromType: "Procedure", - EdgeLabel: "complication_reference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|complication_reference_PractitionerRole|Procedure": { - FromType: "PractitionerRole", - EdgeLabel: "complication_reference_PractitionerRole", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Procedure|complication_reference_ResearchStudy|ResearchStudy": { - FromType: "Procedure", - EdgeLabel: "complication_reference_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|complication_reference_ResearchStudy|Procedure": { - FromType: "ResearchStudy", - EdgeLabel: "complication_reference_ResearchStudy", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "Procedure|complication_reference_Patient|Patient": { - FromType: "Procedure", - EdgeLabel: "complication_reference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|complication_reference_Patient|Procedure": { - FromType: "Patient", - EdgeLabel: "complication_reference_Patient", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Procedure|complication_reference_ResearchSubject|ResearchSubject": { - FromType: "Procedure", - EdgeLabel: "complication_reference_ResearchSubject", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchSubject|complication_reference_ResearchSubject|Procedure": { - FromType: "ResearchSubject", - EdgeLabel: "complication_reference_ResearchSubject", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "Procedure|complication_reference_Substance|Substance": { - FromType: "Procedure", - EdgeLabel: "complication_reference_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|complication_reference_Substance|Procedure": { - FromType: "Substance", - EdgeLabel: "complication_reference_Substance", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Procedure|complication_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "Procedure", - EdgeLabel: "complication_reference_SubstanceDefinition", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|complication_reference_SubstanceDefinition|Procedure": { - FromType: "SubstanceDefinition", - EdgeLabel: "complication_reference_SubstanceDefinition", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "Procedure|complication_reference_Specimen|Specimen": { - FromType: "Procedure", - EdgeLabel: "complication_reference_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|complication_reference_Specimen|Procedure": { - FromType: "Specimen", - EdgeLabel: "complication_reference_Specimen", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Procedure|complication_reference_Observation|Observation": { - FromType: "Procedure", - EdgeLabel: "complication_reference_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|complication_reference_Observation|Procedure": { - FromType: "Observation", - EdgeLabel: "complication_reference_Observation", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Procedure|complication_reference_DiagnosticReport|DiagnosticReport": { - FromType: "Procedure", - EdgeLabel: "complication_reference_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|complication_reference_DiagnosticReport|Procedure": { - FromType: "DiagnosticReport", - EdgeLabel: "complication_reference_DiagnosticReport", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "Procedure|complication_reference_Condition|Condition": { - FromType: "Procedure", - EdgeLabel: "complication_reference_Condition", - ToType: "Condition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Condition|complication_reference_Condition|Procedure": { - FromType: "Condition", - EdgeLabel: "complication_reference_Condition", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Procedure|complication_reference_Medication|Medication": { - FromType: "Procedure", - EdgeLabel: "complication_reference_Medication", - ToType: "Medication", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Medication|complication_reference_Medication|Procedure": { - FromType: "Medication", - EdgeLabel: "complication_reference_Medication", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Procedure|complication_reference_MedicationAdministration|MedicationAdministration": { - FromType: "Procedure", - EdgeLabel: "complication_reference_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|complication_reference_MedicationAdministration|Procedure": { - FromType: "MedicationAdministration", - EdgeLabel: "complication_reference_MedicationAdministration", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "Procedure|complication_reference_MedicationStatement|MedicationStatement": { - FromType: "Procedure", - EdgeLabel: "complication_reference_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|complication_reference_MedicationStatement|Procedure": { - FromType: "MedicationStatement", - EdgeLabel: "complication_reference_MedicationStatement", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "Procedure|complication_reference_MedicationRequest|MedicationRequest": { - FromType: "Procedure", - EdgeLabel: "complication_reference_MedicationRequest", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationRequest|complication_reference_MedicationRequest|Procedure": { - FromType: "MedicationRequest", - EdgeLabel: "complication_reference_MedicationRequest", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "Procedure|complication_reference_Procedure|Procedure": { - FromType: "Procedure", - EdgeLabel: "complication_reference_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|complication_reference_DocumentReference|DocumentReference": { - FromType: "Procedure", - EdgeLabel: "complication_reference_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|complication_reference_DocumentReference|Procedure": { - FromType: "DocumentReference", - EdgeLabel: "complication_reference_DocumentReference", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "Procedure|complication_reference_Task|Task": { - FromType: "Procedure", - EdgeLabel: "complication_reference_Task", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Task|complication_reference_Task|Procedure": { - FromType: "Task", - EdgeLabel: "complication_reference_Task", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Procedure|complication_reference_ImagingStudy|ImagingStudy": { - FromType: "Procedure", - EdgeLabel: "complication_reference_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|complication_reference_ImagingStudy|Procedure": { - FromType: "ImagingStudy", - EdgeLabel: "complication_reference_ImagingStudy", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "Procedure|complication_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "Procedure", - EdgeLabel: "complication_reference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "FamilyMemberHistory|complication_reference_FamilyMemberHistory|Procedure": { - FromType: "FamilyMemberHistory", - EdgeLabel: "complication_reference_FamilyMemberHistory", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "Procedure|complication_reference_BodyStructure|BodyStructure": { - FromType: "Procedure", - EdgeLabel: "complication_reference_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|complication_reference_BodyStructure|Procedure": { - FromType: "BodyStructure", - EdgeLabel: "complication_reference_BodyStructure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "Procedure|note_authorReference_Practitioner|Practitioner": { - FromType: "Procedure", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|note_authorReference_Practitioner|Procedure": { - FromType: "Practitioner", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Procedure|note_authorReference_PractitionerRole|PractitionerRole": { - FromType: "Procedure", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|note_authorReference_PractitionerRole|Procedure": { - FromType: "PractitionerRole", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Procedure|note_authorReference_Patient|Patient": { - FromType: "Procedure", - EdgeLabel: "note_authorReference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|note_authorReference_Patient|Procedure": { - FromType: "Patient", - EdgeLabel: "note_authorReference_Patient", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Procedure|note_authorReference_Organization|Organization": { - FromType: "Procedure", - EdgeLabel: "note_authorReference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|note_authorReference_Organization|Procedure": { - FromType: "Organization", - EdgeLabel: "note_authorReference_Organization", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Procedure|performer_actor_Practitioner|Practitioner": { - FromType: "Procedure", - EdgeLabel: "performer_actor_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actor_procedure_performer", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|performer_actor_Practitioner|Procedure": { - FromType: "Practitioner", - EdgeLabel: "performer_actor_Practitioner", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actor_procedure_performer", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Procedure|performer_actor_PractitionerRole|PractitionerRole": { - FromType: "Procedure", - EdgeLabel: "performer_actor_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actor_procedure_performer", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|performer_actor_PractitionerRole|Procedure": { - FromType: "PractitionerRole", - EdgeLabel: "performer_actor_PractitionerRole", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actor_procedure_performer", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Procedure|performer_actor_Organization|Organization": { - FromType: "Procedure", - EdgeLabel: "performer_actor_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actor_procedure_performer", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|performer_actor_Organization|Procedure": { - FromType: "Organization", - EdgeLabel: "performer_actor_Organization", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actor_procedure_performer", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Procedure|performer_actor_Patient|Patient": { - FromType: "Procedure", - EdgeLabel: "performer_actor_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actor_procedure_performer", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|performer_actor_Patient|Procedure": { - FromType: "Patient", - EdgeLabel: "performer_actor_Patient", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actor_procedure_performer", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Procedure|performer_onBehalfOf|Organization": { - FromType: "Procedure", - EdgeLabel: "performer_onBehalfOf", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "onBehalfOf_procedure_performer", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|performer_onBehalfOf|Procedure": { - FromType: "Organization", - EdgeLabel: "performer_onBehalfOf", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "onBehalfOf_procedure_performer", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Procedure|reason_reference_Organization|Organization": { - FromType: "Procedure", - EdgeLabel: "reason_reference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|reason_reference_Organization|Procedure": { - FromType: "Organization", - EdgeLabel: "reason_reference_Organization", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Procedure|reason_reference_Group|Group": { - FromType: "Procedure", - EdgeLabel: "reason_reference_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|reason_reference_Group|Procedure": { - FromType: "Group", - EdgeLabel: "reason_reference_Group", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Procedure|reason_reference_Practitioner|Practitioner": { - FromType: "Procedure", - EdgeLabel: "reason_reference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|reason_reference_Practitioner|Procedure": { - FromType: "Practitioner", - EdgeLabel: "reason_reference_Practitioner", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Procedure|reason_reference_PractitionerRole|PractitionerRole": { - FromType: "Procedure", - EdgeLabel: "reason_reference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|reason_reference_PractitionerRole|Procedure": { - FromType: "PractitionerRole", - EdgeLabel: "reason_reference_PractitionerRole", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Procedure|reason_reference_ResearchStudy|ResearchStudy": { - FromType: "Procedure", - EdgeLabel: "reason_reference_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|reason_reference_ResearchStudy|Procedure": { - FromType: "ResearchStudy", - EdgeLabel: "reason_reference_ResearchStudy", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "Procedure|reason_reference_Patient|Patient": { - FromType: "Procedure", - EdgeLabel: "reason_reference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|reason_reference_Patient|Procedure": { - FromType: "Patient", - EdgeLabel: "reason_reference_Patient", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Procedure|reason_reference_ResearchSubject|ResearchSubject": { - FromType: "Procedure", - EdgeLabel: "reason_reference_ResearchSubject", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchSubject|reason_reference_ResearchSubject|Procedure": { - FromType: "ResearchSubject", - EdgeLabel: "reason_reference_ResearchSubject", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "Procedure|reason_reference_Substance|Substance": { - FromType: "Procedure", - EdgeLabel: "reason_reference_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|reason_reference_Substance|Procedure": { - FromType: "Substance", - EdgeLabel: "reason_reference_Substance", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Procedure|reason_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "Procedure", - EdgeLabel: "reason_reference_SubstanceDefinition", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|reason_reference_SubstanceDefinition|Procedure": { - FromType: "SubstanceDefinition", - EdgeLabel: "reason_reference_SubstanceDefinition", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "Procedure|reason_reference_Specimen|Specimen": { - FromType: "Procedure", - EdgeLabel: "reason_reference_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|reason_reference_Specimen|Procedure": { - FromType: "Specimen", - EdgeLabel: "reason_reference_Specimen", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Procedure|reason_reference_Observation|Observation": { - FromType: "Procedure", - EdgeLabel: "reason_reference_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|reason_reference_Observation|Procedure": { - FromType: "Observation", - EdgeLabel: "reason_reference_Observation", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Procedure|reason_reference_DiagnosticReport|DiagnosticReport": { - FromType: "Procedure", - EdgeLabel: "reason_reference_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|reason_reference_DiagnosticReport|Procedure": { - FromType: "DiagnosticReport", - EdgeLabel: "reason_reference_DiagnosticReport", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "Procedure|reason_reference_Condition|Condition": { - FromType: "Procedure", - EdgeLabel: "reason_reference_Condition", - ToType: "Condition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Condition|reason_reference_Condition|Procedure": { - FromType: "Condition", - EdgeLabel: "reason_reference_Condition", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Procedure|reason_reference_Medication|Medication": { - FromType: "Procedure", - EdgeLabel: "reason_reference_Medication", - ToType: "Medication", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Medication|reason_reference_Medication|Procedure": { - FromType: "Medication", - EdgeLabel: "reason_reference_Medication", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Procedure|reason_reference_MedicationAdministration|MedicationAdministration": { - FromType: "Procedure", - EdgeLabel: "reason_reference_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|reason_reference_MedicationAdministration|Procedure": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_MedicationAdministration", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "Procedure|reason_reference_MedicationStatement|MedicationStatement": { - FromType: "Procedure", - EdgeLabel: "reason_reference_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|reason_reference_MedicationStatement|Procedure": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_MedicationStatement", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "Procedure|reason_reference_MedicationRequest|MedicationRequest": { - FromType: "Procedure", - EdgeLabel: "reason_reference_MedicationRequest", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationRequest|reason_reference_MedicationRequest|Procedure": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_MedicationRequest", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "Procedure|reason_reference_Procedure|Procedure": { - FromType: "Procedure", - EdgeLabel: "reason_reference_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|reason_reference_DocumentReference|DocumentReference": { - FromType: "Procedure", - EdgeLabel: "reason_reference_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|reason_reference_DocumentReference|Procedure": { - FromType: "DocumentReference", - EdgeLabel: "reason_reference_DocumentReference", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "Procedure|reason_reference_Task|Task": { - FromType: "Procedure", - EdgeLabel: "reason_reference_Task", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Task|reason_reference_Task|Procedure": { - FromType: "Task", - EdgeLabel: "reason_reference_Task", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Procedure|reason_reference_ImagingStudy|ImagingStudy": { - FromType: "Procedure", - EdgeLabel: "reason_reference_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|reason_reference_ImagingStudy|Procedure": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_ImagingStudy", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "Procedure|reason_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "Procedure", - EdgeLabel: "reason_reference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "FamilyMemberHistory|reason_reference_FamilyMemberHistory|Procedure": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_FamilyMemberHistory", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "Procedure|reason_reference_BodyStructure|BodyStructure": { - FromType: "Procedure", - EdgeLabel: "reason_reference_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|reason_reference_BodyStructure|Procedure": { - FromType: "BodyStructure", - EdgeLabel: "reason_reference_BodyStructure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "Procedure|used_reference_Organization|Organization": { - FromType: "Procedure", - EdgeLabel: "used_reference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|used_reference_Organization|Procedure": { - FromType: "Organization", - EdgeLabel: "used_reference_Organization", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Procedure|used_reference_Group|Group": { - FromType: "Procedure", - EdgeLabel: "used_reference_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|used_reference_Group|Procedure": { - FromType: "Group", - EdgeLabel: "used_reference_Group", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Procedure|used_reference_Practitioner|Practitioner": { - FromType: "Procedure", - EdgeLabel: "used_reference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|used_reference_Practitioner|Procedure": { - FromType: "Practitioner", - EdgeLabel: "used_reference_Practitioner", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Procedure|used_reference_PractitionerRole|PractitionerRole": { - FromType: "Procedure", - EdgeLabel: "used_reference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|used_reference_PractitionerRole|Procedure": { - FromType: "PractitionerRole", - EdgeLabel: "used_reference_PractitionerRole", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Procedure|used_reference_ResearchStudy|ResearchStudy": { - FromType: "Procedure", - EdgeLabel: "used_reference_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|used_reference_ResearchStudy|Procedure": { - FromType: "ResearchStudy", - EdgeLabel: "used_reference_ResearchStudy", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "Procedure|used_reference_Patient|Patient": { - FromType: "Procedure", - EdgeLabel: "used_reference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|used_reference_Patient|Procedure": { - FromType: "Patient", - EdgeLabel: "used_reference_Patient", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Procedure|used_reference_ResearchSubject|ResearchSubject": { - FromType: "Procedure", - EdgeLabel: "used_reference_ResearchSubject", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchSubject|used_reference_ResearchSubject|Procedure": { - FromType: "ResearchSubject", - EdgeLabel: "used_reference_ResearchSubject", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "Procedure|used_reference_Substance|Substance": { - FromType: "Procedure", - EdgeLabel: "used_reference_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|used_reference_Substance|Procedure": { - FromType: "Substance", - EdgeLabel: "used_reference_Substance", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Procedure|used_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "Procedure", - EdgeLabel: "used_reference_SubstanceDefinition", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|used_reference_SubstanceDefinition|Procedure": { - FromType: "SubstanceDefinition", - EdgeLabel: "used_reference_SubstanceDefinition", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "Procedure|used_reference_Specimen|Specimen": { - FromType: "Procedure", - EdgeLabel: "used_reference_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|used_reference_Specimen|Procedure": { - FromType: "Specimen", - EdgeLabel: "used_reference_Specimen", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Procedure|used_reference_Observation|Observation": { - FromType: "Procedure", - EdgeLabel: "used_reference_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|used_reference_Observation|Procedure": { - FromType: "Observation", - EdgeLabel: "used_reference_Observation", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Procedure|used_reference_DiagnosticReport|DiagnosticReport": { - FromType: "Procedure", - EdgeLabel: "used_reference_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|used_reference_DiagnosticReport|Procedure": { - FromType: "DiagnosticReport", - EdgeLabel: "used_reference_DiagnosticReport", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "Procedure|used_reference_Condition|Condition": { - FromType: "Procedure", - EdgeLabel: "used_reference_Condition", - ToType: "Condition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Condition|used_reference_Condition|Procedure": { - FromType: "Condition", - EdgeLabel: "used_reference_Condition", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Procedure|used_reference_Medication|Medication": { - FromType: "Procedure", - EdgeLabel: "used_reference_Medication", - ToType: "Medication", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Medication|used_reference_Medication|Procedure": { - FromType: "Medication", - EdgeLabel: "used_reference_Medication", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Procedure|used_reference_MedicationAdministration|MedicationAdministration": { - FromType: "Procedure", - EdgeLabel: "used_reference_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|used_reference_MedicationAdministration|Procedure": { - FromType: "MedicationAdministration", - EdgeLabel: "used_reference_MedicationAdministration", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "Procedure|used_reference_MedicationStatement|MedicationStatement": { - FromType: "Procedure", - EdgeLabel: "used_reference_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|used_reference_MedicationStatement|Procedure": { - FromType: "MedicationStatement", - EdgeLabel: "used_reference_MedicationStatement", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "Procedure|used_reference_MedicationRequest|MedicationRequest": { - FromType: "Procedure", - EdgeLabel: "used_reference_MedicationRequest", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationRequest|used_reference_MedicationRequest|Procedure": { - FromType: "MedicationRequest", - EdgeLabel: "used_reference_MedicationRequest", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "Procedure|used_reference_Procedure|Procedure": { - FromType: "Procedure", - EdgeLabel: "used_reference_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|used_reference_DocumentReference|DocumentReference": { - FromType: "Procedure", - EdgeLabel: "used_reference_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|used_reference_DocumentReference|Procedure": { - FromType: "DocumentReference", - EdgeLabel: "used_reference_DocumentReference", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "Procedure|used_reference_Task|Task": { - FromType: "Procedure", - EdgeLabel: "used_reference_Task", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Task|used_reference_Task|Procedure": { - FromType: "Task", - EdgeLabel: "used_reference_Task", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Procedure|used_reference_ImagingStudy|ImagingStudy": { - FromType: "Procedure", - EdgeLabel: "used_reference_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|used_reference_ImagingStudy|Procedure": { - FromType: "ImagingStudy", - EdgeLabel: "used_reference_ImagingStudy", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "Procedure|used_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "Procedure", - EdgeLabel: "used_reference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "FamilyMemberHistory|used_reference_FamilyMemberHistory|Procedure": { - FromType: "FamilyMemberHistory", - EdgeLabel: "used_reference_FamilyMemberHistory", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "Procedure|used_reference_BodyStructure|BodyStructure": { - FromType: "Procedure", - EdgeLabel: "used_reference_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|used_reference_BodyStructure|Procedure": { - FromType: "BodyStructure", - EdgeLabel: "used_reference_BodyStructure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "ProcedurePerformer|actor_Practitioner|Practitioner": { - FromType: "ProcedurePerformer", - EdgeLabel: "actor_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actor_procedure_performer", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|actor_Practitioner|ProcedurePerformer": { - FromType: "Practitioner", - EdgeLabel: "actor_Practitioner", - ToType: "ProcedurePerformer", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actor_procedure_performer", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "ProcedurePerformer|actor_PractitionerRole|PractitionerRole": { - FromType: "ProcedurePerformer", - EdgeLabel: "actor_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actor_procedure_performer", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|actor_PractitionerRole|ProcedurePerformer": { - FromType: "PractitionerRole", - EdgeLabel: "actor_PractitionerRole", - ToType: "ProcedurePerformer", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actor_procedure_performer", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "ProcedurePerformer|actor_Organization|Organization": { - FromType: "ProcedurePerformer", - EdgeLabel: "actor_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actor_procedure_performer", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|actor_Organization|ProcedurePerformer": { - FromType: "Organization", - EdgeLabel: "actor_Organization", - ToType: "ProcedurePerformer", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actor_procedure_performer", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "ProcedurePerformer|actor_Patient|Patient": { - FromType: "ProcedurePerformer", - EdgeLabel: "actor_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actor_procedure_performer", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|actor_Patient|ProcedurePerformer": { - FromType: "Patient", - EdgeLabel: "actor_Patient", - ToType: "ProcedurePerformer", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actor_procedure_performer", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "ProcedurePerformer|onBehalfOf|Organization": { - FromType: "ProcedurePerformer", - EdgeLabel: "onBehalfOf", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "onBehalfOf_procedure_performer", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|onBehalfOf|ProcedurePerformer": { - FromType: "Organization", - EdgeLabel: "onBehalfOf", - ToType: "ProcedurePerformer", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "onBehalfOf_procedure_performer", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "RelatedArtifact|resourceReference_Organization|Organization": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|resourceReference_Organization|RelatedArtifact": { - FromType: "Organization", - EdgeLabel: "resourceReference_Organization", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "RelatedArtifact|resourceReference_Group|Group": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|resourceReference_Group|RelatedArtifact": { - FromType: "Group", - EdgeLabel: "resourceReference_Group", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "RelatedArtifact|resourceReference_Practitioner|Practitioner": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|resourceReference_Practitioner|RelatedArtifact": { - FromType: "Practitioner", - EdgeLabel: "resourceReference_Practitioner", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "RelatedArtifact|resourceReference_PractitionerRole|PractitionerRole": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|resourceReference_PractitionerRole|RelatedArtifact": { - FromType: "PractitionerRole", - EdgeLabel: "resourceReference_PractitionerRole", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "RelatedArtifact|resourceReference_ResearchStudy|ResearchStudy": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|resourceReference_ResearchStudy|RelatedArtifact": { - FromType: "ResearchStudy", - EdgeLabel: "resourceReference_ResearchStudy", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "RelatedArtifact|resourceReference_Patient|Patient": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|resourceReference_Patient|RelatedArtifact": { - FromType: "Patient", - EdgeLabel: "resourceReference_Patient", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "RelatedArtifact|resourceReference_ResearchSubject|ResearchSubject": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_ResearchSubject", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchSubject|resourceReference_ResearchSubject|RelatedArtifact": { - FromType: "ResearchSubject", - EdgeLabel: "resourceReference_ResearchSubject", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "RelatedArtifact|resourceReference_Substance|Substance": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|resourceReference_Substance|RelatedArtifact": { - FromType: "Substance", - EdgeLabel: "resourceReference_Substance", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "RelatedArtifact|resourceReference_SubstanceDefinition|SubstanceDefinition": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_SubstanceDefinition", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|resourceReference_SubstanceDefinition|RelatedArtifact": { - FromType: "SubstanceDefinition", - EdgeLabel: "resourceReference_SubstanceDefinition", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "RelatedArtifact|resourceReference_Specimen|Specimen": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|resourceReference_Specimen|RelatedArtifact": { - FromType: "Specimen", - EdgeLabel: "resourceReference_Specimen", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "RelatedArtifact|resourceReference_Observation|Observation": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|resourceReference_Observation|RelatedArtifact": { - FromType: "Observation", - EdgeLabel: "resourceReference_Observation", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "RelatedArtifact|resourceReference_DiagnosticReport|DiagnosticReport": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|resourceReference_DiagnosticReport|RelatedArtifact": { - FromType: "DiagnosticReport", - EdgeLabel: "resourceReference_DiagnosticReport", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "RelatedArtifact|resourceReference_Condition|Condition": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_Condition", - ToType: "Condition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Condition|resourceReference_Condition|RelatedArtifact": { - FromType: "Condition", - EdgeLabel: "resourceReference_Condition", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "RelatedArtifact|resourceReference_Medication|Medication": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_Medication", - ToType: "Medication", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Medication|resourceReference_Medication|RelatedArtifact": { - FromType: "Medication", - EdgeLabel: "resourceReference_Medication", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "RelatedArtifact|resourceReference_MedicationAdministration|MedicationAdministration": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|resourceReference_MedicationAdministration|RelatedArtifact": { - FromType: "MedicationAdministration", - EdgeLabel: "resourceReference_MedicationAdministration", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "RelatedArtifact|resourceReference_MedicationStatement|MedicationStatement": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|resourceReference_MedicationStatement|RelatedArtifact": { - FromType: "MedicationStatement", - EdgeLabel: "resourceReference_MedicationStatement", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "RelatedArtifact|resourceReference_MedicationRequest|MedicationRequest": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_MedicationRequest", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationRequest|resourceReference_MedicationRequest|RelatedArtifact": { - FromType: "MedicationRequest", - EdgeLabel: "resourceReference_MedicationRequest", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "RelatedArtifact|resourceReference_Procedure|Procedure": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|resourceReference_Procedure|RelatedArtifact": { - FromType: "Procedure", - EdgeLabel: "resourceReference_Procedure", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "RelatedArtifact|resourceReference_DocumentReference|DocumentReference": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|resourceReference_DocumentReference|RelatedArtifact": { - FromType: "DocumentReference", - EdgeLabel: "resourceReference_DocumentReference", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "RelatedArtifact|resourceReference_Task|Task": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_Task", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Task|resourceReference_Task|RelatedArtifact": { - FromType: "Task", - EdgeLabel: "resourceReference_Task", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "RelatedArtifact|resourceReference_ImagingStudy|ImagingStudy": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|resourceReference_ImagingStudy|RelatedArtifact": { - FromType: "ImagingStudy", - EdgeLabel: "resourceReference_ImagingStudy", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "RelatedArtifact|resourceReference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "FamilyMemberHistory|resourceReference_FamilyMemberHistory|RelatedArtifact": { - FromType: "FamilyMemberHistory", - EdgeLabel: "resourceReference_FamilyMemberHistory", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "RelatedArtifact|resourceReference_BodyStructure|BodyStructure": { - FromType: "RelatedArtifact", - EdgeLabel: "resourceReference_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|resourceReference_BodyStructure|RelatedArtifact": { - FromType: "BodyStructure", - EdgeLabel: "resourceReference_BodyStructure", - ToType: "RelatedArtifact", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "ResearchStudy|rootDir_Directory|Directory": { - FromType: "ResearchStudy", - EdgeLabel: "rootDir_Directory", - ToType: "Directory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{}, - RegexMatch: []string{ - "Directory/*", - }, - }, - "Directory|rootDir_Directory|ResearchStudy": { - FromType: "Directory", - EdgeLabel: "rootDir_Directory", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{}, - RegexMatch: []string{ - "Directory/*", - }, - }, - "ResearchStudy|partOf|ResearchStudy": { - FromType: "ResearchStudy", - EdgeLabel: "partOf", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "partOf_research_study", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|result_DiagnosticReport|DiagnosticReport": { - FromType: "ResearchStudy", - EdgeLabel: "result_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "result_research_study", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|result_DiagnosticReport|ResearchStudy": { - FromType: "DiagnosticReport", - EdgeLabel: "result_DiagnosticReport", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "result_research_study", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "ResearchStudy|site_ResearchStudy|ResearchStudy": { - FromType: "ResearchStudy", - EdgeLabel: "site_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "site_research_study", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|site_Organization|Organization": { - FromType: "ResearchStudy", - EdgeLabel: "site_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "site_research_study", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|site_Organization|ResearchStudy": { - FromType: "Organization", - EdgeLabel: "site_Organization", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "site_research_study", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "ResearchStudy|associatedParty_party_Practitioner|Practitioner": { - FromType: "ResearchStudy", - EdgeLabel: "associatedParty_party_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_study_associated_party", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|associatedParty_party_Practitioner|ResearchStudy": { - FromType: "Practitioner", - EdgeLabel: "associatedParty_party_Practitioner", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_study_associated_party", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "ResearchStudy|associatedParty_party_PractitionerRole|PractitionerRole": { - FromType: "ResearchStudy", - EdgeLabel: "associatedParty_party_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_study_associated_party", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|associatedParty_party_PractitionerRole|ResearchStudy": { - FromType: "PractitionerRole", - EdgeLabel: "associatedParty_party_PractitionerRole", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_study_associated_party", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "ResearchStudy|associatedParty_party_Organization|Organization": { - FromType: "ResearchStudy", - EdgeLabel: "associatedParty_party_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_study_associated_party", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|associatedParty_party_Organization|ResearchStudy": { - FromType: "Organization", - EdgeLabel: "associatedParty_party_Organization", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_study_associated_party", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "ResearchStudy|comparisonGroup_observedGroup|Group": { - FromType: "ResearchStudy", - EdgeLabel: "comparisonGroup_observedGroup", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_study_comparison_group", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|comparisonGroup_observedGroup|ResearchStudy": { - FromType: "Group", - EdgeLabel: "comparisonGroup_observedGroup", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_study_comparison_group", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "ResearchStudy|focus_reference_Organization|Organization": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|focus_reference_Organization|ResearchStudy": { - FromType: "Organization", - EdgeLabel: "focus_reference_Organization", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "ResearchStudy|focus_reference_Group|Group": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|focus_reference_Group|ResearchStudy": { - FromType: "Group", - EdgeLabel: "focus_reference_Group", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "ResearchStudy|focus_reference_Practitioner|Practitioner": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|focus_reference_Practitioner|ResearchStudy": { - FromType: "Practitioner", - EdgeLabel: "focus_reference_Practitioner", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "ResearchStudy|focus_reference_PractitionerRole|PractitionerRole": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|focus_reference_PractitionerRole|ResearchStudy": { - FromType: "PractitionerRole", - EdgeLabel: "focus_reference_PractitionerRole", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "ResearchStudy|focus_reference_ResearchStudy|ResearchStudy": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|focus_reference_Patient|Patient": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|focus_reference_Patient|ResearchStudy": { - FromType: "Patient", - EdgeLabel: "focus_reference_Patient", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "ResearchStudy|focus_reference_ResearchSubject|ResearchSubject": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_ResearchSubject", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchSubject|focus_reference_ResearchSubject|ResearchStudy": { - FromType: "ResearchSubject", - EdgeLabel: "focus_reference_ResearchSubject", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchStudy|focus_reference_Substance|Substance": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|focus_reference_Substance|ResearchStudy": { - FromType: "Substance", - EdgeLabel: "focus_reference_Substance", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "ResearchStudy|focus_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_SubstanceDefinition", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|focus_reference_SubstanceDefinition|ResearchStudy": { - FromType: "SubstanceDefinition", - EdgeLabel: "focus_reference_SubstanceDefinition", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "ResearchStudy|focus_reference_Specimen|Specimen": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|focus_reference_Specimen|ResearchStudy": { - FromType: "Specimen", - EdgeLabel: "focus_reference_Specimen", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "ResearchStudy|focus_reference_Observation|Observation": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|focus_reference_Observation|ResearchStudy": { - FromType: "Observation", - EdgeLabel: "focus_reference_Observation", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "ResearchStudy|focus_reference_DiagnosticReport|DiagnosticReport": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|focus_reference_DiagnosticReport|ResearchStudy": { - FromType: "DiagnosticReport", - EdgeLabel: "focus_reference_DiagnosticReport", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "ResearchStudy|focus_reference_Condition|Condition": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_Condition", - ToType: "Condition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Condition|focus_reference_Condition|ResearchStudy": { - FromType: "Condition", - EdgeLabel: "focus_reference_Condition", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "ResearchStudy|focus_reference_Medication|Medication": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_Medication", - ToType: "Medication", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Medication|focus_reference_Medication|ResearchStudy": { - FromType: "Medication", - EdgeLabel: "focus_reference_Medication", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "ResearchStudy|focus_reference_MedicationAdministration|MedicationAdministration": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|focus_reference_MedicationAdministration|ResearchStudy": { - FromType: "MedicationAdministration", - EdgeLabel: "focus_reference_MedicationAdministration", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "ResearchStudy|focus_reference_MedicationStatement|MedicationStatement": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|focus_reference_MedicationStatement|ResearchStudy": { - FromType: "MedicationStatement", - EdgeLabel: "focus_reference_MedicationStatement", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "ResearchStudy|focus_reference_MedicationRequest|MedicationRequest": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_MedicationRequest", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationRequest|focus_reference_MedicationRequest|ResearchStudy": { - FromType: "MedicationRequest", - EdgeLabel: "focus_reference_MedicationRequest", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "ResearchStudy|focus_reference_Procedure|Procedure": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|focus_reference_Procedure|ResearchStudy": { - FromType: "Procedure", - EdgeLabel: "focus_reference_Procedure", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "ResearchStudy|focus_reference_DocumentReference|DocumentReference": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|focus_reference_DocumentReference|ResearchStudy": { - FromType: "DocumentReference", - EdgeLabel: "focus_reference_DocumentReference", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "ResearchStudy|focus_reference_Task|Task": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_Task", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Task|focus_reference_Task|ResearchStudy": { - FromType: "Task", - EdgeLabel: "focus_reference_Task", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "ResearchStudy|focus_reference_ImagingStudy|ImagingStudy": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|focus_reference_ImagingStudy|ResearchStudy": { - FromType: "ImagingStudy", - EdgeLabel: "focus_reference_ImagingStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ResearchStudy|focus_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "FamilyMemberHistory|focus_reference_FamilyMemberHistory|ResearchStudy": { - FromType: "FamilyMemberHistory", - EdgeLabel: "focus_reference_FamilyMemberHistory", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "ResearchStudy|focus_reference_BodyStructure|BodyStructure": { - FromType: "ResearchStudy", - EdgeLabel: "focus_reference_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|focus_reference_BodyStructure|ResearchStudy": { - FromType: "BodyStructure", - EdgeLabel: "focus_reference_BodyStructure", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "ResearchStudy|note_authorReference_Practitioner|Practitioner": { - FromType: "ResearchStudy", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|note_authorReference_Practitioner|ResearchStudy": { - FromType: "Practitioner", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "ResearchStudy|note_authorReference_PractitionerRole|PractitionerRole": { - FromType: "ResearchStudy", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|note_authorReference_PractitionerRole|ResearchStudy": { - FromType: "PractitionerRole", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "ResearchStudy|note_authorReference_Patient|Patient": { - FromType: "ResearchStudy", - EdgeLabel: "note_authorReference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|note_authorReference_Patient|ResearchStudy": { - FromType: "Patient", - EdgeLabel: "note_authorReference_Patient", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "ResearchStudy|note_authorReference_Organization|Organization": { - FromType: "ResearchStudy", - EdgeLabel: "note_authorReference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|note_authorReference_Organization|ResearchStudy": { - FromType: "Organization", - EdgeLabel: "note_authorReference_Organization", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "ResearchStudy|recruitment_actualGroup|Group": { - FromType: "ResearchStudy", - EdgeLabel: "recruitment_actualGroup", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actualGroup_research_study_recruitment", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|recruitment_actualGroup|ResearchStudy": { - FromType: "Group", - EdgeLabel: "recruitment_actualGroup", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actualGroup_research_study_recruitment", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "ResearchStudy|recruitment_eligibility_Group|Group": { - FromType: "ResearchStudy", - EdgeLabel: "recruitment_eligibility_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "eligibility_research_study_recruitment", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|recruitment_eligibility_Group|ResearchStudy": { - FromType: "Group", - EdgeLabel: "recruitment_eligibility_Group", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "eligibility_research_study_recruitment", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_Organization|Organization": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|relatedArtifact_resourceReference_Organization|ResearchStudy": { - FromType: "Organization", - EdgeLabel: "relatedArtifact_resourceReference_Organization", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_Group|Group": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|relatedArtifact_resourceReference_Group|ResearchStudy": { - FromType: "Group", - EdgeLabel: "relatedArtifact_resourceReference_Group", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_Practitioner|Practitioner": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|relatedArtifact_resourceReference_Practitioner|ResearchStudy": { - FromType: "Practitioner", - EdgeLabel: "relatedArtifact_resourceReference_Practitioner", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_PractitionerRole|PractitionerRole": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|relatedArtifact_resourceReference_PractitionerRole|ResearchStudy": { - FromType: "PractitionerRole", - EdgeLabel: "relatedArtifact_resourceReference_PractitionerRole", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_ResearchStudy|ResearchStudy": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_Patient|Patient": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|relatedArtifact_resourceReference_Patient|ResearchStudy": { - FromType: "Patient", - EdgeLabel: "relatedArtifact_resourceReference_Patient", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_ResearchSubject|ResearchSubject": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_ResearchSubject", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchSubject|relatedArtifact_resourceReference_ResearchSubject|ResearchStudy": { - FromType: "ResearchSubject", - EdgeLabel: "relatedArtifact_resourceReference_ResearchSubject", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_Substance|Substance": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|relatedArtifact_resourceReference_Substance|ResearchStudy": { - FromType: "Substance", - EdgeLabel: "relatedArtifact_resourceReference_Substance", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_SubstanceDefinition|SubstanceDefinition": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_SubstanceDefinition", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|relatedArtifact_resourceReference_SubstanceDefinition|ResearchStudy": { - FromType: "SubstanceDefinition", - EdgeLabel: "relatedArtifact_resourceReference_SubstanceDefinition", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_Specimen|Specimen": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|relatedArtifact_resourceReference_Specimen|ResearchStudy": { - FromType: "Specimen", - EdgeLabel: "relatedArtifact_resourceReference_Specimen", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_Observation|Observation": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|relatedArtifact_resourceReference_Observation|ResearchStudy": { - FromType: "Observation", - EdgeLabel: "relatedArtifact_resourceReference_Observation", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_DiagnosticReport|DiagnosticReport": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|relatedArtifact_resourceReference_DiagnosticReport|ResearchStudy": { - FromType: "DiagnosticReport", - EdgeLabel: "relatedArtifact_resourceReference_DiagnosticReport", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_Condition|Condition": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_Condition", - ToType: "Condition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Condition|relatedArtifact_resourceReference_Condition|ResearchStudy": { - FromType: "Condition", - EdgeLabel: "relatedArtifact_resourceReference_Condition", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_Medication|Medication": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_Medication", - ToType: "Medication", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Medication|relatedArtifact_resourceReference_Medication|ResearchStudy": { - FromType: "Medication", - EdgeLabel: "relatedArtifact_resourceReference_Medication", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_MedicationAdministration|MedicationAdministration": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|relatedArtifact_resourceReference_MedicationAdministration|ResearchStudy": { - FromType: "MedicationAdministration", - EdgeLabel: "relatedArtifact_resourceReference_MedicationAdministration", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_MedicationStatement|MedicationStatement": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|relatedArtifact_resourceReference_MedicationStatement|ResearchStudy": { - FromType: "MedicationStatement", - EdgeLabel: "relatedArtifact_resourceReference_MedicationStatement", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_MedicationRequest|MedicationRequest": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_MedicationRequest", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationRequest|relatedArtifact_resourceReference_MedicationRequest|ResearchStudy": { - FromType: "MedicationRequest", - EdgeLabel: "relatedArtifact_resourceReference_MedicationRequest", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_Procedure|Procedure": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|relatedArtifact_resourceReference_Procedure|ResearchStudy": { - FromType: "Procedure", - EdgeLabel: "relatedArtifact_resourceReference_Procedure", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_DocumentReference|DocumentReference": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|relatedArtifact_resourceReference_DocumentReference|ResearchStudy": { - FromType: "DocumentReference", - EdgeLabel: "relatedArtifact_resourceReference_DocumentReference", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_Task|Task": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_Task", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Task|relatedArtifact_resourceReference_Task|ResearchStudy": { - FromType: "Task", - EdgeLabel: "relatedArtifact_resourceReference_Task", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_ImagingStudy|ImagingStudy": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|relatedArtifact_resourceReference_ImagingStudy|ResearchStudy": { - FromType: "ImagingStudy", - EdgeLabel: "relatedArtifact_resourceReference_ImagingStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "FamilyMemberHistory|relatedArtifact_resourceReference_FamilyMemberHistory|ResearchStudy": { - FromType: "FamilyMemberHistory", - EdgeLabel: "relatedArtifact_resourceReference_FamilyMemberHistory", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "ResearchStudy|relatedArtifact_resourceReference_BodyStructure|BodyStructure": { - FromType: "ResearchStudy", - EdgeLabel: "relatedArtifact_resourceReference_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|relatedArtifact_resourceReference_BodyStructure|ResearchStudy": { - FromType: "BodyStructure", - EdgeLabel: "relatedArtifact_resourceReference_BodyStructure", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "ResearchStudyAssociatedParty|party_Practitioner|Practitioner": { - FromType: "ResearchStudyAssociatedParty", - EdgeLabel: "party_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_study_associated_party", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|party_Practitioner|ResearchStudyAssociatedParty": { - FromType: "Practitioner", - EdgeLabel: "party_Practitioner", - ToType: "ResearchStudyAssociatedParty", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_study_associated_party", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "ResearchStudyAssociatedParty|party_PractitionerRole|PractitionerRole": { - FromType: "ResearchStudyAssociatedParty", - EdgeLabel: "party_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_study_associated_party", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|party_PractitionerRole|ResearchStudyAssociatedParty": { - FromType: "PractitionerRole", - EdgeLabel: "party_PractitionerRole", - ToType: "ResearchStudyAssociatedParty", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_study_associated_party", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "ResearchStudyAssociatedParty|party_Organization|Organization": { - FromType: "ResearchStudyAssociatedParty", - EdgeLabel: "party_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_study_associated_party", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|party_Organization|ResearchStudyAssociatedParty": { - FromType: "Organization", - EdgeLabel: "party_Organization", - ToType: "ResearchStudyAssociatedParty", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_study_associated_party", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "ResearchStudyComparisonGroup|observedGroup|Group": { - FromType: "ResearchStudyComparisonGroup", - EdgeLabel: "observedGroup", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_study_comparison_group", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|observedGroup|ResearchStudyComparisonGroup": { - FromType: "Group", - EdgeLabel: "observedGroup", - ToType: "ResearchStudyComparisonGroup", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_study_comparison_group", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "ResearchStudyRecruitment|actualGroup|Group": { - FromType: "ResearchStudyRecruitment", - EdgeLabel: "actualGroup", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actualGroup_research_study_recruitment", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|actualGroup|ResearchStudyRecruitment": { - FromType: "Group", - EdgeLabel: "actualGroup", - ToType: "ResearchStudyRecruitment", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "actualGroup_research_study_recruitment", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "ResearchStudyRecruitment|eligibility_Group|Group": { - FromType: "ResearchStudyRecruitment", - EdgeLabel: "eligibility_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "eligibility_research_study_recruitment", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|eligibility_Group|ResearchStudyRecruitment": { - FromType: "Group", - EdgeLabel: "eligibility_Group", - ToType: "ResearchStudyRecruitment", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "eligibility_research_study_recruitment", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "ResearchSubject|study|ResearchStudy": { - FromType: "ResearchSubject", - EdgeLabel: "study", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_subject", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|study|ResearchSubject": { - FromType: "ResearchStudy", - EdgeLabel: "study", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_subject", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchSubject|subject_Patient|Patient": { - FromType: "ResearchSubject", - EdgeLabel: "subject_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_subject", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|subject_Patient|ResearchSubject": { - FromType: "Patient", - EdgeLabel: "subject_Patient", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_subject", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "ResearchSubject|subject_Group|Group": { - FromType: "ResearchSubject", - EdgeLabel: "subject_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_subject", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|subject_Group|ResearchSubject": { - FromType: "Group", - EdgeLabel: "subject_Group", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_subject", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "ResearchSubject|subject_Specimen|Specimen": { - FromType: "ResearchSubject", - EdgeLabel: "subject_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_subject", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|subject_Specimen|ResearchSubject": { - FromType: "Specimen", - EdgeLabel: "subject_Specimen", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_subject", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "ResearchSubject|subject_Medication|Medication": { - FromType: "ResearchSubject", - EdgeLabel: "subject_Medication", - ToType: "Medication", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_subject", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Medication|subject_Medication|ResearchSubject": { - FromType: "Medication", - EdgeLabel: "subject_Medication", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_subject", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "ResearchSubject|subject_Substance|Substance": { - FromType: "ResearchSubject", - EdgeLabel: "subject_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_subject", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|subject_Substance|ResearchSubject": { - FromType: "Substance", - EdgeLabel: "subject_Substance", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "research_subject", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Signature|onBehalfOf_Practitioner|Practitioner": { - FromType: "Signature", - EdgeLabel: "onBehalfOf_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "onBehalfOf_signature", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|onBehalfOf_Practitioner|Signature": { - FromType: "Practitioner", - EdgeLabel: "onBehalfOf_Practitioner", - ToType: "Signature", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "onBehalfOf_signature", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Signature|onBehalfOf_PractitionerRole|PractitionerRole": { - FromType: "Signature", - EdgeLabel: "onBehalfOf_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "onBehalfOf_signature", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|onBehalfOf_PractitionerRole|Signature": { - FromType: "PractitionerRole", - EdgeLabel: "onBehalfOf_PractitionerRole", - ToType: "Signature", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "onBehalfOf_signature", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Signature|onBehalfOf_Patient|Patient": { - FromType: "Signature", - EdgeLabel: "onBehalfOf_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "onBehalfOf_signature", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|onBehalfOf_Patient|Signature": { - FromType: "Patient", - EdgeLabel: "onBehalfOf_Patient", - ToType: "Signature", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "onBehalfOf_signature", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Signature|onBehalfOf_Organization|Organization": { - FromType: "Signature", - EdgeLabel: "onBehalfOf_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "onBehalfOf_signature", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|onBehalfOf_Organization|Signature": { - FromType: "Organization", - EdgeLabel: "onBehalfOf_Organization", - ToType: "Signature", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "onBehalfOf_signature", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Signature|who_Practitioner|Practitioner": { - FromType: "Signature", - EdgeLabel: "who_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "who_signature", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|who_Practitioner|Signature": { - FromType: "Practitioner", - EdgeLabel: "who_Practitioner", - ToType: "Signature", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "who_signature", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Signature|who_PractitionerRole|PractitionerRole": { - FromType: "Signature", - EdgeLabel: "who_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "who_signature", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|who_PractitionerRole|Signature": { - FromType: "PractitionerRole", - EdgeLabel: "who_PractitionerRole", - ToType: "Signature", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "who_signature", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Signature|who_Patient|Patient": { - FromType: "Signature", - EdgeLabel: "who_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "who_signature", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|who_Patient|Signature": { - FromType: "Patient", - EdgeLabel: "who_Patient", - ToType: "Signature", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "who_signature", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Signature|who_Organization|Organization": { - FromType: "Signature", - EdgeLabel: "who_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "who_signature", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|who_Organization|Signature": { - FromType: "Organization", - EdgeLabel: "who_Organization", - ToType: "Signature", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "who_signature", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Specimen|parent|Specimen": { - FromType: "Specimen", - EdgeLabel: "parent", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "parent_specimen", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|subject_Patient|Patient": { - FromType: "Specimen", - EdgeLabel: "subject_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|subject_Patient|Specimen": { - FromType: "Patient", - EdgeLabel: "subject_Patient", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Specimen|subject_Group|Group": { - FromType: "Specimen", - EdgeLabel: "subject_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|subject_Group|Specimen": { - FromType: "Group", - EdgeLabel: "subject_Group", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Specimen|subject_Substance|Substance": { - FromType: "Specimen", - EdgeLabel: "subject_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|subject_Substance|Specimen": { - FromType: "Substance", - EdgeLabel: "subject_Substance", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Specimen|collection_collector_Practitioner|Practitioner": { - FromType: "Specimen", - EdgeLabel: "collection_collector_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_collection", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|collection_collector_Practitioner|Specimen": { - FromType: "Practitioner", - EdgeLabel: "collection_collector_Practitioner", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_collection", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Specimen|collection_collector_PractitionerRole|PractitionerRole": { - FromType: "Specimen", - EdgeLabel: "collection_collector_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_collection", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|collection_collector_PractitionerRole|Specimen": { - FromType: "PractitionerRole", - EdgeLabel: "collection_collector_PractitionerRole", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_collection", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Specimen|collection_collector_Patient|Patient": { - FromType: "Specimen", - EdgeLabel: "collection_collector_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_collection", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|collection_collector_Patient|Specimen": { - FromType: "Patient", - EdgeLabel: "collection_collector_Patient", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_collection", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Specimen|collection_procedure|Procedure": { - FromType: "Specimen", - EdgeLabel: "collection_procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_collection", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|collection_procedure|Specimen": { - FromType: "Procedure", - EdgeLabel: "collection_procedure", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_collection", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Specimen|note_authorReference_Practitioner|Practitioner": { - FromType: "Specimen", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|note_authorReference_Practitioner|Specimen": { - FromType: "Practitioner", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Specimen|note_authorReference_PractitionerRole|PractitionerRole": { - FromType: "Specimen", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|note_authorReference_PractitionerRole|Specimen": { - FromType: "PractitionerRole", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Specimen|note_authorReference_Patient|Patient": { - FromType: "Specimen", - EdgeLabel: "note_authorReference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|note_authorReference_Patient|Specimen": { - FromType: "Patient", - EdgeLabel: "note_authorReference_Patient", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Specimen|note_authorReference_Organization|Organization": { - FromType: "Specimen", - EdgeLabel: "note_authorReference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|note_authorReference_Organization|Specimen": { - FromType: "Organization", - EdgeLabel: "note_authorReference_Organization", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Specimen|processing_additive|Substance": { - FromType: "Specimen", - EdgeLabel: "processing_additive", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "additive_specimen_processing", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|processing_additive|Specimen": { - FromType: "Substance", - EdgeLabel: "processing_additive", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "additive_specimen_processing", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "SpecimenCollection|collector_Practitioner|Practitioner": { - FromType: "SpecimenCollection", - EdgeLabel: "collector_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_collection", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|collector_Practitioner|SpecimenCollection": { - FromType: "Practitioner", - EdgeLabel: "collector_Practitioner", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_collection", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "SpecimenCollection|collector_PractitionerRole|PractitionerRole": { - FromType: "SpecimenCollection", - EdgeLabel: "collector_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_collection", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|collector_PractitionerRole|SpecimenCollection": { - FromType: "PractitionerRole", - EdgeLabel: "collector_PractitionerRole", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_collection", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "SpecimenCollection|collector_Patient|Patient": { - FromType: "SpecimenCollection", - EdgeLabel: "collector_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_collection", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|collector_Patient|SpecimenCollection": { - FromType: "Patient", - EdgeLabel: "collector_Patient", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_collection", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "SpecimenCollection|procedure|Procedure": { - FromType: "SpecimenCollection", - EdgeLabel: "procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_collection", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|procedure|SpecimenCollection": { - FromType: "Procedure", - EdgeLabel: "procedure", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "specimen_collection", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "SpecimenCollection|bodySite_reference_Organization|Organization": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|bodySite_reference_Organization|SpecimenCollection": { - FromType: "Organization", - EdgeLabel: "bodySite_reference_Organization", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "SpecimenCollection|bodySite_reference_Group|Group": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|bodySite_reference_Group|SpecimenCollection": { - FromType: "Group", - EdgeLabel: "bodySite_reference_Group", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "SpecimenCollection|bodySite_reference_Practitioner|Practitioner": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|bodySite_reference_Practitioner|SpecimenCollection": { - FromType: "Practitioner", - EdgeLabel: "bodySite_reference_Practitioner", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "SpecimenCollection|bodySite_reference_PractitionerRole|PractitionerRole": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|bodySite_reference_PractitionerRole|SpecimenCollection": { - FromType: "PractitionerRole", - EdgeLabel: "bodySite_reference_PractitionerRole", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "SpecimenCollection|bodySite_reference_ResearchStudy|ResearchStudy": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|bodySite_reference_ResearchStudy|SpecimenCollection": { - FromType: "ResearchStudy", - EdgeLabel: "bodySite_reference_ResearchStudy", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "SpecimenCollection|bodySite_reference_Patient|Patient": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|bodySite_reference_Patient|SpecimenCollection": { - FromType: "Patient", - EdgeLabel: "bodySite_reference_Patient", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "SpecimenCollection|bodySite_reference_ResearchSubject|ResearchSubject": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_ResearchSubject", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchSubject|bodySite_reference_ResearchSubject|SpecimenCollection": { - FromType: "ResearchSubject", - EdgeLabel: "bodySite_reference_ResearchSubject", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "SpecimenCollection|bodySite_reference_Substance|Substance": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|bodySite_reference_Substance|SpecimenCollection": { - FromType: "Substance", - EdgeLabel: "bodySite_reference_Substance", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "SpecimenCollection|bodySite_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_SubstanceDefinition", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|bodySite_reference_SubstanceDefinition|SpecimenCollection": { - FromType: "SubstanceDefinition", - EdgeLabel: "bodySite_reference_SubstanceDefinition", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SpecimenCollection|bodySite_reference_Specimen|Specimen": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|bodySite_reference_Specimen|SpecimenCollection": { - FromType: "Specimen", - EdgeLabel: "bodySite_reference_Specimen", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "SpecimenCollection|bodySite_reference_Observation|Observation": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|bodySite_reference_Observation|SpecimenCollection": { - FromType: "Observation", - EdgeLabel: "bodySite_reference_Observation", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "SpecimenCollection|bodySite_reference_DiagnosticReport|DiagnosticReport": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|bodySite_reference_DiagnosticReport|SpecimenCollection": { - FromType: "DiagnosticReport", - EdgeLabel: "bodySite_reference_DiagnosticReport", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "SpecimenCollection|bodySite_reference_Condition|Condition": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_Condition", - ToType: "Condition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Condition|bodySite_reference_Condition|SpecimenCollection": { - FromType: "Condition", - EdgeLabel: "bodySite_reference_Condition", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "SpecimenCollection|bodySite_reference_Medication|Medication": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_Medication", - ToType: "Medication", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Medication|bodySite_reference_Medication|SpecimenCollection": { - FromType: "Medication", - EdgeLabel: "bodySite_reference_Medication", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "SpecimenCollection|bodySite_reference_MedicationAdministration|MedicationAdministration": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|bodySite_reference_MedicationAdministration|SpecimenCollection": { - FromType: "MedicationAdministration", - EdgeLabel: "bodySite_reference_MedicationAdministration", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "SpecimenCollection|bodySite_reference_MedicationStatement|MedicationStatement": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|bodySite_reference_MedicationStatement|SpecimenCollection": { - FromType: "MedicationStatement", - EdgeLabel: "bodySite_reference_MedicationStatement", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "SpecimenCollection|bodySite_reference_MedicationRequest|MedicationRequest": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_MedicationRequest", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationRequest|bodySite_reference_MedicationRequest|SpecimenCollection": { - FromType: "MedicationRequest", - EdgeLabel: "bodySite_reference_MedicationRequest", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "SpecimenCollection|bodySite_reference_Procedure|Procedure": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|bodySite_reference_Procedure|SpecimenCollection": { - FromType: "Procedure", - EdgeLabel: "bodySite_reference_Procedure", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "SpecimenCollection|bodySite_reference_DocumentReference|DocumentReference": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|bodySite_reference_DocumentReference|SpecimenCollection": { - FromType: "DocumentReference", - EdgeLabel: "bodySite_reference_DocumentReference", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "SpecimenCollection|bodySite_reference_Task|Task": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_Task", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Task|bodySite_reference_Task|SpecimenCollection": { - FromType: "Task", - EdgeLabel: "bodySite_reference_Task", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "SpecimenCollection|bodySite_reference_ImagingStudy|ImagingStudy": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|bodySite_reference_ImagingStudy|SpecimenCollection": { - FromType: "ImagingStudy", - EdgeLabel: "bodySite_reference_ImagingStudy", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "SpecimenCollection|bodySite_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "FamilyMemberHistory|bodySite_reference_FamilyMemberHistory|SpecimenCollection": { - FromType: "FamilyMemberHistory", - EdgeLabel: "bodySite_reference_FamilyMemberHistory", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "SpecimenCollection|bodySite_reference_BodyStructure|BodyStructure": { - FromType: "SpecimenCollection", - EdgeLabel: "bodySite_reference_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|bodySite_reference_BodyStructure|SpecimenCollection": { - FromType: "BodyStructure", - EdgeLabel: "bodySite_reference_BodyStructure", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "SpecimenCollection|device_reference_Organization|Organization": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|device_reference_Organization|SpecimenCollection": { - FromType: "Organization", - EdgeLabel: "device_reference_Organization", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "SpecimenCollection|device_reference_Group|Group": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|device_reference_Group|SpecimenCollection": { - FromType: "Group", - EdgeLabel: "device_reference_Group", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "SpecimenCollection|device_reference_Practitioner|Practitioner": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|device_reference_Practitioner|SpecimenCollection": { - FromType: "Practitioner", - EdgeLabel: "device_reference_Practitioner", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "SpecimenCollection|device_reference_PractitionerRole|PractitionerRole": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|device_reference_PractitionerRole|SpecimenCollection": { - FromType: "PractitionerRole", - EdgeLabel: "device_reference_PractitionerRole", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "SpecimenCollection|device_reference_ResearchStudy|ResearchStudy": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|device_reference_ResearchStudy|SpecimenCollection": { - FromType: "ResearchStudy", - EdgeLabel: "device_reference_ResearchStudy", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "SpecimenCollection|device_reference_Patient|Patient": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|device_reference_Patient|SpecimenCollection": { - FromType: "Patient", - EdgeLabel: "device_reference_Patient", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "SpecimenCollection|device_reference_ResearchSubject|ResearchSubject": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_ResearchSubject", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchSubject|device_reference_ResearchSubject|SpecimenCollection": { - FromType: "ResearchSubject", - EdgeLabel: "device_reference_ResearchSubject", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "SpecimenCollection|device_reference_Substance|Substance": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|device_reference_Substance|SpecimenCollection": { - FromType: "Substance", - EdgeLabel: "device_reference_Substance", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "SpecimenCollection|device_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_SubstanceDefinition", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|device_reference_SubstanceDefinition|SpecimenCollection": { - FromType: "SubstanceDefinition", - EdgeLabel: "device_reference_SubstanceDefinition", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SpecimenCollection|device_reference_Specimen|Specimen": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|device_reference_Specimen|SpecimenCollection": { - FromType: "Specimen", - EdgeLabel: "device_reference_Specimen", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "SpecimenCollection|device_reference_Observation|Observation": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|device_reference_Observation|SpecimenCollection": { - FromType: "Observation", - EdgeLabel: "device_reference_Observation", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "SpecimenCollection|device_reference_DiagnosticReport|DiagnosticReport": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|device_reference_DiagnosticReport|SpecimenCollection": { - FromType: "DiagnosticReport", - EdgeLabel: "device_reference_DiagnosticReport", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "SpecimenCollection|device_reference_Condition|Condition": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_Condition", - ToType: "Condition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Condition|device_reference_Condition|SpecimenCollection": { - FromType: "Condition", - EdgeLabel: "device_reference_Condition", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "SpecimenCollection|device_reference_Medication|Medication": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_Medication", - ToType: "Medication", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Medication|device_reference_Medication|SpecimenCollection": { - FromType: "Medication", - EdgeLabel: "device_reference_Medication", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "SpecimenCollection|device_reference_MedicationAdministration|MedicationAdministration": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|device_reference_MedicationAdministration|SpecimenCollection": { - FromType: "MedicationAdministration", - EdgeLabel: "device_reference_MedicationAdministration", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "SpecimenCollection|device_reference_MedicationStatement|MedicationStatement": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|device_reference_MedicationStatement|SpecimenCollection": { - FromType: "MedicationStatement", - EdgeLabel: "device_reference_MedicationStatement", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "SpecimenCollection|device_reference_MedicationRequest|MedicationRequest": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_MedicationRequest", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationRequest|device_reference_MedicationRequest|SpecimenCollection": { - FromType: "MedicationRequest", - EdgeLabel: "device_reference_MedicationRequest", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "SpecimenCollection|device_reference_Procedure|Procedure": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|device_reference_Procedure|SpecimenCollection": { - FromType: "Procedure", - EdgeLabel: "device_reference_Procedure", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "SpecimenCollection|device_reference_DocumentReference|DocumentReference": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|device_reference_DocumentReference|SpecimenCollection": { - FromType: "DocumentReference", - EdgeLabel: "device_reference_DocumentReference", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "SpecimenCollection|device_reference_Task|Task": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_Task", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Task|device_reference_Task|SpecimenCollection": { - FromType: "Task", - EdgeLabel: "device_reference_Task", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "SpecimenCollection|device_reference_ImagingStudy|ImagingStudy": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|device_reference_ImagingStudy|SpecimenCollection": { - FromType: "ImagingStudy", - EdgeLabel: "device_reference_ImagingStudy", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "SpecimenCollection|device_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "FamilyMemberHistory|device_reference_FamilyMemberHistory|SpecimenCollection": { - FromType: "FamilyMemberHistory", - EdgeLabel: "device_reference_FamilyMemberHistory", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "SpecimenCollection|device_reference_BodyStructure|BodyStructure": { - FromType: "SpecimenCollection", - EdgeLabel: "device_reference_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|device_reference_BodyStructure|SpecimenCollection": { - FromType: "BodyStructure", - EdgeLabel: "device_reference_BodyStructure", - ToType: "SpecimenCollection", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "SpecimenProcessing|additive|Substance": { - FromType: "SpecimenProcessing", - EdgeLabel: "additive", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "additive_specimen_processing", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|additive|SpecimenProcessing": { - FromType: "Substance", - EdgeLabel: "additive", - ToType: "SpecimenProcessing", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "additive_specimen_processing", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|code_reference_Organization|Organization": { - FromType: "Substance", - EdgeLabel: "code_reference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|code_reference_Organization|Substance": { - FromType: "Organization", - EdgeLabel: "code_reference_Organization", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Substance|code_reference_Group|Group": { - FromType: "Substance", - EdgeLabel: "code_reference_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|code_reference_Group|Substance": { - FromType: "Group", - EdgeLabel: "code_reference_Group", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Substance|code_reference_Practitioner|Practitioner": { - FromType: "Substance", - EdgeLabel: "code_reference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|code_reference_Practitioner|Substance": { - FromType: "Practitioner", - EdgeLabel: "code_reference_Practitioner", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Substance|code_reference_PractitionerRole|PractitionerRole": { - FromType: "Substance", - EdgeLabel: "code_reference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|code_reference_PractitionerRole|Substance": { - FromType: "PractitionerRole", - EdgeLabel: "code_reference_PractitionerRole", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Substance|code_reference_ResearchStudy|ResearchStudy": { - FromType: "Substance", - EdgeLabel: "code_reference_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|code_reference_ResearchStudy|Substance": { - FromType: "ResearchStudy", - EdgeLabel: "code_reference_ResearchStudy", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "Substance|code_reference_Patient|Patient": { - FromType: "Substance", - EdgeLabel: "code_reference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|code_reference_Patient|Substance": { - FromType: "Patient", - EdgeLabel: "code_reference_Patient", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Substance|code_reference_ResearchSubject|ResearchSubject": { - FromType: "Substance", - EdgeLabel: "code_reference_ResearchSubject", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchSubject|code_reference_ResearchSubject|Substance": { - FromType: "ResearchSubject", - EdgeLabel: "code_reference_ResearchSubject", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "Substance|code_reference_Substance|Substance": { - FromType: "Substance", - EdgeLabel: "code_reference_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|code_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "Substance", - EdgeLabel: "code_reference_SubstanceDefinition", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|code_reference_SubstanceDefinition|Substance": { - FromType: "SubstanceDefinition", - EdgeLabel: "code_reference_SubstanceDefinition", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "Substance|code_reference_Specimen|Specimen": { - FromType: "Substance", - EdgeLabel: "code_reference_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|code_reference_Specimen|Substance": { - FromType: "Specimen", - EdgeLabel: "code_reference_Specimen", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Substance|code_reference_Observation|Observation": { - FromType: "Substance", - EdgeLabel: "code_reference_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|code_reference_Observation|Substance": { - FromType: "Observation", - EdgeLabel: "code_reference_Observation", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Substance|code_reference_DiagnosticReport|DiagnosticReport": { - FromType: "Substance", - EdgeLabel: "code_reference_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|code_reference_DiagnosticReport|Substance": { - FromType: "DiagnosticReport", - EdgeLabel: "code_reference_DiagnosticReport", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "Substance|code_reference_Condition|Condition": { - FromType: "Substance", - EdgeLabel: "code_reference_Condition", - ToType: "Condition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Condition|code_reference_Condition|Substance": { - FromType: "Condition", - EdgeLabel: "code_reference_Condition", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Substance|code_reference_Medication|Medication": { - FromType: "Substance", - EdgeLabel: "code_reference_Medication", - ToType: "Medication", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Medication|code_reference_Medication|Substance": { - FromType: "Medication", - EdgeLabel: "code_reference_Medication", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Medication/*", - }, - }, - "Substance|code_reference_MedicationAdministration|MedicationAdministration": { - FromType: "Substance", - EdgeLabel: "code_reference_MedicationAdministration", - ToType: "MedicationAdministration", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "MedicationAdministration|code_reference_MedicationAdministration|Substance": { - FromType: "MedicationAdministration", - EdgeLabel: "code_reference_MedicationAdministration", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationAdministration/*", - }, - }, - "Substance|code_reference_MedicationStatement|MedicationStatement": { - FromType: "Substance", - EdgeLabel: "code_reference_MedicationStatement", - ToType: "MedicationStatement", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "MedicationStatement|code_reference_MedicationStatement|Substance": { - FromType: "MedicationStatement", - EdgeLabel: "code_reference_MedicationStatement", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationStatement/*", - }, - }, - "Substance|code_reference_MedicationRequest|MedicationRequest": { - FromType: "Substance", - EdgeLabel: "code_reference_MedicationRequest", - ToType: "MedicationRequest", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "MedicationRequest|code_reference_MedicationRequest|Substance": { - FromType: "MedicationRequest", - EdgeLabel: "code_reference_MedicationRequest", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "Substance|code_reference_Procedure|Procedure": { - FromType: "Substance", - EdgeLabel: "code_reference_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|code_reference_Procedure|Substance": { - FromType: "Procedure", - EdgeLabel: "code_reference_Procedure", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Substance|code_reference_DocumentReference|DocumentReference": { - FromType: "Substance", - EdgeLabel: "code_reference_DocumentReference", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|code_reference_DocumentReference|Substance": { - FromType: "DocumentReference", - EdgeLabel: "code_reference_DocumentReference", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "Substance|code_reference_Task|Task": { - FromType: "Substance", - EdgeLabel: "code_reference_Task", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Task|code_reference_Task|Substance": { - FromType: "Task", - EdgeLabel: "code_reference_Task", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "Substance|code_reference_ImagingStudy|ImagingStudy": { - FromType: "Substance", - EdgeLabel: "code_reference_ImagingStudy", - ToType: "ImagingStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "ImagingStudy|code_reference_ImagingStudy|Substance": { - FromType: "ImagingStudy", - EdgeLabel: "code_reference_ImagingStudy", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "ImagingStudy/*", - }, - }, - "Substance|code_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "Substance", - EdgeLabel: "code_reference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "FamilyMemberHistory|code_reference_FamilyMemberHistory|Substance": { - FromType: "FamilyMemberHistory", - EdgeLabel: "code_reference_FamilyMemberHistory", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "Substance|code_reference_BodyStructure|BodyStructure": { - FromType: "Substance", - EdgeLabel: "code_reference_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|code_reference_BodyStructure|Substance": { - FromType: "BodyStructure", - EdgeLabel: "code_reference_BodyStructure", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "Substance|ingredient_substanceReference|Substance": { - FromType: "Substance", - EdgeLabel: "ingredient_substanceReference", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "substance_ingredient", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "SubstanceDefinition|manufacturer|Organization": { - FromType: "SubstanceDefinition", - EdgeLabel: "manufacturer", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "manufacturer_substance_definition", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|manufacturer|SubstanceDefinition": { - FromType: "Organization", - EdgeLabel: "manufacturer", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "manufacturer_substance_definition", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "SubstanceDefinition|supplier|Organization": { - FromType: "SubstanceDefinition", - EdgeLabel: "supplier", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supplier_substance_definition", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|supplier|SubstanceDefinition": { - FromType: "Organization", - EdgeLabel: "supplier", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "supplier_substance_definition", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "SubstanceDefinition|code_source|DocumentReference": { - FromType: "SubstanceDefinition", - EdgeLabel: "code_source", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "source_substance_definition_code", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|code_source|SubstanceDefinition": { - FromType: "DocumentReference", - EdgeLabel: "code_source", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "source_substance_definition_code", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "SubstanceDefinition|name_source|DocumentReference": { - FromType: "SubstanceDefinition", - EdgeLabel: "name_source", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "source_substance_definition_name", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|name_source|SubstanceDefinition": { - FromType: "DocumentReference", - EdgeLabel: "name_source", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "source_substance_definition_name", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "SubstanceDefinition|note_authorReference_Practitioner|Practitioner": { - FromType: "SubstanceDefinition", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|note_authorReference_Practitioner|SubstanceDefinition": { - FromType: "Practitioner", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "SubstanceDefinition|note_authorReference_PractitionerRole|PractitionerRole": { - FromType: "SubstanceDefinition", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|note_authorReference_PractitionerRole|SubstanceDefinition": { - FromType: "PractitionerRole", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "SubstanceDefinition|note_authorReference_Patient|Patient": { - FromType: "SubstanceDefinition", - EdgeLabel: "note_authorReference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|note_authorReference_Patient|SubstanceDefinition": { - FromType: "Patient", - EdgeLabel: "note_authorReference_Patient", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "SubstanceDefinition|note_authorReference_Organization|Organization": { - FromType: "SubstanceDefinition", - EdgeLabel: "note_authorReference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|note_authorReference_Organization|SubstanceDefinition": { - FromType: "Organization", - EdgeLabel: "note_authorReference_Organization", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "SubstanceDefinition|relationship_source|DocumentReference": { - FromType: "SubstanceDefinition", - EdgeLabel: "relationship_source", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "source_substance_definition_relationship", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|relationship_source|SubstanceDefinition": { - FromType: "DocumentReference", - EdgeLabel: "relationship_source", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "source_substance_definition_relationship", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "SubstanceDefinition|relationship_substanceDefinitionReference|SubstanceDefinition": { - FromType: "SubstanceDefinition", - EdgeLabel: "relationship_substanceDefinitionReference", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "substance_definition_relationship", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|structure_sourceDocument|DocumentReference": { - FromType: "SubstanceDefinition", - EdgeLabel: "structure_sourceDocument", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "sourceDocument_substance_definition_structure", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|structure_sourceDocument|SubstanceDefinition": { - FromType: "DocumentReference", - EdgeLabel: "structure_sourceDocument", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "sourceDocument_substance_definition_structure", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "SubstanceDefinitionCode|source|DocumentReference": { - FromType: "SubstanceDefinitionCode", - EdgeLabel: "source", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "source_substance_definition_code", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|source|SubstanceDefinitionCode": { - FromType: "DocumentReference", - EdgeLabel: "source", - ToType: "SubstanceDefinitionCode", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "source_substance_definition_code", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "SubstanceDefinitionCode|note_authorReference_Practitioner|Practitioner": { - FromType: "SubstanceDefinitionCode", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|note_authorReference_Practitioner|SubstanceDefinitionCode": { - FromType: "Practitioner", - EdgeLabel: "note_authorReference_Practitioner", - ToType: "SubstanceDefinitionCode", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "SubstanceDefinitionCode|note_authorReference_PractitionerRole|PractitionerRole": { - FromType: "SubstanceDefinitionCode", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|note_authorReference_PractitionerRole|SubstanceDefinitionCode": { - FromType: "PractitionerRole", - EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "SubstanceDefinitionCode", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "SubstanceDefinitionCode|note_authorReference_Patient|Patient": { - FromType: "SubstanceDefinitionCode", - EdgeLabel: "note_authorReference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|note_authorReference_Patient|SubstanceDefinitionCode": { - FromType: "Patient", - EdgeLabel: "note_authorReference_Patient", - ToType: "SubstanceDefinitionCode", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "SubstanceDefinitionCode|note_authorReference_Organization|Organization": { - FromType: "SubstanceDefinitionCode", - EdgeLabel: "note_authorReference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|note_authorReference_Organization|SubstanceDefinitionCode": { - FromType: "Organization", - EdgeLabel: "note_authorReference_Organization", - ToType: "SubstanceDefinitionCode", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "SubstanceDefinitionName|source|DocumentReference": { - FromType: "SubstanceDefinitionName", - EdgeLabel: "source", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "source_substance_definition_name", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|source|SubstanceDefinitionName": { - FromType: "DocumentReference", - EdgeLabel: "source", - ToType: "SubstanceDefinitionName", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "source_substance_definition_name", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "SubstanceDefinitionName|synonym_source|DocumentReference": { - FromType: "SubstanceDefinitionName", - EdgeLabel: "synonym_source", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "source_substance_definition_name", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|synonym_source|SubstanceDefinitionName": { - FromType: "DocumentReference", - EdgeLabel: "synonym_source", - ToType: "SubstanceDefinitionName", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "source_substance_definition_name", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "SubstanceDefinitionName|translation_source|DocumentReference": { - FromType: "SubstanceDefinitionName", - EdgeLabel: "translation_source", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "source_substance_definition_name", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|translation_source|SubstanceDefinitionName": { - FromType: "DocumentReference", - EdgeLabel: "translation_source", - ToType: "SubstanceDefinitionName", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "source_substance_definition_name", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "SubstanceDefinitionRelationship|source|DocumentReference": { - FromType: "SubstanceDefinitionRelationship", - EdgeLabel: "source", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "source_substance_definition_relationship", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|source|SubstanceDefinitionRelationship": { - FromType: "DocumentReference", - EdgeLabel: "source", - ToType: "SubstanceDefinitionRelationship", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "source_substance_definition_relationship", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "SubstanceDefinitionRelationship|substanceDefinitionReference|SubstanceDefinition": { - FromType: "SubstanceDefinitionRelationship", - EdgeLabel: "substanceDefinitionReference", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "substance_definition_relationship", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|substanceDefinitionReference|SubstanceDefinitionRelationship": { - FromType: "SubstanceDefinition", - EdgeLabel: "substanceDefinitionReference", - ToType: "SubstanceDefinitionRelationship", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "substance_definition_relationship", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinitionStructure|sourceDocument|DocumentReference": { - FromType: "SubstanceDefinitionStructure", - EdgeLabel: "sourceDocument", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "sourceDocument_substance_definition_structure", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|sourceDocument|SubstanceDefinitionStructure": { - FromType: "DocumentReference", - EdgeLabel: "sourceDocument", - ToType: "SubstanceDefinitionStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "sourceDocument_substance_definition_structure", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "SubstanceDefinitionStructure|representation_document|DocumentReference": { - FromType: "SubstanceDefinitionStructure", - EdgeLabel: "representation_document", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "substance_definition_structure_representation", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|representation_document|SubstanceDefinitionStructure": { - FromType: "DocumentReference", - EdgeLabel: "representation_document", - ToType: "SubstanceDefinitionStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "substance_definition_structure_representation", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "SubstanceDefinitionStructureRepresentation|document|DocumentReference": { - FromType: "SubstanceDefinitionStructureRepresentation", - EdgeLabel: "document", - ToType: "DocumentReference", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "substance_definition_structure_representation", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "DocumentReference|document|SubstanceDefinitionStructureRepresentation": { - FromType: "DocumentReference", - EdgeLabel: "document", - ToType: "SubstanceDefinitionStructureRepresentation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "substance_definition_structure_representation", - }, - RegexMatch: []string{ - "DocumentReference/*", - }, - }, - "SubstanceIngredient|substanceReference|Substance": { - FromType: "SubstanceIngredient", - EdgeLabel: "substanceReference", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "substance_ingredient", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|substanceReference|SubstanceIngredient": { - FromType: "Substance", - EdgeLabel: "substanceReference", - ToType: "SubstanceIngredient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "substance_ingredient", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Task|basedOn_Organization|Organization": { - FromType: "Task", - EdgeLabel: "basedOn_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|basedOn_Organization|Task": { - FromType: "Organization", - EdgeLabel: "basedOn_Organization", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Task|basedOn_Group|Group": { - FromType: "Task", - EdgeLabel: "basedOn_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|basedOn_Group|Task": { - FromType: "Group", - EdgeLabel: "basedOn_Group", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Task|basedOn_Practitioner|Practitioner": { - FromType: "Task", - EdgeLabel: "basedOn_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|basedOn_Practitioner|Task": { - FromType: "Practitioner", - EdgeLabel: "basedOn_Practitioner", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Task|basedOn_PractitionerRole|PractitionerRole": { - FromType: "Task", - EdgeLabel: "basedOn_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|basedOn_PractitionerRole|Task": { - FromType: "PractitionerRole", - EdgeLabel: "basedOn_PractitionerRole", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "Task|basedOn_ResearchStudy|ResearchStudy": { - FromType: "Task", - EdgeLabel: "basedOn_ResearchStudy", - ToType: "ResearchStudy", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "ResearchStudy|basedOn_ResearchStudy|Task": { - FromType: "ResearchStudy", - EdgeLabel: "basedOn_ResearchStudy", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "Task|basedOn_Patient|Patient": { - FromType: "Task", - EdgeLabel: "basedOn_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|basedOn_Patient|Task": { - FromType: "Patient", - EdgeLabel: "basedOn_Patient", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Task|basedOn_ResearchSubject|ResearchSubject": { - FromType: "Task", - EdgeLabel: "basedOn_ResearchSubject", - ToType: "ResearchSubject", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "ResearchSubject|basedOn_ResearchSubject|Task": { - FromType: "ResearchSubject", - EdgeLabel: "basedOn_ResearchSubject", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "ResearchSubject/*", - }, - }, - "Task|basedOn_Substance|Substance": { - FromType: "Task", - EdgeLabel: "basedOn_Substance", - ToType: "Substance", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Substance|basedOn_Substance|Task": { - FromType: "Substance", - EdgeLabel: "basedOn_Substance", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "Substance/*", - }, - }, - "Task|basedOn_SubstanceDefinition|SubstanceDefinition": { - FromType: "Task", - EdgeLabel: "basedOn_SubstanceDefinition", - ToType: "SubstanceDefinition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "SubstanceDefinition|basedOn_SubstanceDefinition|Task": { - FromType: "SubstanceDefinition", - EdgeLabel: "basedOn_SubstanceDefinition", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "SubstanceDefinition/*", - }, - }, - "Task|basedOn_Specimen|Specimen": { - FromType: "Task", - EdgeLabel: "basedOn_Specimen", - ToType: "Specimen", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Specimen|basedOn_Specimen|Task": { - FromType: "Specimen", - EdgeLabel: "basedOn_Specimen", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "Specimen/*", - }, - }, - "Task|basedOn_Observation|Observation": { - FromType: "Task", - EdgeLabel: "basedOn_Observation", - ToType: "Observation", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Observation|basedOn_Observation|Task": { - FromType: "Observation", - EdgeLabel: "basedOn_Observation", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "Observation/*", - }, - }, - "Task|basedOn_DiagnosticReport|DiagnosticReport": { - FromType: "Task", - EdgeLabel: "basedOn_DiagnosticReport", - ToType: "DiagnosticReport", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "DiagnosticReport|basedOn_DiagnosticReport|Task": { - FromType: "DiagnosticReport", - EdgeLabel: "basedOn_DiagnosticReport", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "DiagnosticReport/*", - }, - }, - "Task|basedOn_Condition|Condition": { - FromType: "Task", - EdgeLabel: "basedOn_Condition", - ToType: "Condition", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Condition|basedOn_Condition|Task": { - FromType: "Condition", - EdgeLabel: "basedOn_Condition", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "basedOn_task", - }, - RegexMatch: []string{ - "Condition/*", - }, - }, - "Task|basedOn_Medication|Medication": { - FromType: "Task", - EdgeLabel: "basedOn_Medication", - ToType: "Medication", + }, + "BodyStructure|complication_reference_BodyStructure|Procedure": { + FromType: "BodyStructure", + EdgeLabel: "complication_reference_BodyStructure", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "codeable_reference", }, RegexMatch: []string{ - "Medication/*", + "BodyStructure/*", }, }, - "Medication|basedOn_Medication|Task": { - FromType: "Medication", - EdgeLabel: "basedOn_Medication", - ToType: "Task", + "Procedure|note_authorReference_Practitioner|Practitioner": { + FromType: "Procedure", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "annotation", }, RegexMatch: []string{ - "Medication/*", + "Practitioner/*", }, }, - "Task|basedOn_MedicationAdministration|MedicationAdministration": { - FromType: "Task", - EdgeLabel: "basedOn_MedicationAdministration", - ToType: "MedicationAdministration", + "Practitioner|note_authorReference_Practitioner|Procedure": { + FromType: "Practitioner", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "annotation", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Practitioner/*", }, }, - "MedicationAdministration|basedOn_MedicationAdministration|Task": { - FromType: "MedicationAdministration", - EdgeLabel: "basedOn_MedicationAdministration", - ToType: "Task", + "Procedure|note_authorReference_PractitionerRole|PractitionerRole": { + FromType: "Procedure", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "annotation", }, RegexMatch: []string{ - "MedicationAdministration/*", + "PractitionerRole/*", }, }, - "Task|basedOn_MedicationStatement|MedicationStatement": { - FromType: "Task", - EdgeLabel: "basedOn_MedicationStatement", - ToType: "MedicationStatement", + "PractitionerRole|note_authorReference_PractitionerRole|Procedure": { + FromType: "PractitionerRole", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "annotation", }, RegexMatch: []string{ - "MedicationStatement/*", + "PractitionerRole/*", }, }, - "MedicationStatement|basedOn_MedicationStatement|Task": { - FromType: "MedicationStatement", - EdgeLabel: "basedOn_MedicationStatement", - ToType: "Task", + "Procedure|note_authorReference_Patient|Patient": { + FromType: "Procedure", + EdgeLabel: "note_authorReference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "annotation", }, RegexMatch: []string{ - "MedicationStatement/*", + "Patient/*", }, }, - "Task|basedOn_MedicationRequest|MedicationRequest": { - FromType: "Task", - EdgeLabel: "basedOn_MedicationRequest", - ToType: "MedicationRequest", + "Patient|note_authorReference_Patient|Procedure": { + FromType: "Patient", + EdgeLabel: "note_authorReference_Patient", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "annotation", }, RegexMatch: []string{ - "MedicationRequest/*", + "Patient/*", }, }, - "MedicationRequest|basedOn_MedicationRequest|Task": { - FromType: "MedicationRequest", - EdgeLabel: "basedOn_MedicationRequest", - ToType: "Task", + "Procedure|note_authorReference_Organization|Organization": { + FromType: "Procedure", + EdgeLabel: "note_authorReference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "annotation", }, RegexMatch: []string{ - "MedicationRequest/*", + "Organization/*", }, }, - "Task|basedOn_Procedure|Procedure": { - FromType: "Task", - EdgeLabel: "basedOn_Procedure", + "Organization|note_authorReference_Organization|Procedure": { + FromType: "Organization", + EdgeLabel: "note_authorReference_Organization", ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "annotation", }, RegexMatch: []string{ - "Procedure/*", + "Organization/*", }, }, - "Procedure|basedOn_Procedure|Task": { + "Procedure|performer_actor_Practitioner|Practitioner": { FromType: "Procedure", - EdgeLabel: "basedOn_Procedure", - ToType: "Task", + EdgeLabel: "performer_actor_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "actor_procedure_performer", }, RegexMatch: []string{ - "Procedure/*", + "Practitioner/*", }, }, - "Task|basedOn_DocumentReference|DocumentReference": { - FromType: "Task", - EdgeLabel: "basedOn_DocumentReference", - ToType: "DocumentReference", + "Practitioner|performer_actor_Practitioner|Procedure": { + FromType: "Practitioner", + EdgeLabel: "performer_actor_Practitioner", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "actor_procedure_performer", }, RegexMatch: []string{ - "DocumentReference/*", + "Practitioner/*", }, }, - "DocumentReference|basedOn_DocumentReference|Task": { - FromType: "DocumentReference", - EdgeLabel: "basedOn_DocumentReference", - ToType: "Task", + "Procedure|performer_actor_PractitionerRole|PractitionerRole": { + FromType: "Procedure", + EdgeLabel: "performer_actor_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "actor_procedure_performer", }, RegexMatch: []string{ - "DocumentReference/*", + "PractitionerRole/*", }, }, - "Task|basedOn_Task|Task": { - FromType: "Task", - EdgeLabel: "basedOn_Task", - ToType: "Task", + "PractitionerRole|performer_actor_PractitionerRole|Procedure": { + FromType: "PractitionerRole", + EdgeLabel: "performer_actor_PractitionerRole", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "actor_procedure_performer", }, RegexMatch: []string{ - "Task/*", + "PractitionerRole/*", }, }, - "Task|basedOn_ImagingStudy|ImagingStudy": { - FromType: "Task", - EdgeLabel: "basedOn_ImagingStudy", - ToType: "ImagingStudy", + "Procedure|performer_actor_Organization|Organization": { + FromType: "Procedure", + EdgeLabel: "performer_actor_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "actor_procedure_performer", }, RegexMatch: []string{ - "ImagingStudy/*", + "Organization/*", }, }, - "ImagingStudy|basedOn_ImagingStudy|Task": { - FromType: "ImagingStudy", - EdgeLabel: "basedOn_ImagingStudy", - ToType: "Task", + "Organization|performer_actor_Organization|Procedure": { + FromType: "Organization", + EdgeLabel: "performer_actor_Organization", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "actor_procedure_performer", }, RegexMatch: []string{ - "ImagingStudy/*", + "Organization/*", }, }, - "Task|basedOn_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "Task", - EdgeLabel: "basedOn_FamilyMemberHistory", - ToType: "FamilyMemberHistory", + "Procedure|performer_actor_Patient|Patient": { + FromType: "Procedure", + EdgeLabel: "performer_actor_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "actor_procedure_performer", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Patient/*", }, }, - "FamilyMemberHistory|basedOn_FamilyMemberHistory|Task": { - FromType: "FamilyMemberHistory", - EdgeLabel: "basedOn_FamilyMemberHistory", - ToType: "Task", + "Patient|performer_actor_Patient|Procedure": { + FromType: "Patient", + EdgeLabel: "performer_actor_Patient", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "actor_procedure_performer", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Patient/*", }, }, - "Task|basedOn_BodyStructure|BodyStructure": { - FromType: "Task", - EdgeLabel: "basedOn_BodyStructure", - ToType: "BodyStructure", + "Procedure|performer_onBehalfOf|Organization": { + FromType: "Procedure", + EdgeLabel: "performer_onBehalfOf", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "onBehalfOf_procedure_performer", }, RegexMatch: []string{ - "BodyStructure/*", + "Organization/*", }, }, - "BodyStructure|basedOn_BodyStructure|Task": { - FromType: "BodyStructure", - EdgeLabel: "basedOn_BodyStructure", - ToType: "Task", + "Organization|performer_onBehalfOf|Procedure": { + FromType: "Organization", + EdgeLabel: "performer_onBehalfOf", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "basedOn_task", + "onBehalfOf_procedure_performer", }, RegexMatch: []string{ - "BodyStructure/*", + "Organization/*", }, }, - "Task|focus_Organization|Organization": { - FromType: "Task", - EdgeLabel: "focus_Organization", + "Procedure|reason_reference_Organization|Organization": { + FromType: "Procedure", + EdgeLabel: "reason_reference_Organization", ToType: "Organization", Direction: []string{ "outbound", @@ -55616,16 +36246,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Organization/*", }, }, - "Organization|focus_Organization|Task": { + "Organization|reason_reference_Organization|Procedure": { FromType: "Organization", - EdgeLabel: "focus_Organization", - ToType: "Task", + EdgeLabel: "reason_reference_Organization", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -55633,15 +36263,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Organization/*", }, }, - "Task|focus_Group|Group": { - FromType: "Task", - EdgeLabel: "focus_Group", + "Procedure|reason_reference_Group|Group": { + FromType: "Procedure", + EdgeLabel: "reason_reference_Group", ToType: "Group", Direction: []string{ "outbound", @@ -55650,16 +36280,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Group/*", }, }, - "Group|focus_Group|Task": { + "Group|reason_reference_Group|Procedure": { FromType: "Group", - EdgeLabel: "focus_Group", - ToType: "Task", + EdgeLabel: "reason_reference_Group", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -55667,15 +36297,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Group/*", }, }, - "Task|focus_Practitioner|Practitioner": { - FromType: "Task", - EdgeLabel: "focus_Practitioner", + "Procedure|reason_reference_Practitioner|Practitioner": { + FromType: "Procedure", + EdgeLabel: "reason_reference_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", @@ -55684,16 +36314,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Practitioner|focus_Practitioner|Task": { + "Practitioner|reason_reference_Practitioner|Procedure": { FromType: "Practitioner", - EdgeLabel: "focus_Practitioner", - ToType: "Task", + EdgeLabel: "reason_reference_Practitioner", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -55701,15 +36331,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Task|focus_PractitionerRole|PractitionerRole": { - FromType: "Task", - EdgeLabel: "focus_PractitionerRole", + "Procedure|reason_reference_PractitionerRole|PractitionerRole": { + FromType: "Procedure", + EdgeLabel: "reason_reference_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", @@ -55718,16 +36348,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "PractitionerRole|focus_PractitionerRole|Task": { + "PractitionerRole|reason_reference_PractitionerRole|Procedure": { FromType: "PractitionerRole", - EdgeLabel: "focus_PractitionerRole", - ToType: "Task", + EdgeLabel: "reason_reference_PractitionerRole", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -55735,15 +36365,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "Task|focus_ResearchStudy|ResearchStudy": { - FromType: "Task", - EdgeLabel: "focus_ResearchStudy", + "Procedure|reason_reference_ResearchStudy|ResearchStudy": { + FromType: "Procedure", + EdgeLabel: "reason_reference_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -55752,16 +36382,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "ResearchStudy|focus_ResearchStudy|Task": { + "ResearchStudy|reason_reference_ResearchStudy|Procedure": { FromType: "ResearchStudy", - EdgeLabel: "focus_ResearchStudy", - ToType: "Task", + EdgeLabel: "reason_reference_ResearchStudy", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -55769,15 +36399,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "Task|focus_Patient|Patient": { - FromType: "Task", - EdgeLabel: "focus_Patient", + "Procedure|reason_reference_Patient|Patient": { + FromType: "Procedure", + EdgeLabel: "reason_reference_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -55786,16 +36416,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|focus_Patient|Task": { + "Patient|reason_reference_Patient|Procedure": { FromType: "Patient", - EdgeLabel: "focus_Patient", - ToType: "Task", + EdgeLabel: "reason_reference_Patient", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -55803,15 +36433,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Patient/*", }, }, - "Task|focus_ResearchSubject|ResearchSubject": { - FromType: "Task", - EdgeLabel: "focus_ResearchSubject", + "Procedure|reason_reference_ResearchSubject|ResearchSubject": { + FromType: "Procedure", + EdgeLabel: "reason_reference_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -55820,16 +36450,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "ResearchSubject|focus_ResearchSubject|Task": { + "ResearchSubject|reason_reference_ResearchSubject|Procedure": { FromType: "ResearchSubject", - EdgeLabel: "focus_ResearchSubject", - ToType: "Task", + EdgeLabel: "reason_reference_ResearchSubject", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -55837,15 +36467,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "Task|focus_Substance|Substance": { - FromType: "Task", - EdgeLabel: "focus_Substance", + "Procedure|reason_reference_Substance|Substance": { + FromType: "Procedure", + EdgeLabel: "reason_reference_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -55854,16 +36484,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Substance/*", }, }, - "Substance|focus_Substance|Task": { + "Substance|reason_reference_Substance|Procedure": { FromType: "Substance", - EdgeLabel: "focus_Substance", - ToType: "Task", + EdgeLabel: "reason_reference_Substance", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -55871,15 +36501,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Substance/*", }, }, - "Task|focus_SubstanceDefinition|SubstanceDefinition": { - FromType: "Task", - EdgeLabel: "focus_SubstanceDefinition", + "Procedure|reason_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "Procedure", + EdgeLabel: "reason_reference_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -55888,16 +36518,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|focus_SubstanceDefinition|Task": { + "SubstanceDefinition|reason_reference_SubstanceDefinition|Procedure": { FromType: "SubstanceDefinition", - EdgeLabel: "focus_SubstanceDefinition", - ToType: "Task", + EdgeLabel: "reason_reference_SubstanceDefinition", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -55905,15 +36535,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "Task|focus_Specimen|Specimen": { - FromType: "Task", - EdgeLabel: "focus_Specimen", + "Procedure|reason_reference_Specimen|Specimen": { + FromType: "Procedure", + EdgeLabel: "reason_reference_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -55922,16 +36552,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Specimen/*", }, }, - "Specimen|focus_Specimen|Task": { + "Specimen|reason_reference_Specimen|Procedure": { FromType: "Specimen", - EdgeLabel: "focus_Specimen", - ToType: "Task", + EdgeLabel: "reason_reference_Specimen", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -55939,15 +36569,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Specimen/*", }, }, - "Task|focus_Observation|Observation": { - FromType: "Task", - EdgeLabel: "focus_Observation", + "Procedure|reason_reference_Observation|Observation": { + FromType: "Procedure", + EdgeLabel: "reason_reference_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -55956,16 +36586,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Observation/*", }, }, - "Observation|focus_Observation|Task": { + "Observation|reason_reference_Observation|Procedure": { FromType: "Observation", - EdgeLabel: "focus_Observation", - ToType: "Task", + EdgeLabel: "reason_reference_Observation", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -55973,15 +36603,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Observation/*", }, }, - "Task|focus_DiagnosticReport|DiagnosticReport": { - FromType: "Task", - EdgeLabel: "focus_DiagnosticReport", + "Procedure|reason_reference_DiagnosticReport|DiagnosticReport": { + FromType: "Procedure", + EdgeLabel: "reason_reference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -55990,16 +36620,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "DiagnosticReport|focus_DiagnosticReport|Task": { + "DiagnosticReport|reason_reference_DiagnosticReport|Procedure": { FromType: "DiagnosticReport", - EdgeLabel: "focus_DiagnosticReport", - ToType: "Task", + EdgeLabel: "reason_reference_DiagnosticReport", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56007,15 +36637,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "Task|focus_Condition|Condition": { - FromType: "Task", - EdgeLabel: "focus_Condition", + "Procedure|reason_reference_Condition|Condition": { + FromType: "Procedure", + EdgeLabel: "reason_reference_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -56024,16 +36654,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Condition/*", }, }, - "Condition|focus_Condition|Task": { + "Condition|reason_reference_Condition|Procedure": { FromType: "Condition", - EdgeLabel: "focus_Condition", - ToType: "Task", + EdgeLabel: "reason_reference_Condition", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56041,15 +36671,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Condition/*", }, }, - "Task|focus_Medication|Medication": { - FromType: "Task", - EdgeLabel: "focus_Medication", + "Procedure|reason_reference_Medication|Medication": { + FromType: "Procedure", + EdgeLabel: "reason_reference_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -56058,16 +36688,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Medication/*", }, }, - "Medication|focus_Medication|Task": { + "Medication|reason_reference_Medication|Procedure": { FromType: "Medication", - EdgeLabel: "focus_Medication", - ToType: "Task", + EdgeLabel: "reason_reference_Medication", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56075,15 +36705,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Medication/*", }, }, - "Task|focus_MedicationAdministration|MedicationAdministration": { - FromType: "Task", - EdgeLabel: "focus_MedicationAdministration", + "Procedure|reason_reference_MedicationAdministration|MedicationAdministration": { + FromType: "Procedure", + EdgeLabel: "reason_reference_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -56092,16 +36722,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "MedicationAdministration|focus_MedicationAdministration|Task": { + "MedicationAdministration|reason_reference_MedicationAdministration|Procedure": { FromType: "MedicationAdministration", - EdgeLabel: "focus_MedicationAdministration", - ToType: "Task", + EdgeLabel: "reason_reference_MedicationAdministration", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56109,15 +36739,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "Task|focus_MedicationStatement|MedicationStatement": { - FromType: "Task", - EdgeLabel: "focus_MedicationStatement", + "Procedure|reason_reference_MedicationStatement|MedicationStatement": { + FromType: "Procedure", + EdgeLabel: "reason_reference_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -56126,16 +36756,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "MedicationStatement|focus_MedicationStatement|Task": { - FromType: "MedicationStatement", - EdgeLabel: "focus_MedicationStatement", - ToType: "Task", + "MedicationStatement|reason_reference_MedicationStatement|Procedure": { + FromType: "MedicationStatement", + EdgeLabel: "reason_reference_MedicationStatement", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56143,15 +36773,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "Task|focus_MedicationRequest|MedicationRequest": { - FromType: "Task", - EdgeLabel: "focus_MedicationRequest", + "Procedure|reason_reference_MedicationRequest|MedicationRequest": { + FromType: "Procedure", + EdgeLabel: "reason_reference_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -56160,16 +36790,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "MedicationRequest|focus_MedicationRequest|Task": { + "MedicationRequest|reason_reference_MedicationRequest|Procedure": { FromType: "MedicationRequest", - EdgeLabel: "focus_MedicationRequest", - ToType: "Task", + EdgeLabel: "reason_reference_MedicationRequest", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56177,15 +36807,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "Task|focus_Procedure|Procedure": { - FromType: "Task", - EdgeLabel: "focus_Procedure", + "Procedure|reason_reference_Procedure|Procedure": { + FromType: "Procedure", + EdgeLabel: "reason_reference_Procedure", ToType: "Procedure", Direction: []string{ "outbound", @@ -56194,16 +36824,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Procedure/*", }, }, - "Procedure|focus_Procedure|Task": { + "Procedure|reason_reference_DocumentReference|DocumentReference": { FromType: "Procedure", - EdgeLabel: "focus_Procedure", - ToType: "Task", + EdgeLabel: "reason_reference_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -56211,16 +36841,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ - "Procedure/*", + "DocumentReference/*", }, }, - "Task|focus_DocumentReference|DocumentReference": { - FromType: "Task", - EdgeLabel: "focus_DocumentReference", - ToType: "DocumentReference", + "DocumentReference|reason_reference_DocumentReference|Procedure": { + FromType: "DocumentReference", + EdgeLabel: "reason_reference_DocumentReference", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56228,15 +36858,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "DocumentReference/*", }, }, - "DocumentReference|focus_DocumentReference|Task": { - FromType: "DocumentReference", - EdgeLabel: "focus_DocumentReference", + "Procedure|reason_reference_Task|Task": { + FromType: "Procedure", + EdgeLabel: "reason_reference_Task", ToType: "Task", Direction: []string{ "outbound", @@ -56245,16 +36875,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ - "DocumentReference/*", + "Task/*", }, }, - "Task|focus_Task|Task": { + "Task|reason_reference_Task|Procedure": { FromType: "Task", - EdgeLabel: "focus_Task", - ToType: "Task", + EdgeLabel: "reason_reference_Task", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56262,15 +36892,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "Task/*", }, }, - "Task|focus_ImagingStudy|ImagingStudy": { - FromType: "Task", - EdgeLabel: "focus_ImagingStudy", + "Procedure|reason_reference_ImagingStudy|ImagingStudy": { + FromType: "Procedure", + EdgeLabel: "reason_reference_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", @@ -56279,16 +36909,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "ImagingStudy/*", }, }, - "ImagingStudy|focus_ImagingStudy|Task": { + "ImagingStudy|reason_reference_ImagingStudy|Procedure": { FromType: "ImagingStudy", - EdgeLabel: "focus_ImagingStudy", - ToType: "Task", + EdgeLabel: "reason_reference_ImagingStudy", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56296,15 +36926,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "ImagingStudy/*", }, }, - "Task|focus_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "Task", - EdgeLabel: "focus_FamilyMemberHistory", + "Procedure|reason_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "Procedure", + EdgeLabel: "reason_reference_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -56313,16 +36943,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|focus_FamilyMemberHistory|Task": { + "FamilyMemberHistory|reason_reference_FamilyMemberHistory|Procedure": { FromType: "FamilyMemberHistory", - EdgeLabel: "focus_FamilyMemberHistory", - ToType: "Task", + EdgeLabel: "reason_reference_FamilyMemberHistory", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56330,15 +36960,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "FamilyMemberHistory/*", }, }, - "Task|focus_BodyStructure|BodyStructure": { - FromType: "Task", - EdgeLabel: "focus_BodyStructure", + "Procedure|reason_reference_BodyStructure|BodyStructure": { + FromType: "Procedure", + EdgeLabel: "reason_reference_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", @@ -56347,16 +36977,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "BodyStructure/*", }, }, - "BodyStructure|focus_BodyStructure|Task": { + "BodyStructure|reason_reference_BodyStructure|Procedure": { FromType: "BodyStructure", - EdgeLabel: "focus_BodyStructure", - ToType: "Task", + EdgeLabel: "reason_reference_BodyStructure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56364,15 +36994,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "focus_task", + "codeable_reference", }, RegexMatch: []string{ "BodyStructure/*", }, }, - "Task|for_fhir_Organization|Organization": { - FromType: "Task", - EdgeLabel: "for_fhir_Organization", + "Procedure|used_reference_Organization|Organization": { + FromType: "Procedure", + EdgeLabel: "used_reference_Organization", ToType: "Organization", Direction: []string{ "outbound", @@ -56381,16 +37011,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Organization/*", }, }, - "Organization|for_fhir_Organization|Task": { + "Organization|used_reference_Organization|Procedure": { FromType: "Organization", - EdgeLabel: "for_fhir_Organization", - ToType: "Task", + EdgeLabel: "used_reference_Organization", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56398,15 +37028,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Organization/*", }, }, - "Task|for_fhir_Group|Group": { - FromType: "Task", - EdgeLabel: "for_fhir_Group", + "Procedure|used_reference_Group|Group": { + FromType: "Procedure", + EdgeLabel: "used_reference_Group", ToType: "Group", Direction: []string{ "outbound", @@ -56415,16 +37045,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Group/*", }, }, - "Group|for_fhir_Group|Task": { + "Group|used_reference_Group|Procedure": { FromType: "Group", - EdgeLabel: "for_fhir_Group", - ToType: "Task", + EdgeLabel: "used_reference_Group", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56432,15 +37062,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Group/*", }, }, - "Task|for_fhir_Practitioner|Practitioner": { - FromType: "Task", - EdgeLabel: "for_fhir_Practitioner", + "Procedure|used_reference_Practitioner|Practitioner": { + FromType: "Procedure", + EdgeLabel: "used_reference_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", @@ -56449,16 +37079,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Practitioner|for_fhir_Practitioner|Task": { + "Practitioner|used_reference_Practitioner|Procedure": { FromType: "Practitioner", - EdgeLabel: "for_fhir_Practitioner", - ToType: "Task", + EdgeLabel: "used_reference_Practitioner", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56466,15 +37096,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Task|for_fhir_PractitionerRole|PractitionerRole": { - FromType: "Task", - EdgeLabel: "for_fhir_PractitionerRole", + "Procedure|used_reference_PractitionerRole|PractitionerRole": { + FromType: "Procedure", + EdgeLabel: "used_reference_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", @@ -56483,16 +37113,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "PractitionerRole|for_fhir_PractitionerRole|Task": { + "PractitionerRole|used_reference_PractitionerRole|Procedure": { FromType: "PractitionerRole", - EdgeLabel: "for_fhir_PractitionerRole", - ToType: "Task", + EdgeLabel: "used_reference_PractitionerRole", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56500,15 +37130,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "Task|for_fhir_ResearchStudy|ResearchStudy": { - FromType: "Task", - EdgeLabel: "for_fhir_ResearchStudy", + "Procedure|used_reference_ResearchStudy|ResearchStudy": { + FromType: "Procedure", + EdgeLabel: "used_reference_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -56517,16 +37147,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "ResearchStudy|for_fhir_ResearchStudy|Task": { + "ResearchStudy|used_reference_ResearchStudy|Procedure": { FromType: "ResearchStudy", - EdgeLabel: "for_fhir_ResearchStudy", - ToType: "Task", + EdgeLabel: "used_reference_ResearchStudy", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56534,15 +37164,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "Task|for_fhir_Patient|Patient": { - FromType: "Task", - EdgeLabel: "for_fhir_Patient", + "Procedure|used_reference_Patient|Patient": { + FromType: "Procedure", + EdgeLabel: "used_reference_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -56551,16 +37181,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|for_fhir_Patient|Task": { + "Patient|used_reference_Patient|Procedure": { FromType: "Patient", - EdgeLabel: "for_fhir_Patient", - ToType: "Task", + EdgeLabel: "used_reference_Patient", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56568,15 +37198,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Patient/*", }, }, - "Task|for_fhir_ResearchSubject|ResearchSubject": { - FromType: "Task", - EdgeLabel: "for_fhir_ResearchSubject", + "Procedure|used_reference_ResearchSubject|ResearchSubject": { + FromType: "Procedure", + EdgeLabel: "used_reference_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -56585,16 +37215,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "ResearchSubject|for_fhir_ResearchSubject|Task": { + "ResearchSubject|used_reference_ResearchSubject|Procedure": { FromType: "ResearchSubject", - EdgeLabel: "for_fhir_ResearchSubject", - ToType: "Task", + EdgeLabel: "used_reference_ResearchSubject", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56602,15 +37232,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "Task|for_fhir_Substance|Substance": { - FromType: "Task", - EdgeLabel: "for_fhir_Substance", + "Procedure|used_reference_Substance|Substance": { + FromType: "Procedure", + EdgeLabel: "used_reference_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -56619,16 +37249,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Substance/*", }, }, - "Substance|for_fhir_Substance|Task": { + "Substance|used_reference_Substance|Procedure": { FromType: "Substance", - EdgeLabel: "for_fhir_Substance", - ToType: "Task", + EdgeLabel: "used_reference_Substance", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56636,15 +37266,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Substance/*", }, }, - "Task|for_fhir_SubstanceDefinition|SubstanceDefinition": { - FromType: "Task", - EdgeLabel: "for_fhir_SubstanceDefinition", + "Procedure|used_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "Procedure", + EdgeLabel: "used_reference_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -56653,16 +37283,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|for_fhir_SubstanceDefinition|Task": { + "SubstanceDefinition|used_reference_SubstanceDefinition|Procedure": { FromType: "SubstanceDefinition", - EdgeLabel: "for_fhir_SubstanceDefinition", - ToType: "Task", + EdgeLabel: "used_reference_SubstanceDefinition", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56670,15 +37300,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "Task|for_fhir_Specimen|Specimen": { - FromType: "Task", - EdgeLabel: "for_fhir_Specimen", + "Procedure|used_reference_Specimen|Specimen": { + FromType: "Procedure", + EdgeLabel: "used_reference_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -56687,16 +37317,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Specimen/*", }, }, - "Specimen|for_fhir_Specimen|Task": { + "Specimen|used_reference_Specimen|Procedure": { FromType: "Specimen", - EdgeLabel: "for_fhir_Specimen", - ToType: "Task", + EdgeLabel: "used_reference_Specimen", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56704,15 +37334,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Specimen/*", }, }, - "Task|for_fhir_Observation|Observation": { - FromType: "Task", - EdgeLabel: "for_fhir_Observation", + "Procedure|used_reference_Observation|Observation": { + FromType: "Procedure", + EdgeLabel: "used_reference_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -56721,16 +37351,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Observation/*", }, }, - "Observation|for_fhir_Observation|Task": { + "Observation|used_reference_Observation|Procedure": { FromType: "Observation", - EdgeLabel: "for_fhir_Observation", - ToType: "Task", + EdgeLabel: "used_reference_Observation", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56738,15 +37368,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Observation/*", }, }, - "Task|for_fhir_DiagnosticReport|DiagnosticReport": { - FromType: "Task", - EdgeLabel: "for_fhir_DiagnosticReport", + "Procedure|used_reference_DiagnosticReport|DiagnosticReport": { + FromType: "Procedure", + EdgeLabel: "used_reference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -56755,16 +37385,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "DiagnosticReport|for_fhir_DiagnosticReport|Task": { + "DiagnosticReport|used_reference_DiagnosticReport|Procedure": { FromType: "DiagnosticReport", - EdgeLabel: "for_fhir_DiagnosticReport", - ToType: "Task", + EdgeLabel: "used_reference_DiagnosticReport", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56772,15 +37402,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "Task|for_fhir_Condition|Condition": { - FromType: "Task", - EdgeLabel: "for_fhir_Condition", + "Procedure|used_reference_Condition|Condition": { + FromType: "Procedure", + EdgeLabel: "used_reference_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -56789,16 +37419,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Condition/*", }, }, - "Condition|for_fhir_Condition|Task": { + "Condition|used_reference_Condition|Procedure": { FromType: "Condition", - EdgeLabel: "for_fhir_Condition", - ToType: "Task", + EdgeLabel: "used_reference_Condition", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56806,15 +37436,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Condition/*", }, }, - "Task|for_fhir_Medication|Medication": { - FromType: "Task", - EdgeLabel: "for_fhir_Medication", + "Procedure|used_reference_Medication|Medication": { + FromType: "Procedure", + EdgeLabel: "used_reference_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -56823,16 +37453,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Medication/*", }, }, - "Medication|for_fhir_Medication|Task": { + "Medication|used_reference_Medication|Procedure": { FromType: "Medication", - EdgeLabel: "for_fhir_Medication", - ToType: "Task", + EdgeLabel: "used_reference_Medication", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56840,15 +37470,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Medication/*", }, }, - "Task|for_fhir_MedicationAdministration|MedicationAdministration": { - FromType: "Task", - EdgeLabel: "for_fhir_MedicationAdministration", + "Procedure|used_reference_MedicationAdministration|MedicationAdministration": { + FromType: "Procedure", + EdgeLabel: "used_reference_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -56857,16 +37487,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "MedicationAdministration|for_fhir_MedicationAdministration|Task": { + "MedicationAdministration|used_reference_MedicationAdministration|Procedure": { FromType: "MedicationAdministration", - EdgeLabel: "for_fhir_MedicationAdministration", - ToType: "Task", + EdgeLabel: "used_reference_MedicationAdministration", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56874,15 +37504,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "Task|for_fhir_MedicationStatement|MedicationStatement": { - FromType: "Task", - EdgeLabel: "for_fhir_MedicationStatement", + "Procedure|used_reference_MedicationStatement|MedicationStatement": { + FromType: "Procedure", + EdgeLabel: "used_reference_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -56891,16 +37521,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "MedicationStatement|for_fhir_MedicationStatement|Task": { + "MedicationStatement|used_reference_MedicationStatement|Procedure": { FromType: "MedicationStatement", - EdgeLabel: "for_fhir_MedicationStatement", - ToType: "Task", + EdgeLabel: "used_reference_MedicationStatement", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56908,15 +37538,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "Task|for_fhir_MedicationRequest|MedicationRequest": { - FromType: "Task", - EdgeLabel: "for_fhir_MedicationRequest", + "Procedure|used_reference_MedicationRequest|MedicationRequest": { + FromType: "Procedure", + EdgeLabel: "used_reference_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -56925,16 +37555,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "MedicationRequest|for_fhir_MedicationRequest|Task": { + "MedicationRequest|used_reference_MedicationRequest|Procedure": { FromType: "MedicationRequest", - EdgeLabel: "for_fhir_MedicationRequest", - ToType: "Task", + EdgeLabel: "used_reference_MedicationRequest", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56942,15 +37572,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "Task|for_fhir_Procedure|Procedure": { - FromType: "Task", - EdgeLabel: "for_fhir_Procedure", + "Procedure|used_reference_Procedure|Procedure": { + FromType: "Procedure", + EdgeLabel: "used_reference_Procedure", ToType: "Procedure", Direction: []string{ "outbound", @@ -56959,16 +37589,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Procedure/*", }, }, - "Procedure|for_fhir_Procedure|Task": { + "Procedure|used_reference_DocumentReference|DocumentReference": { FromType: "Procedure", - EdgeLabel: "for_fhir_Procedure", - ToType: "Task", + EdgeLabel: "used_reference_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -56976,16 +37606,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ - "Procedure/*", + "DocumentReference/*", }, }, - "Task|for_fhir_DocumentReference|DocumentReference": { - FromType: "Task", - EdgeLabel: "for_fhir_DocumentReference", - ToType: "DocumentReference", + "DocumentReference|used_reference_DocumentReference|Procedure": { + FromType: "DocumentReference", + EdgeLabel: "used_reference_DocumentReference", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -56993,15 +37623,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "DocumentReference/*", }, }, - "DocumentReference|for_fhir_DocumentReference|Task": { - FromType: "DocumentReference", - EdgeLabel: "for_fhir_DocumentReference", + "Procedure|used_reference_Task|Task": { + FromType: "Procedure", + EdgeLabel: "used_reference_Task", ToType: "Task", Direction: []string{ "outbound", @@ -57010,16 +37640,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ - "DocumentReference/*", + "Task/*", }, }, - "Task|for_fhir_Task|Task": { + "Task|used_reference_Task|Procedure": { FromType: "Task", - EdgeLabel: "for_fhir_Task", - ToType: "Task", + EdgeLabel: "used_reference_Task", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -57027,15 +37657,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "Task/*", }, }, - "Task|for_fhir_ImagingStudy|ImagingStudy": { - FromType: "Task", - EdgeLabel: "for_fhir_ImagingStudy", + "Procedure|used_reference_ImagingStudy|ImagingStudy": { + FromType: "Procedure", + EdgeLabel: "used_reference_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", @@ -57044,16 +37674,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "ImagingStudy/*", }, }, - "ImagingStudy|for_fhir_ImagingStudy|Task": { + "ImagingStudy|used_reference_ImagingStudy|Procedure": { FromType: "ImagingStudy", - EdgeLabel: "for_fhir_ImagingStudy", - ToType: "Task", + EdgeLabel: "used_reference_ImagingStudy", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -57061,15 +37691,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "ImagingStudy/*", }, }, - "Task|for_fhir_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "Task", - EdgeLabel: "for_fhir_FamilyMemberHistory", + "Procedure|used_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "Procedure", + EdgeLabel: "used_reference_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -57078,67 +37708,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "for_task", + "codeable_reference", }, RegexMatch: []string{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|for_fhir_FamilyMemberHistory|Task": { + "FamilyMemberHistory|used_reference_FamilyMemberHistory|Procedure": { FromType: "FamilyMemberHistory", - EdgeLabel: "for_fhir_FamilyMemberHistory", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "for_task", - }, - RegexMatch: []string{ - "FamilyMemberHistory/*", - }, - }, - "Task|for_fhir_BodyStructure|BodyStructure": { - FromType: "Task", - EdgeLabel: "for_fhir_BodyStructure", - ToType: "BodyStructure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "for_task", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "BodyStructure|for_fhir_BodyStructure|Task": { - FromType: "BodyStructure", - EdgeLabel: "for_fhir_BodyStructure", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "for_task", - }, - RegexMatch: []string{ - "BodyStructure/*", - }, - }, - "Task|owner_Practitioner|Practitioner": { - FromType: "Task", - EdgeLabel: "owner_Practitioner", - ToType: "Practitioner", + EdgeLabel: "used_reference_FamilyMemberHistory", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -57146,16 +37725,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "owner_task", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "FamilyMemberHistory/*", }, }, - "Practitioner|owner_Practitioner|Task": { - FromType: "Practitioner", - EdgeLabel: "owner_Practitioner", - ToType: "Task", + "Procedure|used_reference_BodyStructure|BodyStructure": { + FromType: "Procedure", + EdgeLabel: "used_reference_BodyStructure", + ToType: "BodyStructure", Direction: []string{ "outbound", }, @@ -57163,16 +37742,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "owner_task", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "BodyStructure/*", }, }, - "Task|owner_PractitionerRole|PractitionerRole": { - FromType: "Task", - EdgeLabel: "owner_PractitionerRole", - ToType: "PractitionerRole", + "BodyStructure|used_reference_BodyStructure|Procedure": { + FromType: "BodyStructure", + EdgeLabel: "used_reference_BodyStructure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -57180,101 +37759,101 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "owner_task", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "BodyStructure/*", }, }, - "PractitionerRole|owner_PractitionerRole|Task": { - FromType: "PractitionerRole", - EdgeLabel: "owner_PractitionerRole", - ToType: "Task", + "ResearchStudy|partOf|ResearchStudy": { + FromType: "ResearchStudy", + EdgeLabel: "partOf", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "owner_task", + "partOf_research_study", }, RegexMatch: []string{ - "PractitionerRole/*", + "ResearchStudy/*", }, }, - "Task|owner_Organization|Organization": { - FromType: "Task", - EdgeLabel: "owner_Organization", - ToType: "Organization", + "ResearchStudy|result_DiagnosticReport|DiagnosticReport": { + FromType: "ResearchStudy", + EdgeLabel: "result_DiagnosticReport", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "owner_task", + "result_research_study", }, RegexMatch: []string{ - "Organization/*", + "DiagnosticReport/*", }, }, - "Organization|owner_Organization|Task": { - FromType: "Organization", - EdgeLabel: "owner_Organization", - ToType: "Task", + "DiagnosticReport|result_DiagnosticReport|ResearchStudy": { + FromType: "DiagnosticReport", + EdgeLabel: "result_DiagnosticReport", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "owner_task", + "result_research_study", }, RegexMatch: []string{ - "Organization/*", + "DiagnosticReport/*", }, }, - "Task|owner_Patient|Patient": { - FromType: "Task", - EdgeLabel: "owner_Patient", - ToType: "Patient", + "ResearchStudy|site_ResearchStudy|ResearchStudy": { + FromType: "ResearchStudy", + EdgeLabel: "site_ResearchStudy", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "owner_task", + "site_research_study", }, RegexMatch: []string{ - "Patient/*", + "ResearchStudy/*", }, }, - "Patient|owner_Patient|Task": { - FromType: "Patient", - EdgeLabel: "owner_Patient", - ToType: "Task", + "ResearchStudy|site_Organization|Organization": { + FromType: "ResearchStudy", + EdgeLabel: "site_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "owner_task", + "site_research_study", }, RegexMatch: []string{ - "Patient/*", + "Organization/*", }, }, - "Task|partOf|Task": { - FromType: "Task", - EdgeLabel: "partOf", - ToType: "Task", + "Organization|site_Organization|ResearchStudy": { + FromType: "Organization", + EdgeLabel: "site_Organization", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57282,16 +37861,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "partOf_task", + "site_research_study", }, RegexMatch: []string{ - "Task/*", + "Organization/*", }, }, - "Task|requester_Organization|Organization": { - FromType: "Task", - EdgeLabel: "requester_Organization", - ToType: "Organization", + "ResearchStudy|associatedParty_party_Practitioner|Practitioner": { + FromType: "ResearchStudy", + EdgeLabel: "associatedParty_party_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -57299,16 +37878,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "requester_task", + "research_study_associated_party", }, RegexMatch: []string{ - "Organization/*", + "Practitioner/*", }, }, - "Organization|requester_Organization|Task": { - FromType: "Organization", - EdgeLabel: "requester_Organization", - ToType: "Task", + "Practitioner|associatedParty_party_Practitioner|ResearchStudy": { + FromType: "Practitioner", + EdgeLabel: "associatedParty_party_Practitioner", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57316,16 +37895,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "requester_task", + "research_study_associated_party", }, RegexMatch: []string{ - "Organization/*", + "Practitioner/*", }, }, - "Task|requester_Patient|Patient": { - FromType: "Task", - EdgeLabel: "requester_Patient", - ToType: "Patient", + "ResearchStudy|associatedParty_party_PractitionerRole|PractitionerRole": { + FromType: "ResearchStudy", + EdgeLabel: "associatedParty_party_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -57333,16 +37912,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "requester_task", + "research_study_associated_party", }, RegexMatch: []string{ - "Patient/*", + "PractitionerRole/*", }, }, - "Patient|requester_Patient|Task": { - FromType: "Patient", - EdgeLabel: "requester_Patient", - ToType: "Task", + "PractitionerRole|associatedParty_party_PractitionerRole|ResearchStudy": { + FromType: "PractitionerRole", + EdgeLabel: "associatedParty_party_PractitionerRole", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57350,16 +37929,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "requester_task", + "research_study_associated_party", }, RegexMatch: []string{ - "Patient/*", + "PractitionerRole/*", }, }, - "Task|requester_Practitioner|Practitioner": { - FromType: "Task", - EdgeLabel: "requester_Practitioner", - ToType: "Practitioner", + "ResearchStudy|associatedParty_party_Organization|Organization": { + FromType: "ResearchStudy", + EdgeLabel: "associatedParty_party_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -57367,16 +37946,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "requester_task", + "research_study_associated_party", }, RegexMatch: []string{ - "Practitioner/*", + "Organization/*", }, }, - "Practitioner|requester_Practitioner|Task": { - FromType: "Practitioner", - EdgeLabel: "requester_Practitioner", - ToType: "Task", + "Organization|associatedParty_party_Organization|ResearchStudy": { + FromType: "Organization", + EdgeLabel: "associatedParty_party_Organization", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57384,16 +37963,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "requester_task", + "research_study_associated_party", }, RegexMatch: []string{ - "Practitioner/*", + "Organization/*", }, }, - "Task|requester_PractitionerRole|PractitionerRole": { - FromType: "Task", - EdgeLabel: "requester_PractitionerRole", - ToType: "PractitionerRole", + "ResearchStudy|comparisonGroup_observedGroup|Group": { + FromType: "ResearchStudy", + EdgeLabel: "comparisonGroup_observedGroup", + ToType: "Group", Direction: []string{ "outbound", }, @@ -57401,16 +37980,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "requester_task", + "research_study_comparison_group", }, RegexMatch: []string{ - "PractitionerRole/*", + "Group/*", }, }, - "PractitionerRole|requester_PractitionerRole|Task": { - FromType: "PractitionerRole", - EdgeLabel: "requester_PractitionerRole", - ToType: "Task", + "Group|comparisonGroup_observedGroup|ResearchStudy": { + FromType: "Group", + EdgeLabel: "comparisonGroup_observedGroup", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57418,15 +37997,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "requester_task", + "research_study_comparison_group", }, RegexMatch: []string{ - "PractitionerRole/*", + "Group/*", }, }, - "Task|input_valueReference_Organization|Organization": { - FromType: "Task", - EdgeLabel: "input_valueReference_Organization", + "ResearchStudy|focus_reference_Organization|Organization": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_Organization", ToType: "Organization", Direction: []string{ "outbound", @@ -57435,16 +38014,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Organization/*", }, }, - "Organization|input_valueReference_Organization|Task": { + "Organization|focus_reference_Organization|ResearchStudy": { FromType: "Organization", - EdgeLabel: "input_valueReference_Organization", - ToType: "Task", + EdgeLabel: "focus_reference_Organization", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57452,15 +38031,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Organization/*", }, }, - "Task|input_valueReference_Group|Group": { - FromType: "Task", - EdgeLabel: "input_valueReference_Group", + "ResearchStudy|focus_reference_Group|Group": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_Group", ToType: "Group", Direction: []string{ "outbound", @@ -57469,16 +38048,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Group/*", }, }, - "Group|input_valueReference_Group|Task": { + "Group|focus_reference_Group|ResearchStudy": { FromType: "Group", - EdgeLabel: "input_valueReference_Group", - ToType: "Task", + EdgeLabel: "focus_reference_Group", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57486,15 +38065,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Group/*", }, }, - "Task|input_valueReference_Practitioner|Practitioner": { - FromType: "Task", - EdgeLabel: "input_valueReference_Practitioner", + "ResearchStudy|focus_reference_Practitioner|Practitioner": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", @@ -57503,16 +38082,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Practitioner|input_valueReference_Practitioner|Task": { + "Practitioner|focus_reference_Practitioner|ResearchStudy": { FromType: "Practitioner", - EdgeLabel: "input_valueReference_Practitioner", - ToType: "Task", + EdgeLabel: "focus_reference_Practitioner", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57520,15 +38099,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Task|input_valueReference_PractitionerRole|PractitionerRole": { - FromType: "Task", - EdgeLabel: "input_valueReference_PractitionerRole", + "ResearchStudy|focus_reference_PractitionerRole|PractitionerRole": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", @@ -57537,16 +38116,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "PractitionerRole|input_valueReference_PractitionerRole|Task": { + "PractitionerRole|focus_reference_PractitionerRole|ResearchStudy": { FromType: "PractitionerRole", - EdgeLabel: "input_valueReference_PractitionerRole", - ToType: "Task", + EdgeLabel: "focus_reference_PractitionerRole", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57554,15 +38133,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "Task|input_valueReference_ResearchStudy|ResearchStudy": { - FromType: "Task", - EdgeLabel: "input_valueReference_ResearchStudy", + "ResearchStudy|focus_reference_ResearchStudy|ResearchStudy": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -57571,32 +38150,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "ResearchStudy|input_valueReference_ResearchStudy|Task": { + "ResearchStudy|focus_reference_Patient|Patient": { FromType: "ResearchStudy", - EdgeLabel: "input_valueReference_ResearchStudy", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "task_input", - }, - RegexMatch: []string{ - "ResearchStudy/*", - }, - }, - "Task|input_valueReference_Patient|Patient": { - FromType: "Task", - EdgeLabel: "input_valueReference_Patient", + EdgeLabel: "focus_reference_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -57605,16 +38167,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|input_valueReference_Patient|Task": { + "Patient|focus_reference_Patient|ResearchStudy": { FromType: "Patient", - EdgeLabel: "input_valueReference_Patient", - ToType: "Task", + EdgeLabel: "focus_reference_Patient", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57622,15 +38184,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Patient/*", }, }, - "Task|input_valueReference_ResearchSubject|ResearchSubject": { - FromType: "Task", - EdgeLabel: "input_valueReference_ResearchSubject", + "ResearchStudy|focus_reference_ResearchSubject|ResearchSubject": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -57639,16 +38201,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "ResearchSubject|input_valueReference_ResearchSubject|Task": { + "ResearchSubject|focus_reference_ResearchSubject|ResearchStudy": { FromType: "ResearchSubject", - EdgeLabel: "input_valueReference_ResearchSubject", - ToType: "Task", + EdgeLabel: "focus_reference_ResearchSubject", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57656,15 +38218,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "Task|input_valueReference_Substance|Substance": { - FromType: "Task", - EdgeLabel: "input_valueReference_Substance", + "ResearchStudy|focus_reference_Substance|Substance": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -57673,16 +38235,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Substance/*", }, }, - "Substance|input_valueReference_Substance|Task": { + "Substance|focus_reference_Substance|ResearchStudy": { FromType: "Substance", - EdgeLabel: "input_valueReference_Substance", - ToType: "Task", + EdgeLabel: "focus_reference_Substance", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57690,15 +38252,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Substance/*", }, }, - "Task|input_valueReference_SubstanceDefinition|SubstanceDefinition": { - FromType: "Task", - EdgeLabel: "input_valueReference_SubstanceDefinition", + "ResearchStudy|focus_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -57707,16 +38269,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|input_valueReference_SubstanceDefinition|Task": { + "SubstanceDefinition|focus_reference_SubstanceDefinition|ResearchStudy": { FromType: "SubstanceDefinition", - EdgeLabel: "input_valueReference_SubstanceDefinition", - ToType: "Task", + EdgeLabel: "focus_reference_SubstanceDefinition", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57724,15 +38286,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "Task|input_valueReference_Specimen|Specimen": { - FromType: "Task", - EdgeLabel: "input_valueReference_Specimen", + "ResearchStudy|focus_reference_Specimen|Specimen": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -57741,16 +38303,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Specimen/*", }, }, - "Specimen|input_valueReference_Specimen|Task": { + "Specimen|focus_reference_Specimen|ResearchStudy": { FromType: "Specimen", - EdgeLabel: "input_valueReference_Specimen", - ToType: "Task", + EdgeLabel: "focus_reference_Specimen", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57758,15 +38320,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Specimen/*", }, }, - "Task|input_valueReference_Observation|Observation": { - FromType: "Task", - EdgeLabel: "input_valueReference_Observation", + "ResearchStudy|focus_reference_Observation|Observation": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -57775,16 +38337,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Observation/*", }, }, - "Observation|input_valueReference_Observation|Task": { + "Observation|focus_reference_Observation|ResearchStudy": { FromType: "Observation", - EdgeLabel: "input_valueReference_Observation", - ToType: "Task", + EdgeLabel: "focus_reference_Observation", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57792,15 +38354,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Observation/*", }, }, - "Task|input_valueReference_DiagnosticReport|DiagnosticReport": { - FromType: "Task", - EdgeLabel: "input_valueReference_DiagnosticReport", + "ResearchStudy|focus_reference_DiagnosticReport|DiagnosticReport": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -57809,16 +38371,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "DiagnosticReport|input_valueReference_DiagnosticReport|Task": { + "DiagnosticReport|focus_reference_DiagnosticReport|ResearchStudy": { FromType: "DiagnosticReport", - EdgeLabel: "input_valueReference_DiagnosticReport", - ToType: "Task", + EdgeLabel: "focus_reference_DiagnosticReport", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57826,15 +38388,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "Task|input_valueReference_Condition|Condition": { - FromType: "Task", - EdgeLabel: "input_valueReference_Condition", + "ResearchStudy|focus_reference_Condition|Condition": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -57843,16 +38405,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Condition/*", }, }, - "Condition|input_valueReference_Condition|Task": { + "Condition|focus_reference_Condition|ResearchStudy": { FromType: "Condition", - EdgeLabel: "input_valueReference_Condition", - ToType: "Task", + EdgeLabel: "focus_reference_Condition", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57860,15 +38422,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Condition/*", }, }, - "Task|input_valueReference_Medication|Medication": { - FromType: "Task", - EdgeLabel: "input_valueReference_Medication", + "ResearchStudy|focus_reference_Medication|Medication": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -57877,16 +38439,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Medication/*", }, }, - "Medication|input_valueReference_Medication|Task": { + "Medication|focus_reference_Medication|ResearchStudy": { FromType: "Medication", - EdgeLabel: "input_valueReference_Medication", - ToType: "Task", + EdgeLabel: "focus_reference_Medication", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57894,15 +38456,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Medication/*", }, }, - "Task|input_valueReference_MedicationAdministration|MedicationAdministration": { - FromType: "Task", - EdgeLabel: "input_valueReference_MedicationAdministration", + "ResearchStudy|focus_reference_MedicationAdministration|MedicationAdministration": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -57911,16 +38473,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "MedicationAdministration|input_valueReference_MedicationAdministration|Task": { + "MedicationAdministration|focus_reference_MedicationAdministration|ResearchStudy": { FromType: "MedicationAdministration", - EdgeLabel: "input_valueReference_MedicationAdministration", - ToType: "Task", + EdgeLabel: "focus_reference_MedicationAdministration", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57928,15 +38490,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "Task|input_valueReference_MedicationStatement|MedicationStatement": { - FromType: "Task", - EdgeLabel: "input_valueReference_MedicationStatement", + "ResearchStudy|focus_reference_MedicationStatement|MedicationStatement": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -57945,16 +38507,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "MedicationStatement|input_valueReference_MedicationStatement|Task": { + "MedicationStatement|focus_reference_MedicationStatement|ResearchStudy": { FromType: "MedicationStatement", - EdgeLabel: "input_valueReference_MedicationStatement", - ToType: "Task", + EdgeLabel: "focus_reference_MedicationStatement", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57962,15 +38524,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "Task|input_valueReference_MedicationRequest|MedicationRequest": { - FromType: "Task", - EdgeLabel: "input_valueReference_MedicationRequest", + "ResearchStudy|focus_reference_MedicationRequest|MedicationRequest": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -57979,16 +38541,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "MedicationRequest|input_valueReference_MedicationRequest|Task": { + "MedicationRequest|focus_reference_MedicationRequest|ResearchStudy": { FromType: "MedicationRequest", - EdgeLabel: "input_valueReference_MedicationRequest", - ToType: "Task", + EdgeLabel: "focus_reference_MedicationRequest", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -57996,15 +38558,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "Task|input_valueReference_Procedure|Procedure": { - FromType: "Task", - EdgeLabel: "input_valueReference_Procedure", + "ResearchStudy|focus_reference_Procedure|Procedure": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_Procedure", ToType: "Procedure", Direction: []string{ "outbound", @@ -58013,16 +38575,33 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Procedure/*", }, }, - "Procedure|input_valueReference_Procedure|Task": { + "Procedure|focus_reference_Procedure|ResearchStudy": { FromType: "Procedure", - EdgeLabel: "input_valueReference_Procedure", - ToType: "Task", + EdgeLabel: "focus_reference_Procedure", + ToType: "ResearchStudy", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "Procedure/*", + }, + }, + "ResearchStudy|focus_reference_DocumentReference|DocumentReference": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -58030,16 +38609,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ - "Procedure/*", + "DocumentReference/*", }, }, - "Task|input_valueReference_DocumentReference|DocumentReference": { - FromType: "Task", - EdgeLabel: "input_valueReference_DocumentReference", - ToType: "DocumentReference", + "DocumentReference|focus_reference_DocumentReference|ResearchStudy": { + FromType: "DocumentReference", + EdgeLabel: "focus_reference_DocumentReference", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58047,15 +38626,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "DocumentReference/*", }, }, - "DocumentReference|input_valueReference_DocumentReference|Task": { - FromType: "DocumentReference", - EdgeLabel: "input_valueReference_DocumentReference", + "ResearchStudy|focus_reference_Task|Task": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_Task", ToType: "Task", Direction: []string{ "outbound", @@ -58064,16 +38643,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ - "DocumentReference/*", + "Task/*", }, }, - "Task|input_valueReference_Task|Task": { + "Task|focus_reference_Task|ResearchStudy": { FromType: "Task", - EdgeLabel: "input_valueReference_Task", - ToType: "Task", + EdgeLabel: "focus_reference_Task", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58081,15 +38660,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "Task/*", }, }, - "Task|input_valueReference_ImagingStudy|ImagingStudy": { - FromType: "Task", - EdgeLabel: "input_valueReference_ImagingStudy", + "ResearchStudy|focus_reference_ImagingStudy|ImagingStudy": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", @@ -58098,16 +38677,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "ImagingStudy/*", }, }, - "ImagingStudy|input_valueReference_ImagingStudy|Task": { + "ImagingStudy|focus_reference_ImagingStudy|ResearchStudy": { FromType: "ImagingStudy", - EdgeLabel: "input_valueReference_ImagingStudy", - ToType: "Task", + EdgeLabel: "focus_reference_ImagingStudy", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58115,15 +38694,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "ImagingStudy/*", }, }, - "Task|input_valueReference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "Task", - EdgeLabel: "input_valueReference_FamilyMemberHistory", + "ResearchStudy|focus_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -58132,16 +38711,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|input_valueReference_FamilyMemberHistory|Task": { + "FamilyMemberHistory|focus_reference_FamilyMemberHistory|ResearchStudy": { FromType: "FamilyMemberHistory", - EdgeLabel: "input_valueReference_FamilyMemberHistory", - ToType: "Task", + EdgeLabel: "focus_reference_FamilyMemberHistory", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58149,15 +38728,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "FamilyMemberHistory/*", }, }, - "Task|input_valueReference_BodyStructure|BodyStructure": { - FromType: "Task", - EdgeLabel: "input_valueReference_BodyStructure", + "ResearchStudy|focus_reference_BodyStructure|BodyStructure": { + FromType: "ResearchStudy", + EdgeLabel: "focus_reference_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", @@ -58166,16 +38745,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "BodyStructure/*", }, }, - "BodyStructure|input_valueReference_BodyStructure|Task": { + "BodyStructure|focus_reference_BodyStructure|ResearchStudy": { FromType: "BodyStructure", - EdgeLabel: "input_valueReference_BodyStructure", - ToType: "Task", + EdgeLabel: "focus_reference_BodyStructure", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58183,14 +38762,14 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "codeable_reference", }, RegexMatch: []string{ "BodyStructure/*", }, }, - "Task|note_authorReference_Practitioner|Practitioner": { - FromType: "Task", + "ResearchStudy|note_authorReference_Practitioner|Practitioner": { + FromType: "ResearchStudy", EdgeLabel: "note_authorReference_Practitioner", ToType: "Practitioner", Direction: []string{ @@ -58206,10 +38785,10 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "Practitioner|note_authorReference_Practitioner|Task": { + "Practitioner|note_authorReference_Practitioner|ResearchStudy": { FromType: "Practitioner", EdgeLabel: "note_authorReference_Practitioner", - ToType: "Task", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58223,8 +38802,8 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "Task|note_authorReference_PractitionerRole|PractitionerRole": { - FromType: "Task", + "ResearchStudy|note_authorReference_PractitionerRole|PractitionerRole": { + FromType: "ResearchStudy", EdgeLabel: "note_authorReference_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ @@ -58240,10 +38819,10 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "PractitionerRole|note_authorReference_PractitionerRole|Task": { + "PractitionerRole|note_authorReference_PractitionerRole|ResearchStudy": { FromType: "PractitionerRole", EdgeLabel: "note_authorReference_PractitionerRole", - ToType: "Task", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58257,8 +38836,8 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "Task|note_authorReference_Patient|Patient": { - FromType: "Task", + "ResearchStudy|note_authorReference_Patient|Patient": { + FromType: "ResearchStudy", EdgeLabel: "note_authorReference_Patient", ToType: "Patient", Direction: []string{ @@ -58274,10 +38853,10 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "Patient|note_authorReference_Patient|Task": { + "Patient|note_authorReference_Patient|ResearchStudy": { FromType: "Patient", EdgeLabel: "note_authorReference_Patient", - ToType: "Task", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58291,8 +38870,8 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "Task|note_authorReference_Organization|Organization": { - FromType: "Task", + "ResearchStudy|note_authorReference_Organization|Organization": { + FromType: "ResearchStudy", EdgeLabel: "note_authorReference_Organization", ToType: "Organization", Direction: []string{ @@ -58308,10 +38887,10 @@ var Traversals = map[string]Traversal{ "Organization/*", }, }, - "Organization|note_authorReference_Organization|Task": { + "Organization|note_authorReference_Organization|ResearchStudy": { FromType: "Organization", EdgeLabel: "note_authorReference_Organization", - ToType: "Task", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58325,10 +38904,10 @@ var Traversals = map[string]Traversal{ "Organization/*", }, }, - "Task|output_valueReference_Organization|Organization": { - FromType: "Task", - EdgeLabel: "output_valueReference_Organization", - ToType: "Organization", + "ResearchStudy|recruitment_actualGroup|Group": { + FromType: "ResearchStudy", + EdgeLabel: "recruitment_actualGroup", + ToType: "Group", Direction: []string{ "outbound", }, @@ -58336,16 +38915,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "actualGroup_research_study_recruitment", }, RegexMatch: []string{ - "Organization/*", + "Group/*", }, }, - "Organization|output_valueReference_Organization|Task": { - FromType: "Organization", - EdgeLabel: "output_valueReference_Organization", - ToType: "Task", + "Group|recruitment_actualGroup|ResearchStudy": { + FromType: "Group", + EdgeLabel: "recruitment_actualGroup", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58353,15 +38932,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "actualGroup_research_study_recruitment", }, RegexMatch: []string{ - "Organization/*", + "Group/*", }, }, - "Task|output_valueReference_Group|Group": { - FromType: "Task", - EdgeLabel: "output_valueReference_Group", + "ResearchStudy|recruitment_eligibility_Group|Group": { + FromType: "ResearchStudy", + EdgeLabel: "recruitment_eligibility_Group", ToType: "Group", Direction: []string{ "outbound", @@ -58370,16 +38949,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "eligibility_research_study_recruitment", }, RegexMatch: []string{ "Group/*", }, }, - "Group|output_valueReference_Group|Task": { + "Group|recruitment_eligibility_Group|ResearchStudy": { FromType: "Group", - EdgeLabel: "output_valueReference_Group", - ToType: "Task", + EdgeLabel: "recruitment_eligibility_Group", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58387,16 +38966,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "eligibility_research_study_recruitment", }, RegexMatch: []string{ "Group/*", }, }, - "Task|output_valueReference_Practitioner|Practitioner": { - FromType: "Task", - EdgeLabel: "output_valueReference_Practitioner", - ToType: "Practitioner", + "ResearchStudy|relatedArtifact_resourceReference_Organization|Organization": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -58404,16 +38983,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ - "Practitioner/*", + "Organization/*", }, }, - "Practitioner|output_valueReference_Practitioner|Task": { - FromType: "Practitioner", - EdgeLabel: "output_valueReference_Practitioner", - ToType: "Task", + "Organization|relatedArtifact_resourceReference_Organization|ResearchStudy": { + FromType: "Organization", + EdgeLabel: "relatedArtifact_resourceReference_Organization", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58421,16 +39000,67 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", + }, + RegexMatch: []string{ + "Organization/*", + }, + }, + "ResearchStudy|relatedArtifact_resourceReference_Group|Group": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_Group", + ToType: "Group", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "related_artifact", + }, + RegexMatch: []string{ + "Group/*", + }, + }, + "Group|relatedArtifact_resourceReference_Group|ResearchStudy": { + FromType: "Group", + EdgeLabel: "relatedArtifact_resourceReference_Group", + ToType: "ResearchStudy", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "related_artifact", + }, + RegexMatch: []string{ + "Group/*", + }, + }, + "ResearchStudy|relatedArtifact_resourceReference_Practitioner|Practitioner": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_Practitioner", + ToType: "Practitioner", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "related_artifact", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Task|output_valueReference_PractitionerRole|PractitionerRole": { - FromType: "Task", - EdgeLabel: "output_valueReference_PractitionerRole", - ToType: "PractitionerRole", + "Practitioner|relatedArtifact_resourceReference_Practitioner|ResearchStudy": { + FromType: "Practitioner", + EdgeLabel: "relatedArtifact_resourceReference_Practitioner", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58438,16 +39068,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ - "PractitionerRole/*", + "Practitioner/*", }, }, - "PractitionerRole|output_valueReference_PractitionerRole|Task": { - FromType: "PractitionerRole", - EdgeLabel: "output_valueReference_PractitionerRole", - ToType: "Task", + "ResearchStudy|relatedArtifact_resourceReference_PractitionerRole|PractitionerRole": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -58455,15 +39085,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "Task|output_valueReference_ResearchStudy|ResearchStudy": { - FromType: "Task", - EdgeLabel: "output_valueReference_ResearchStudy", + "PractitionerRole|relatedArtifact_resourceReference_PractitionerRole|ResearchStudy": { + FromType: "PractitionerRole", + EdgeLabel: "relatedArtifact_resourceReference_PractitionerRole", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -58472,16 +39102,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ - "ResearchStudy/*", + "PractitionerRole/*", }, }, - "ResearchStudy|output_valueReference_ResearchStudy|Task": { + "ResearchStudy|relatedArtifact_resourceReference_ResearchStudy|ResearchStudy": { FromType: "ResearchStudy", - EdgeLabel: "output_valueReference_ResearchStudy", - ToType: "Task", + EdgeLabel: "relatedArtifact_resourceReference_ResearchStudy", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58489,15 +39119,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "Task|output_valueReference_Patient|Patient": { - FromType: "Task", - EdgeLabel: "output_valueReference_Patient", + "ResearchStudy|relatedArtifact_resourceReference_Patient|Patient": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -58506,16 +39136,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|output_valueReference_Patient|Task": { + "Patient|relatedArtifact_resourceReference_Patient|ResearchStudy": { FromType: "Patient", - EdgeLabel: "output_valueReference_Patient", - ToType: "Task", + EdgeLabel: "relatedArtifact_resourceReference_Patient", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58523,15 +39153,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "Patient/*", }, }, - "Task|output_valueReference_ResearchSubject|ResearchSubject": { - FromType: "Task", - EdgeLabel: "output_valueReference_ResearchSubject", + "ResearchStudy|relatedArtifact_resourceReference_ResearchSubject|ResearchSubject": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -58540,16 +39170,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "ResearchSubject|output_valueReference_ResearchSubject|Task": { + "ResearchSubject|relatedArtifact_resourceReference_ResearchSubject|ResearchStudy": { FromType: "ResearchSubject", - EdgeLabel: "output_valueReference_ResearchSubject", - ToType: "Task", + EdgeLabel: "relatedArtifact_resourceReference_ResearchSubject", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58557,15 +39187,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "Task|output_valueReference_Substance|Substance": { - FromType: "Task", - EdgeLabel: "output_valueReference_Substance", + "ResearchStudy|relatedArtifact_resourceReference_Substance|Substance": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -58574,16 +39204,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "Substance/*", }, }, - "Substance|output_valueReference_Substance|Task": { + "Substance|relatedArtifact_resourceReference_Substance|ResearchStudy": { FromType: "Substance", - EdgeLabel: "output_valueReference_Substance", - ToType: "Task", + EdgeLabel: "relatedArtifact_resourceReference_Substance", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58591,15 +39221,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "Substance/*", }, }, - "Task|output_valueReference_SubstanceDefinition|SubstanceDefinition": { - FromType: "Task", - EdgeLabel: "output_valueReference_SubstanceDefinition", + "ResearchStudy|relatedArtifact_resourceReference_SubstanceDefinition|SubstanceDefinition": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -58608,16 +39238,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|output_valueReference_SubstanceDefinition|Task": { + "SubstanceDefinition|relatedArtifact_resourceReference_SubstanceDefinition|ResearchStudy": { FromType: "SubstanceDefinition", - EdgeLabel: "output_valueReference_SubstanceDefinition", - ToType: "Task", + EdgeLabel: "relatedArtifact_resourceReference_SubstanceDefinition", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58625,15 +39255,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "Task|output_valueReference_Specimen|Specimen": { - FromType: "Task", - EdgeLabel: "output_valueReference_Specimen", + "ResearchStudy|relatedArtifact_resourceReference_Specimen|Specimen": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -58642,16 +39272,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "Specimen/*", }, }, - "Specimen|output_valueReference_Specimen|Task": { + "Specimen|relatedArtifact_resourceReference_Specimen|ResearchStudy": { FromType: "Specimen", - EdgeLabel: "output_valueReference_Specimen", - ToType: "Task", + EdgeLabel: "relatedArtifact_resourceReference_Specimen", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58659,15 +39289,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "Specimen/*", }, }, - "Task|output_valueReference_Observation|Observation": { - FromType: "Task", - EdgeLabel: "output_valueReference_Observation", + "ResearchStudy|relatedArtifact_resourceReference_Observation|Observation": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -58676,16 +39306,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "Observation/*", }, }, - "Observation|output_valueReference_Observation|Task": { + "Observation|relatedArtifact_resourceReference_Observation|ResearchStudy": { FromType: "Observation", - EdgeLabel: "output_valueReference_Observation", - ToType: "Task", + EdgeLabel: "relatedArtifact_resourceReference_Observation", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58693,15 +39323,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "Observation/*", }, }, - "Task|output_valueReference_DiagnosticReport|DiagnosticReport": { - FromType: "Task", - EdgeLabel: "output_valueReference_DiagnosticReport", + "ResearchStudy|relatedArtifact_resourceReference_DiagnosticReport|DiagnosticReport": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -58710,16 +39340,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "DiagnosticReport|output_valueReference_DiagnosticReport|Task": { + "DiagnosticReport|relatedArtifact_resourceReference_DiagnosticReport|ResearchStudy": { FromType: "DiagnosticReport", - EdgeLabel: "output_valueReference_DiagnosticReport", - ToType: "Task", + EdgeLabel: "relatedArtifact_resourceReference_DiagnosticReport", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58727,15 +39357,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "Task|output_valueReference_Condition|Condition": { - FromType: "Task", - EdgeLabel: "output_valueReference_Condition", + "ResearchStudy|relatedArtifact_resourceReference_Condition|Condition": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -58744,16 +39374,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "Condition/*", }, }, - "Condition|output_valueReference_Condition|Task": { + "Condition|relatedArtifact_resourceReference_Condition|ResearchStudy": { FromType: "Condition", - EdgeLabel: "output_valueReference_Condition", - ToType: "Task", + EdgeLabel: "relatedArtifact_resourceReference_Condition", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58761,15 +39391,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "Condition/*", }, }, - "Task|output_valueReference_Medication|Medication": { - FromType: "Task", - EdgeLabel: "output_valueReference_Medication", + "ResearchStudy|relatedArtifact_resourceReference_Medication|Medication": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -58778,16 +39408,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "Medication/*", }, }, - "Medication|output_valueReference_Medication|Task": { + "Medication|relatedArtifact_resourceReference_Medication|ResearchStudy": { FromType: "Medication", - EdgeLabel: "output_valueReference_Medication", - ToType: "Task", + EdgeLabel: "relatedArtifact_resourceReference_Medication", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58795,15 +39425,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "Medication/*", }, }, - "Task|output_valueReference_MedicationAdministration|MedicationAdministration": { - FromType: "Task", - EdgeLabel: "output_valueReference_MedicationAdministration", + "ResearchStudy|relatedArtifact_resourceReference_MedicationAdministration|MedicationAdministration": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -58812,16 +39442,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "MedicationAdministration|output_valueReference_MedicationAdministration|Task": { + "MedicationAdministration|relatedArtifact_resourceReference_MedicationAdministration|ResearchStudy": { FromType: "MedicationAdministration", - EdgeLabel: "output_valueReference_MedicationAdministration", - ToType: "Task", + EdgeLabel: "relatedArtifact_resourceReference_MedicationAdministration", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58829,15 +39459,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "Task|output_valueReference_MedicationStatement|MedicationStatement": { - FromType: "Task", - EdgeLabel: "output_valueReference_MedicationStatement", + "ResearchStudy|relatedArtifact_resourceReference_MedicationStatement|MedicationStatement": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -58846,16 +39476,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "MedicationStatement|output_valueReference_MedicationStatement|Task": { + "MedicationStatement|relatedArtifact_resourceReference_MedicationStatement|ResearchStudy": { FromType: "MedicationStatement", - EdgeLabel: "output_valueReference_MedicationStatement", - ToType: "Task", + EdgeLabel: "relatedArtifact_resourceReference_MedicationStatement", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58863,15 +39493,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "Task|output_valueReference_MedicationRequest|MedicationRequest": { - FromType: "Task", - EdgeLabel: "output_valueReference_MedicationRequest", + "ResearchStudy|relatedArtifact_resourceReference_MedicationRequest|MedicationRequest": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -58880,67 +39510,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "MedicationRequest|output_valueReference_MedicationRequest|Task": { + "MedicationRequest|relatedArtifact_resourceReference_MedicationRequest|ResearchStudy": { FromType: "MedicationRequest", - EdgeLabel: "output_valueReference_MedicationRequest", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "task_output", - }, - RegexMatch: []string{ - "MedicationRequest/*", - }, - }, - "Task|output_valueReference_Procedure|Procedure": { - FromType: "Task", - EdgeLabel: "output_valueReference_Procedure", - ToType: "Procedure", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "task_output", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Procedure|output_valueReference_Procedure|Task": { - FromType: "Procedure", - EdgeLabel: "output_valueReference_Procedure", - ToType: "Task", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "task_output", - }, - RegexMatch: []string{ - "Procedure/*", - }, - }, - "Task|output_valueReference_DocumentReference|DocumentReference": { - FromType: "Task", - EdgeLabel: "output_valueReference_DocumentReference", - ToType: "DocumentReference", + EdgeLabel: "relatedArtifact_resourceReference_MedicationRequest", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58948,16 +39527,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ - "DocumentReference/*", + "MedicationRequest/*", }, }, - "DocumentReference|output_valueReference_DocumentReference|Task": { - FromType: "DocumentReference", - EdgeLabel: "output_valueReference_DocumentReference", - ToType: "Task", + "ResearchStudy|relatedArtifact_resourceReference_Procedure|Procedure": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -58965,16 +39544,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ - "DocumentReference/*", + "Procedure/*", }, }, - "Task|output_valueReference_Task|Task": { - FromType: "Task", - EdgeLabel: "output_valueReference_Task", - ToType: "Task", + "Procedure|relatedArtifact_resourceReference_Procedure|ResearchStudy": { + FromType: "Procedure", + EdgeLabel: "relatedArtifact_resourceReference_Procedure", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -58982,16 +39561,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ - "Task/*", + "Procedure/*", }, }, - "Task|output_valueReference_ImagingStudy|ImagingStudy": { - FromType: "Task", - EdgeLabel: "output_valueReference_ImagingStudy", - ToType: "ImagingStudy", + "ResearchStudy|relatedArtifact_resourceReference_DocumentReference|DocumentReference": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -58999,16 +39578,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ - "ImagingStudy/*", + "DocumentReference/*", }, }, - "ImagingStudy|output_valueReference_ImagingStudy|Task": { - FromType: "ImagingStudy", - EdgeLabel: "output_valueReference_ImagingStudy", - ToType: "Task", + "DocumentReference|relatedArtifact_resourceReference_DocumentReference|ResearchStudy": { + FromType: "DocumentReference", + EdgeLabel: "relatedArtifact_resourceReference_DocumentReference", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -59016,16 +39595,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ - "ImagingStudy/*", + "DocumentReference/*", }, }, - "Task|output_valueReference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "Task", - EdgeLabel: "output_valueReference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", + "ResearchStudy|relatedArtifact_resourceReference_Task|Task": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_Task", + ToType: "Task", Direction: []string{ "outbound", }, @@ -59033,16 +39612,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Task/*", }, }, - "FamilyMemberHistory|output_valueReference_FamilyMemberHistory|Task": { - FromType: "FamilyMemberHistory", - EdgeLabel: "output_valueReference_FamilyMemberHistory", - ToType: "Task", + "Task|relatedArtifact_resourceReference_Task|ResearchStudy": { + FromType: "Task", + EdgeLabel: "relatedArtifact_resourceReference_Task", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -59050,16 +39629,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Task/*", }, }, - "Task|output_valueReference_BodyStructure|BodyStructure": { - FromType: "Task", - EdgeLabel: "output_valueReference_BodyStructure", - ToType: "BodyStructure", + "ResearchStudy|relatedArtifact_resourceReference_ImagingStudy|ImagingStudy": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_ImagingStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -59067,16 +39646,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ - "BodyStructure/*", + "ImagingStudy/*", }, }, - "BodyStructure|output_valueReference_BodyStructure|Task": { - FromType: "BodyStructure", - EdgeLabel: "output_valueReference_BodyStructure", - ToType: "Task", + "ImagingStudy|relatedArtifact_resourceReference_ImagingStudy|ResearchStudy": { + FromType: "ImagingStudy", + EdgeLabel: "relatedArtifact_resourceReference_ImagingStudy", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -59084,16 +39663,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_output", + "related_artifact", }, RegexMatch: []string{ - "BodyStructure/*", + "ImagingStudy/*", }, }, - "Task|performer_actor_Practitioner|Practitioner": { - FromType: "Task", - EdgeLabel: "performer_actor_Practitioner", - ToType: "Practitioner", + "ResearchStudy|relatedArtifact_resourceReference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_FamilyMemberHistory", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -59101,16 +39680,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_performer", + "related_artifact", }, RegexMatch: []string{ - "Practitioner/*", + "FamilyMemberHistory/*", }, }, - "Practitioner|performer_actor_Practitioner|Task": { - FromType: "Practitioner", - EdgeLabel: "performer_actor_Practitioner", - ToType: "Task", + "FamilyMemberHistory|relatedArtifact_resourceReference_FamilyMemberHistory|ResearchStudy": { + FromType: "FamilyMemberHistory", + EdgeLabel: "relatedArtifact_resourceReference_FamilyMemberHistory", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -59118,16 +39697,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_performer", + "related_artifact", }, RegexMatch: []string{ - "Practitioner/*", + "FamilyMemberHistory/*", }, }, - "Task|performer_actor_PractitionerRole|PractitionerRole": { - FromType: "Task", - EdgeLabel: "performer_actor_PractitionerRole", - ToType: "PractitionerRole", + "ResearchStudy|relatedArtifact_resourceReference_BodyStructure|BodyStructure": { + FromType: "ResearchStudy", + EdgeLabel: "relatedArtifact_resourceReference_BodyStructure", + ToType: "BodyStructure", Direction: []string{ "outbound", }, @@ -59135,16 +39714,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_performer", + "related_artifact", }, RegexMatch: []string{ - "PractitionerRole/*", + "BodyStructure/*", }, }, - "PractitionerRole|performer_actor_PractitionerRole|Task": { - FromType: "PractitionerRole", - EdgeLabel: "performer_actor_PractitionerRole", - ToType: "Task", + "BodyStructure|relatedArtifact_resourceReference_BodyStructure|ResearchStudy": { + FromType: "BodyStructure", + EdgeLabel: "relatedArtifact_resourceReference_BodyStructure", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -59152,16 +39731,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_performer", + "related_artifact", }, RegexMatch: []string{ - "PractitionerRole/*", + "BodyStructure/*", }, }, - "Task|performer_actor_Organization|Organization": { - FromType: "Task", - EdgeLabel: "performer_actor_Organization", - ToType: "Organization", + "ResearchSubject|study|ResearchStudy": { + FromType: "ResearchSubject", + EdgeLabel: "study", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -59169,16 +39748,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_performer", + "research_subject", }, RegexMatch: []string{ - "Organization/*", + "ResearchStudy/*", }, }, - "Organization|performer_actor_Organization|Task": { - FromType: "Organization", - EdgeLabel: "performer_actor_Organization", - ToType: "Task", + "ResearchStudy|study|ResearchSubject": { + FromType: "ResearchStudy", + EdgeLabel: "study", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, @@ -59186,15 +39765,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_performer", + "research_subject", }, RegexMatch: []string{ - "Organization/*", + "ResearchStudy/*", }, }, - "Task|performer_actor_Patient|Patient": { - FromType: "Task", - EdgeLabel: "performer_actor_Patient", + "ResearchSubject|subject_Patient|Patient": { + FromType: "ResearchSubject", + EdgeLabel: "subject_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -59203,16 +39782,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_performer", + "research_subject", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|performer_actor_Patient|Task": { + "Patient|subject_Patient|ResearchSubject": { FromType: "Patient", - EdgeLabel: "performer_actor_Patient", - ToType: "Task", + EdgeLabel: "subject_Patient", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, @@ -59220,16 +39799,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_performer", + "research_subject", }, RegexMatch: []string{ "Patient/*", }, }, - "Task|reason_reference_Organization|Organization": { - FromType: "Task", - EdgeLabel: "reason_reference_Organization", - ToType: "Organization", + "ResearchSubject|subject_Group|Group": { + FromType: "ResearchSubject", + EdgeLabel: "subject_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -59237,16 +39816,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "research_subject", }, RegexMatch: []string{ - "Organization/*", + "Group/*", }, }, - "Organization|reason_reference_Organization|Task": { - FromType: "Organization", - EdgeLabel: "reason_reference_Organization", - ToType: "Task", + "Group|subject_Group|ResearchSubject": { + FromType: "Group", + EdgeLabel: "subject_Group", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, @@ -59254,16 +39833,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "research_subject", }, RegexMatch: []string{ - "Organization/*", + "Group/*", }, }, - "Task|reason_reference_Group|Group": { - FromType: "Task", - EdgeLabel: "reason_reference_Group", - ToType: "Group", + "ResearchSubject|subject_Specimen|Specimen": { + FromType: "ResearchSubject", + EdgeLabel: "subject_Specimen", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -59271,16 +39850,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "research_subject", }, RegexMatch: []string{ - "Group/*", + "Specimen/*", }, }, - "Group|reason_reference_Group|Task": { - FromType: "Group", - EdgeLabel: "reason_reference_Group", - ToType: "Task", + "Specimen|subject_Specimen|ResearchSubject": { + FromType: "Specimen", + EdgeLabel: "subject_Specimen", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, @@ -59288,16 +39867,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "research_subject", }, RegexMatch: []string{ - "Group/*", + "Specimen/*", }, }, - "Task|reason_reference_Practitioner|Practitioner": { - FromType: "Task", - EdgeLabel: "reason_reference_Practitioner", - ToType: "Practitioner", + "ResearchSubject|subject_Medication|Medication": { + FromType: "ResearchSubject", + EdgeLabel: "subject_Medication", + ToType: "Medication", Direction: []string{ "outbound", }, @@ -59305,16 +39884,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "research_subject", }, RegexMatch: []string{ - "Practitioner/*", + "Medication/*", }, }, - "Practitioner|reason_reference_Practitioner|Task": { - FromType: "Practitioner", - EdgeLabel: "reason_reference_Practitioner", - ToType: "Task", + "Medication|subject_Medication|ResearchSubject": { + FromType: "Medication", + EdgeLabel: "subject_Medication", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, @@ -59322,16 +39901,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "research_subject", }, RegexMatch: []string{ - "Practitioner/*", + "Medication/*", }, }, - "Task|reason_reference_PractitionerRole|PractitionerRole": { - FromType: "Task", - EdgeLabel: "reason_reference_PractitionerRole", - ToType: "PractitionerRole", + "ResearchSubject|subject_Substance|Substance": { + FromType: "ResearchSubject", + EdgeLabel: "subject_Substance", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -59339,16 +39918,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "research_subject", }, RegexMatch: []string{ - "PractitionerRole/*", + "Substance/*", }, }, - "PractitionerRole|reason_reference_PractitionerRole|Task": { - FromType: "PractitionerRole", - EdgeLabel: "reason_reference_PractitionerRole", - ToType: "Task", + "Substance|subject_Substance|ResearchSubject": { + FromType: "Substance", + EdgeLabel: "subject_Substance", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, @@ -59356,33 +39935,33 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "research_subject", }, RegexMatch: []string{ - "PractitionerRole/*", + "Substance/*", }, }, - "Task|reason_reference_ResearchStudy|ResearchStudy": { - FromType: "Task", - EdgeLabel: "reason_reference_ResearchStudy", - ToType: "ResearchStudy", + "Specimen|parent|Specimen": { + FromType: "Specimen", + EdgeLabel: "parent", + ToType: "Specimen", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "parent_specimen", }, RegexMatch: []string{ - "ResearchStudy/*", + "Specimen/*", }, }, - "ResearchStudy|reason_reference_ResearchStudy|Task": { - FromType: "ResearchStudy", - EdgeLabel: "reason_reference_ResearchStudy", - ToType: "Task", + "Specimen|subject_Patient|Patient": { + FromType: "Specimen", + EdgeLabel: "subject_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -59390,16 +39969,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "specimen", }, RegexMatch: []string{ - "ResearchStudy/*", + "Patient/*", }, }, - "Task|reason_reference_Patient|Patient": { - FromType: "Task", - EdgeLabel: "reason_reference_Patient", - ToType: "Patient", + "Patient|subject_Patient|Specimen": { + FromType: "Patient", + EdgeLabel: "subject_Patient", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -59407,16 +39986,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "specimen", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|reason_reference_Patient|Task": { - FromType: "Patient", - EdgeLabel: "reason_reference_Patient", - ToType: "Task", + "Specimen|subject_Group|Group": { + FromType: "Specimen", + EdgeLabel: "subject_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -59424,16 +40003,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "specimen", }, RegexMatch: []string{ - "Patient/*", + "Group/*", }, }, - "Task|reason_reference_ResearchSubject|ResearchSubject": { - FromType: "Task", - EdgeLabel: "reason_reference_ResearchSubject", - ToType: "ResearchSubject", + "Group|subject_Group|Specimen": { + FromType: "Group", + EdgeLabel: "subject_Group", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -59441,16 +40020,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "specimen", }, RegexMatch: []string{ - "ResearchSubject/*", + "Group/*", }, }, - "ResearchSubject|reason_reference_ResearchSubject|Task": { - FromType: "ResearchSubject", - EdgeLabel: "reason_reference_ResearchSubject", - ToType: "Task", + "Specimen|subject_Substance|Substance": { + FromType: "Specimen", + EdgeLabel: "subject_Substance", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -59458,16 +40037,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "specimen", }, RegexMatch: []string{ - "ResearchSubject/*", + "Substance/*", }, }, - "Task|reason_reference_Substance|Substance": { - FromType: "Task", - EdgeLabel: "reason_reference_Substance", - ToType: "Substance", + "Substance|subject_Substance|Specimen": { + FromType: "Substance", + EdgeLabel: "subject_Substance", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -59475,16 +40054,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "specimen", }, RegexMatch: []string{ "Substance/*", }, }, - "Substance|reason_reference_Substance|Task": { - FromType: "Substance", - EdgeLabel: "reason_reference_Substance", - ToType: "Task", + "Specimen|collection_collector_Practitioner|Practitioner": { + FromType: "Specimen", + EdgeLabel: "collection_collector_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -59492,16 +40071,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "specimen_collection", }, RegexMatch: []string{ - "Substance/*", + "Practitioner/*", }, }, - "Task|reason_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "Task", - EdgeLabel: "reason_reference_SubstanceDefinition", - ToType: "SubstanceDefinition", + "Practitioner|collection_collector_Practitioner|Specimen": { + FromType: "Practitioner", + EdgeLabel: "collection_collector_Practitioner", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -59509,16 +40088,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "specimen_collection", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "Practitioner/*", }, }, - "SubstanceDefinition|reason_reference_SubstanceDefinition|Task": { - FromType: "SubstanceDefinition", - EdgeLabel: "reason_reference_SubstanceDefinition", - ToType: "Task", + "Specimen|collection_collector_PractitionerRole|PractitionerRole": { + FromType: "Specimen", + EdgeLabel: "collection_collector_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -59526,15 +40105,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "specimen_collection", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "PractitionerRole/*", }, }, - "Task|reason_reference_Specimen|Specimen": { - FromType: "Task", - EdgeLabel: "reason_reference_Specimen", + "PractitionerRole|collection_collector_PractitionerRole|Specimen": { + FromType: "PractitionerRole", + EdgeLabel: "collection_collector_PractitionerRole", ToType: "Specimen", Direction: []string{ "outbound", @@ -59543,16 +40122,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "specimen_collection", }, RegexMatch: []string{ - "Specimen/*", + "PractitionerRole/*", }, }, - "Specimen|reason_reference_Specimen|Task": { + "Specimen|collection_collector_Patient|Patient": { FromType: "Specimen", - EdgeLabel: "reason_reference_Specimen", - ToType: "Task", + EdgeLabel: "collection_collector_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -59560,16 +40139,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "specimen_collection", }, RegexMatch: []string{ - "Specimen/*", + "Patient/*", }, }, - "Task|reason_reference_Observation|Observation": { - FromType: "Task", - EdgeLabel: "reason_reference_Observation", - ToType: "Observation", + "Patient|collection_collector_Patient|Specimen": { + FromType: "Patient", + EdgeLabel: "collection_collector_Patient", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -59577,16 +40156,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "specimen_collection", }, RegexMatch: []string{ - "Observation/*", + "Patient/*", }, }, - "Observation|reason_reference_Observation|Task": { - FromType: "Observation", - EdgeLabel: "reason_reference_Observation", - ToType: "Task", + "Specimen|collection_procedure|Procedure": { + FromType: "Specimen", + EdgeLabel: "collection_procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -59594,16 +40173,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "specimen_collection", }, RegexMatch: []string{ - "Observation/*", + "Procedure/*", }, }, - "Task|reason_reference_DiagnosticReport|DiagnosticReport": { - FromType: "Task", - EdgeLabel: "reason_reference_DiagnosticReport", - ToType: "DiagnosticReport", + "Procedure|collection_procedure|Specimen": { + FromType: "Procedure", + EdgeLabel: "collection_procedure", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -59611,16 +40190,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "specimen_collection", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Procedure/*", }, }, - "DiagnosticReport|reason_reference_DiagnosticReport|Task": { - FromType: "DiagnosticReport", - EdgeLabel: "reason_reference_DiagnosticReport", - ToType: "Task", + "Specimen|note_authorReference_Practitioner|Practitioner": { + FromType: "Specimen", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -59628,16 +40207,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "DiagnosticReport/*", + "Practitioner/*", }, }, - "Task|reason_reference_Condition|Condition": { - FromType: "Task", - EdgeLabel: "reason_reference_Condition", - ToType: "Condition", + "Practitioner|note_authorReference_Practitioner|Specimen": { + FromType: "Practitioner", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -59645,16 +40224,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Condition/*", + "Practitioner/*", }, }, - "Condition|reason_reference_Condition|Task": { - FromType: "Condition", - EdgeLabel: "reason_reference_Condition", - ToType: "Task", + "Specimen|note_authorReference_PractitionerRole|PractitionerRole": { + FromType: "Specimen", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -59662,16 +40241,33 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Condition/*", + "PractitionerRole/*", }, }, - "Task|reason_reference_Medication|Medication": { - FromType: "Task", - EdgeLabel: "reason_reference_Medication", - ToType: "Medication", + "PractitionerRole|note_authorReference_PractitionerRole|Specimen": { + FromType: "PractitionerRole", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "Specimen", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "annotation", + }, + RegexMatch: []string{ + "PractitionerRole/*", + }, + }, + "Specimen|note_authorReference_Patient|Patient": { + FromType: "Specimen", + EdgeLabel: "note_authorReference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -59679,16 +40275,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Medication/*", + "Patient/*", }, }, - "Medication|reason_reference_Medication|Task": { - FromType: "Medication", - EdgeLabel: "reason_reference_Medication", - ToType: "Task", + "Patient|note_authorReference_Patient|Specimen": { + FromType: "Patient", + EdgeLabel: "note_authorReference_Patient", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -59696,16 +40292,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "Medication/*", + "Patient/*", }, }, - "Task|reason_reference_MedicationAdministration|MedicationAdministration": { - FromType: "Task", - EdgeLabel: "reason_reference_MedicationAdministration", - ToType: "MedicationAdministration", + "Specimen|note_authorReference_Organization|Organization": { + FromType: "Specimen", + EdgeLabel: "note_authorReference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -59713,16 +40309,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Organization/*", }, }, - "MedicationAdministration|reason_reference_MedicationAdministration|Task": { - FromType: "MedicationAdministration", - EdgeLabel: "reason_reference_MedicationAdministration", - ToType: "Task", + "Organization|note_authorReference_Organization|Specimen": { + FromType: "Organization", + EdgeLabel: "note_authorReference_Organization", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -59730,50 +40326,50 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Organization/*", }, }, - "Task|reason_reference_MedicationStatement|MedicationStatement": { - FromType: "Task", - EdgeLabel: "reason_reference_MedicationStatement", - ToType: "MedicationStatement", + "Specimen|processing_additive|Substance": { + FromType: "Specimen", + EdgeLabel: "processing_additive", + ToType: "Substance", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "additive_specimen_processing", }, RegexMatch: []string{ - "MedicationStatement/*", + "Substance/*", }, }, - "MedicationStatement|reason_reference_MedicationStatement|Task": { - FromType: "MedicationStatement", - EdgeLabel: "reason_reference_MedicationStatement", - ToType: "Task", + "Substance|processing_additive|Specimen": { + FromType: "Substance", + EdgeLabel: "processing_additive", + ToType: "Specimen", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "additive_specimen_processing", }, RegexMatch: []string{ - "MedicationStatement/*", + "Substance/*", }, }, - "Task|reason_reference_MedicationRequest|MedicationRequest": { - FromType: "Task", - EdgeLabel: "reason_reference_MedicationRequest", - ToType: "MedicationRequest", + "Substance|code_reference_Organization|Organization": { + FromType: "Substance", + EdgeLabel: "code_reference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -59784,13 +40380,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "MedicationRequest/*", + "Organization/*", }, }, - "MedicationRequest|reason_reference_MedicationRequest|Task": { - FromType: "MedicationRequest", - EdgeLabel: "reason_reference_MedicationRequest", - ToType: "Task", + "Organization|code_reference_Organization|Substance": { + FromType: "Organization", + EdgeLabel: "code_reference_Organization", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -59801,13 +40397,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "MedicationRequest/*", + "Organization/*", }, }, - "Task|reason_reference_Procedure|Procedure": { - FromType: "Task", - EdgeLabel: "reason_reference_Procedure", - ToType: "Procedure", + "Substance|code_reference_Group|Group": { + FromType: "Substance", + EdgeLabel: "code_reference_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -59818,13 +40414,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Procedure/*", + "Group/*", }, }, - "Procedure|reason_reference_Procedure|Task": { - FromType: "Procedure", - EdgeLabel: "reason_reference_Procedure", - ToType: "Task", + "Group|code_reference_Group|Substance": { + FromType: "Group", + EdgeLabel: "code_reference_Group", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -59835,13 +40431,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Procedure/*", + "Group/*", }, }, - "Task|reason_reference_DocumentReference|DocumentReference": { - FromType: "Task", - EdgeLabel: "reason_reference_DocumentReference", - ToType: "DocumentReference", + "Substance|code_reference_Practitioner|Practitioner": { + FromType: "Substance", + EdgeLabel: "code_reference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -59852,13 +40448,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "DocumentReference/*", + "Practitioner/*", }, }, - "DocumentReference|reason_reference_DocumentReference|Task": { - FromType: "DocumentReference", - EdgeLabel: "reason_reference_DocumentReference", - ToType: "Task", + "Practitioner|code_reference_Practitioner|Substance": { + FromType: "Practitioner", + EdgeLabel: "code_reference_Practitioner", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -59869,13 +40465,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "DocumentReference/*", + "Practitioner/*", }, }, - "Task|reason_reference_Task|Task": { - FromType: "Task", - EdgeLabel: "reason_reference_Task", - ToType: "Task", + "Substance|code_reference_PractitionerRole|PractitionerRole": { + FromType: "Substance", + EdgeLabel: "code_reference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -59886,13 +40482,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Task/*", + "PractitionerRole/*", }, }, - "Task|reason_reference_ImagingStudy|ImagingStudy": { - FromType: "Task", - EdgeLabel: "reason_reference_ImagingStudy", - ToType: "ImagingStudy", + "PractitionerRole|code_reference_PractitionerRole|Substance": { + FromType: "PractitionerRole", + EdgeLabel: "code_reference_PractitionerRole", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -59903,13 +40499,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "ImagingStudy/*", + "PractitionerRole/*", }, }, - "ImagingStudy|reason_reference_ImagingStudy|Task": { - FromType: "ImagingStudy", - EdgeLabel: "reason_reference_ImagingStudy", - ToType: "Task", + "Substance|code_reference_ResearchStudy|ResearchStudy": { + FromType: "Substance", + EdgeLabel: "code_reference_ResearchStudy", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -59920,13 +40516,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "ImagingStudy/*", + "ResearchStudy/*", }, }, - "Task|reason_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "Task", - EdgeLabel: "reason_reference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", + "ResearchStudy|code_reference_ResearchStudy|Substance": { + FromType: "ResearchStudy", + EdgeLabel: "code_reference_ResearchStudy", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -59937,13 +40533,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "ResearchStudy/*", }, }, - "FamilyMemberHistory|reason_reference_FamilyMemberHistory|Task": { - FromType: "FamilyMemberHistory", - EdgeLabel: "reason_reference_FamilyMemberHistory", - ToType: "Task", + "Substance|code_reference_Patient|Patient": { + FromType: "Substance", + EdgeLabel: "code_reference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -59954,13 +40550,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Patient/*", }, }, - "Task|reason_reference_BodyStructure|BodyStructure": { - FromType: "Task", - EdgeLabel: "reason_reference_BodyStructure", - ToType: "BodyStructure", + "Patient|code_reference_Patient|Substance": { + FromType: "Patient", + EdgeLabel: "code_reference_Patient", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -59971,13 +40567,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "BodyStructure/*", + "Patient/*", }, }, - "BodyStructure|reason_reference_BodyStructure|Task": { - FromType: "BodyStructure", - EdgeLabel: "reason_reference_BodyStructure", - ToType: "Task", + "Substance|code_reference_ResearchSubject|ResearchSubject": { + FromType: "Substance", + EdgeLabel: "code_reference_ResearchSubject", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, @@ -59988,13 +40584,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "BodyStructure/*", + "ResearchSubject/*", }, }, - "Task|requestedPerformer_reference_Organization|Organization": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_Organization", - ToType: "Organization", + "ResearchSubject|code_reference_ResearchSubject|Substance": { + FromType: "ResearchSubject", + EdgeLabel: "code_reference_ResearchSubject", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -60005,13 +40601,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "ResearchSubject/*", }, }, - "Organization|requestedPerformer_reference_Organization|Task": { - FromType: "Organization", - EdgeLabel: "requestedPerformer_reference_Organization", - ToType: "Task", + "Substance|code_reference_Substance|Substance": { + FromType: "Substance", + EdgeLabel: "code_reference_Substance", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -60022,13 +40618,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Substance/*", }, }, - "Task|requestedPerformer_reference_Group|Group": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_Group", - ToType: "Group", + "Substance|code_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "Substance", + EdgeLabel: "code_reference_SubstanceDefinition", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, @@ -60039,13 +40635,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "SubstanceDefinition/*", }, }, - "Group|requestedPerformer_reference_Group|Task": { - FromType: "Group", - EdgeLabel: "requestedPerformer_reference_Group", - ToType: "Task", + "SubstanceDefinition|code_reference_SubstanceDefinition|Substance": { + FromType: "SubstanceDefinition", + EdgeLabel: "code_reference_SubstanceDefinition", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -60056,13 +40652,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "SubstanceDefinition/*", }, }, - "Task|requestedPerformer_reference_Practitioner|Practitioner": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_Practitioner", - ToType: "Practitioner", + "Substance|code_reference_Specimen|Specimen": { + FromType: "Substance", + EdgeLabel: "code_reference_Specimen", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -60073,13 +40669,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Specimen/*", }, }, - "Practitioner|requestedPerformer_reference_Practitioner|Task": { - FromType: "Practitioner", - EdgeLabel: "requestedPerformer_reference_Practitioner", - ToType: "Task", + "Specimen|code_reference_Specimen|Substance": { + FromType: "Specimen", + EdgeLabel: "code_reference_Specimen", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -60090,13 +40686,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Specimen/*", }, }, - "Task|requestedPerformer_reference_PractitionerRole|PractitionerRole": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_PractitionerRole", - ToType: "PractitionerRole", + "Substance|code_reference_Observation|Observation": { + FromType: "Substance", + EdgeLabel: "code_reference_Observation", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -60107,13 +40703,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Observation/*", }, }, - "PractitionerRole|requestedPerformer_reference_PractitionerRole|Task": { - FromType: "PractitionerRole", - EdgeLabel: "requestedPerformer_reference_PractitionerRole", - ToType: "Task", + "Observation|code_reference_Observation|Substance": { + FromType: "Observation", + EdgeLabel: "code_reference_Observation", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -60124,13 +40720,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Observation/*", }, }, - "Task|requestedPerformer_reference_ResearchStudy|ResearchStudy": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_ResearchStudy", - ToType: "ResearchStudy", + "Substance|code_reference_DiagnosticReport|DiagnosticReport": { + FromType: "Substance", + EdgeLabel: "code_reference_DiagnosticReport", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -60141,13 +40737,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "ResearchStudy/*", + "DiagnosticReport/*", }, }, - "ResearchStudy|requestedPerformer_reference_ResearchStudy|Task": { - FromType: "ResearchStudy", - EdgeLabel: "requestedPerformer_reference_ResearchStudy", - ToType: "Task", + "DiagnosticReport|code_reference_DiagnosticReport|Substance": { + FromType: "DiagnosticReport", + EdgeLabel: "code_reference_DiagnosticReport", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -60158,13 +40754,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "ResearchStudy/*", + "DiagnosticReport/*", }, }, - "Task|requestedPerformer_reference_Patient|Patient": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_Patient", - ToType: "Patient", + "Substance|code_reference_Condition|Condition": { + FromType: "Substance", + EdgeLabel: "code_reference_Condition", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -60175,13 +40771,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "Condition/*", }, }, - "Patient|requestedPerformer_reference_Patient|Task": { - FromType: "Patient", - EdgeLabel: "requestedPerformer_reference_Patient", - ToType: "Task", + "Condition|code_reference_Condition|Substance": { + FromType: "Condition", + EdgeLabel: "code_reference_Condition", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -60192,13 +40788,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "Condition/*", }, }, - "Task|requestedPerformer_reference_ResearchSubject|ResearchSubject": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_ResearchSubject", - ToType: "ResearchSubject", + "Substance|code_reference_Medication|Medication": { + FromType: "Substance", + EdgeLabel: "code_reference_Medication", + ToType: "Medication", Direction: []string{ "outbound", }, @@ -60209,13 +40805,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "ResearchSubject/*", + "Medication/*", }, }, - "ResearchSubject|requestedPerformer_reference_ResearchSubject|Task": { - FromType: "ResearchSubject", - EdgeLabel: "requestedPerformer_reference_ResearchSubject", - ToType: "Task", + "Medication|code_reference_Medication|Substance": { + FromType: "Medication", + EdgeLabel: "code_reference_Medication", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -60226,13 +40822,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "ResearchSubject/*", + "Medication/*", }, }, - "Task|requestedPerformer_reference_Substance|Substance": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_Substance", - ToType: "Substance", + "Substance|code_reference_MedicationAdministration|MedicationAdministration": { + FromType: "Substance", + EdgeLabel: "code_reference_MedicationAdministration", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -60243,13 +40839,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Substance/*", + "MedicationAdministration/*", }, }, - "Substance|requestedPerformer_reference_Substance|Task": { - FromType: "Substance", - EdgeLabel: "requestedPerformer_reference_Substance", - ToType: "Task", + "MedicationAdministration|code_reference_MedicationAdministration|Substance": { + FromType: "MedicationAdministration", + EdgeLabel: "code_reference_MedicationAdministration", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -60260,13 +40856,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Substance/*", + "MedicationAdministration/*", }, }, - "Task|requestedPerformer_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_SubstanceDefinition", - ToType: "SubstanceDefinition", + "Substance|code_reference_MedicationStatement|MedicationStatement": { + FromType: "Substance", + EdgeLabel: "code_reference_MedicationStatement", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -60277,13 +40873,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "MedicationStatement/*", }, }, - "SubstanceDefinition|requestedPerformer_reference_SubstanceDefinition|Task": { - FromType: "SubstanceDefinition", - EdgeLabel: "requestedPerformer_reference_SubstanceDefinition", - ToType: "Task", + "MedicationStatement|code_reference_MedicationStatement|Substance": { + FromType: "MedicationStatement", + EdgeLabel: "code_reference_MedicationStatement", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -60294,13 +40890,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "MedicationStatement/*", }, }, - "Task|requestedPerformer_reference_Specimen|Specimen": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_Specimen", - ToType: "Specimen", + "Substance|code_reference_MedicationRequest|MedicationRequest": { + FromType: "Substance", + EdgeLabel: "code_reference_MedicationRequest", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -60311,13 +40907,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Specimen/*", + "MedicationRequest/*", }, }, - "Specimen|requestedPerformer_reference_Specimen|Task": { - FromType: "Specimen", - EdgeLabel: "requestedPerformer_reference_Specimen", - ToType: "Task", + "MedicationRequest|code_reference_MedicationRequest|Substance": { + FromType: "MedicationRequest", + EdgeLabel: "code_reference_MedicationRequest", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -60328,13 +40924,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Specimen/*", + "MedicationRequest/*", }, }, - "Task|requestedPerformer_reference_Observation|Observation": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_Observation", - ToType: "Observation", + "Substance|code_reference_Procedure|Procedure": { + FromType: "Substance", + EdgeLabel: "code_reference_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -60345,13 +40941,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Observation/*", + "Procedure/*", }, }, - "Observation|requestedPerformer_reference_Observation|Task": { - FromType: "Observation", - EdgeLabel: "requestedPerformer_reference_Observation", - ToType: "Task", + "Procedure|code_reference_Procedure|Substance": { + FromType: "Procedure", + EdgeLabel: "code_reference_Procedure", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -60362,13 +40958,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Observation/*", + "Procedure/*", }, }, - "Task|requestedPerformer_reference_DiagnosticReport|DiagnosticReport": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_DiagnosticReport", - ToType: "DiagnosticReport", + "Substance|code_reference_DocumentReference|DocumentReference": { + FromType: "Substance", + EdgeLabel: "code_reference_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -60379,13 +40975,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "DiagnosticReport/*", + "DocumentReference/*", }, }, - "DiagnosticReport|requestedPerformer_reference_DiagnosticReport|Task": { - FromType: "DiagnosticReport", - EdgeLabel: "requestedPerformer_reference_DiagnosticReport", - ToType: "Task", + "DocumentReference|code_reference_DocumentReference|Substance": { + FromType: "DocumentReference", + EdgeLabel: "code_reference_DocumentReference", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -60396,13 +40992,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "DiagnosticReport/*", + "DocumentReference/*", }, }, - "Task|requestedPerformer_reference_Condition|Condition": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_Condition", - ToType: "Condition", + "Substance|code_reference_Task|Task": { + FromType: "Substance", + EdgeLabel: "code_reference_Task", + ToType: "Task", Direction: []string{ "outbound", }, @@ -60413,13 +41009,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Condition/*", + "Task/*", }, }, - "Condition|requestedPerformer_reference_Condition|Task": { - FromType: "Condition", - EdgeLabel: "requestedPerformer_reference_Condition", - ToType: "Task", + "Task|code_reference_Task|Substance": { + FromType: "Task", + EdgeLabel: "code_reference_Task", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -60430,13 +41026,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Condition/*", + "Task/*", }, }, - "Task|requestedPerformer_reference_Medication|Medication": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_Medication", - ToType: "Medication", + "Substance|code_reference_ImagingStudy|ImagingStudy": { + FromType: "Substance", + EdgeLabel: "code_reference_ImagingStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -60447,13 +41043,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Medication/*", + "ImagingStudy/*", }, }, - "Medication|requestedPerformer_reference_Medication|Task": { - FromType: "Medication", - EdgeLabel: "requestedPerformer_reference_Medication", - ToType: "Task", + "ImagingStudy|code_reference_ImagingStudy|Substance": { + FromType: "ImagingStudy", + EdgeLabel: "code_reference_ImagingStudy", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -60464,13 +41060,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "Medication/*", + "ImagingStudy/*", }, }, - "Task|requestedPerformer_reference_MedicationAdministration|MedicationAdministration": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_MedicationAdministration", - ToType: "MedicationAdministration", + "Substance|code_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "Substance", + EdgeLabel: "code_reference_FamilyMemberHistory", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -60481,13 +41077,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "MedicationAdministration/*", + "FamilyMemberHistory/*", }, }, - "MedicationAdministration|requestedPerformer_reference_MedicationAdministration|Task": { - FromType: "MedicationAdministration", - EdgeLabel: "requestedPerformer_reference_MedicationAdministration", - ToType: "Task", + "FamilyMemberHistory|code_reference_FamilyMemberHistory|Substance": { + FromType: "FamilyMemberHistory", + EdgeLabel: "code_reference_FamilyMemberHistory", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -60498,13 +41094,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "MedicationAdministration/*", + "FamilyMemberHistory/*", }, }, - "Task|requestedPerformer_reference_MedicationStatement|MedicationStatement": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_MedicationStatement", - ToType: "MedicationStatement", + "Substance|code_reference_BodyStructure|BodyStructure": { + FromType: "Substance", + EdgeLabel: "code_reference_BodyStructure", + ToType: "BodyStructure", Direction: []string{ "outbound", }, @@ -60515,13 +41111,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "MedicationStatement/*", + "BodyStructure/*", }, }, - "MedicationStatement|requestedPerformer_reference_MedicationStatement|Task": { - FromType: "MedicationStatement", - EdgeLabel: "requestedPerformer_reference_MedicationStatement", - ToType: "Task", + "BodyStructure|code_reference_BodyStructure|Substance": { + FromType: "BodyStructure", + EdgeLabel: "code_reference_BodyStructure", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -60532,13 +41128,13 @@ var Traversals = map[string]Traversal{ "codeable_reference", }, RegexMatch: []string{ - "MedicationStatement/*", + "BodyStructure/*", }, }, - "Task|requestedPerformer_reference_MedicationRequest|MedicationRequest": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_MedicationRequest", - ToType: "MedicationRequest", + "Substance|ingredient_substanceReference|Substance": { + FromType: "Substance", + EdgeLabel: "ingredient_substanceReference", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -60546,152 +41142,152 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "substance_ingredient", }, RegexMatch: []string{ - "MedicationRequest/*", + "Substance/*", }, }, - "MedicationRequest|requestedPerformer_reference_MedicationRequest|Task": { - FromType: "MedicationRequest", - EdgeLabel: "requestedPerformer_reference_MedicationRequest", - ToType: "Task", + "SubstanceDefinition|manufacturer|Organization": { + FromType: "SubstanceDefinition", + EdgeLabel: "manufacturer", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "manufacturer_substance_definition", }, RegexMatch: []string{ - "MedicationRequest/*", + "Organization/*", }, }, - "Task|requestedPerformer_reference_Procedure|Procedure": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_Procedure", - ToType: "Procedure", + "Organization|manufacturer|SubstanceDefinition": { + FromType: "Organization", + EdgeLabel: "manufacturer", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "manufacturer_substance_definition", }, RegexMatch: []string{ - "Procedure/*", + "Organization/*", }, }, - "Procedure|requestedPerformer_reference_Procedure|Task": { - FromType: "Procedure", - EdgeLabel: "requestedPerformer_reference_Procedure", - ToType: "Task", + "SubstanceDefinition|supplier|Organization": { + FromType: "SubstanceDefinition", + EdgeLabel: "supplier", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "supplier_substance_definition", }, RegexMatch: []string{ - "Procedure/*", + "Organization/*", }, }, - "Task|requestedPerformer_reference_DocumentReference|DocumentReference": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_DocumentReference", - ToType: "DocumentReference", + "Organization|supplier|SubstanceDefinition": { + FromType: "Organization", + EdgeLabel: "supplier", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "supplier_substance_definition", }, RegexMatch: []string{ - "DocumentReference/*", + "Organization/*", }, }, - "DocumentReference|requestedPerformer_reference_DocumentReference|Task": { - FromType: "DocumentReference", - EdgeLabel: "requestedPerformer_reference_DocumentReference", - ToType: "Task", + "SubstanceDefinition|code_source|DocumentReference": { + FromType: "SubstanceDefinition", + EdgeLabel: "code_source", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "source_substance_definition_code", }, RegexMatch: []string{ "DocumentReference/*", }, }, - "Task|requestedPerformer_reference_Task|Task": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_Task", - ToType: "Task", + "DocumentReference|code_source|SubstanceDefinition": { + FromType: "DocumentReference", + EdgeLabel: "code_source", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "source_substance_definition_code", }, RegexMatch: []string{ - "Task/*", + "DocumentReference/*", }, }, - "Task|requestedPerformer_reference_ImagingStudy|ImagingStudy": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_ImagingStudy", - ToType: "ImagingStudy", + "SubstanceDefinition|name_source|DocumentReference": { + FromType: "SubstanceDefinition", + EdgeLabel: "name_source", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "source_substance_definition_name", }, RegexMatch: []string{ - "ImagingStudy/*", + "DocumentReference/*", }, }, - "ImagingStudy|requestedPerformer_reference_ImagingStudy|Task": { - FromType: "ImagingStudy", - EdgeLabel: "requestedPerformer_reference_ImagingStudy", - ToType: "Task", + "DocumentReference|name_source|SubstanceDefinition": { + FromType: "DocumentReference", + EdgeLabel: "name_source", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "source_substance_definition_name", }, RegexMatch: []string{ - "ImagingStudy/*", + "DocumentReference/*", }, }, - "Task|requestedPerformer_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", + "SubstanceDefinition|note_authorReference_Practitioner|Practitioner": { + FromType: "SubstanceDefinition", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -60699,16 +41295,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Practitioner/*", }, }, - "FamilyMemberHistory|requestedPerformer_reference_FamilyMemberHistory|Task": { - FromType: "FamilyMemberHistory", - EdgeLabel: "requestedPerformer_reference_FamilyMemberHistory", - ToType: "Task", + "Practitioner|note_authorReference_Practitioner|SubstanceDefinition": { + FromType: "Practitioner", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, @@ -60716,16 +41312,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Practitioner/*", }, }, - "Task|requestedPerformer_reference_BodyStructure|BodyStructure": { - FromType: "Task", - EdgeLabel: "requestedPerformer_reference_BodyStructure", - ToType: "BodyStructure", + "SubstanceDefinition|note_authorReference_PractitionerRole|PractitionerRole": { + FromType: "SubstanceDefinition", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -60733,16 +41329,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "BodyStructure/*", + "PractitionerRole/*", }, }, - "BodyStructure|requestedPerformer_reference_BodyStructure|Task": { - FromType: "BodyStructure", - EdgeLabel: "requestedPerformer_reference_BodyStructure", - ToType: "Task", + "PractitionerRole|note_authorReference_PractitionerRole|SubstanceDefinition": { + FromType: "PractitionerRole", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, @@ -60750,101 +41346,84 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "annotation", }, RegexMatch: []string{ - "BodyStructure/*", + "PractitionerRole/*", }, }, - "Task|restriction_recipient_Patient|Patient": { - FromType: "Task", - EdgeLabel: "restriction_recipient_Patient", + "SubstanceDefinition|note_authorReference_Patient|Patient": { + FromType: "SubstanceDefinition", + EdgeLabel: "note_authorReference_Patient", ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "recipient_task_restriction", + "annotation", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|restriction_recipient_Patient|Task": { + "Patient|note_authorReference_Patient|SubstanceDefinition": { FromType: "Patient", - EdgeLabel: "restriction_recipient_Patient", - ToType: "Task", + EdgeLabel: "note_authorReference_Patient", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "recipient_task_restriction", + "annotation", }, RegexMatch: []string{ "Patient/*", }, }, - "Task|restriction_recipient_Practitioner|Practitioner": { - FromType: "Task", - EdgeLabel: "restriction_recipient_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_many", - }, - Backref: []string{ - "recipient_task_restriction", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|restriction_recipient_Practitioner|Task": { - FromType: "Practitioner", - EdgeLabel: "restriction_recipient_Practitioner", - ToType: "Task", + "SubstanceDefinition|note_authorReference_Organization|Organization": { + FromType: "SubstanceDefinition", + EdgeLabel: "note_authorReference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "recipient_task_restriction", + "annotation", }, RegexMatch: []string{ - "Practitioner/*", + "Organization/*", }, }, - "Task|restriction_recipient_PractitionerRole|PractitionerRole": { - FromType: "Task", - EdgeLabel: "restriction_recipient_PractitionerRole", - ToType: "PractitionerRole", + "Organization|note_authorReference_Organization|SubstanceDefinition": { + FromType: "Organization", + EdgeLabel: "note_authorReference_Organization", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "recipient_task_restriction", + "annotation", }, RegexMatch: []string{ - "PractitionerRole/*", + "Organization/*", }, }, - "PractitionerRole|restriction_recipient_PractitionerRole|Task": { - FromType: "PractitionerRole", - EdgeLabel: "restriction_recipient_PractitionerRole", - ToType: "Task", + "SubstanceDefinition|relationship_source|DocumentReference": { + FromType: "SubstanceDefinition", + EdgeLabel: "relationship_source", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -60852,16 +41431,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "recipient_task_restriction", + "source_substance_definition_relationship", }, RegexMatch: []string{ - "PractitionerRole/*", + "DocumentReference/*", }, }, - "Task|restriction_recipient_Group|Group": { - FromType: "Task", - EdgeLabel: "restriction_recipient_Group", - ToType: "Group", + "DocumentReference|relationship_source|SubstanceDefinition": { + FromType: "DocumentReference", + EdgeLabel: "relationship_source", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, @@ -60869,33 +41448,33 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "recipient_task_restriction", + "source_substance_definition_relationship", }, RegexMatch: []string{ - "Group/*", + "DocumentReference/*", }, }, - "Group|restriction_recipient_Group|Task": { - FromType: "Group", - EdgeLabel: "restriction_recipient_Group", - ToType: "Task", + "SubstanceDefinition|relationship_substanceDefinitionReference|SubstanceDefinition": { + FromType: "SubstanceDefinition", + EdgeLabel: "relationship_substanceDefinitionReference", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "recipient_task_restriction", + "substance_definition_relationship", }, RegexMatch: []string{ - "Group/*", + "SubstanceDefinition/*", }, }, - "Task|restriction_recipient_Organization|Organization": { - FromType: "Task", - EdgeLabel: "restriction_recipient_Organization", - ToType: "Organization", + "SubstanceDefinition|structure_sourceDocument|DocumentReference": { + FromType: "SubstanceDefinition", + EdgeLabel: "structure_sourceDocument", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -60903,16 +41482,16 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "recipient_task_restriction", + "sourceDocument_substance_definition_structure", }, RegexMatch: []string{ - "Organization/*", + "DocumentReference/*", }, }, - "Organization|restriction_recipient_Organization|Task": { - FromType: "Organization", - EdgeLabel: "restriction_recipient_Organization", - ToType: "Task", + "DocumentReference|structure_sourceDocument|SubstanceDefinition": { + FromType: "DocumentReference", + EdgeLabel: "structure_sourceDocument", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, @@ -60920,780 +41499,780 @@ var Traversals = map[string]Traversal{ "has_many", }, Backref: []string{ - "recipient_task_restriction", + "sourceDocument_substance_definition_structure", }, RegexMatch: []string{ - "Organization/*", + "DocumentReference/*", }, }, - "Task|statusReason_reference_Organization|Organization": { + "Task|basedOn_Organization|Organization": { FromType: "Task", - EdgeLabel: "statusReason_reference_Organization", + EdgeLabel: "basedOn_Organization", ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Organization/*", }, }, - "Organization|statusReason_reference_Organization|Task": { + "Organization|basedOn_Organization|Task": { FromType: "Organization", - EdgeLabel: "statusReason_reference_Organization", + EdgeLabel: "basedOn_Organization", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Organization/*", }, }, - "Task|statusReason_reference_Group|Group": { + "Task|basedOn_Group|Group": { FromType: "Task", - EdgeLabel: "statusReason_reference_Group", + EdgeLabel: "basedOn_Group", ToType: "Group", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Group/*", }, }, - "Group|statusReason_reference_Group|Task": { + "Group|basedOn_Group|Task": { FromType: "Group", - EdgeLabel: "statusReason_reference_Group", + EdgeLabel: "basedOn_Group", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Group/*", }, }, - "Task|statusReason_reference_Practitioner|Practitioner": { + "Task|basedOn_Practitioner|Practitioner": { FromType: "Task", - EdgeLabel: "statusReason_reference_Practitioner", + EdgeLabel: "basedOn_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Practitioner|statusReason_reference_Practitioner|Task": { + "Practitioner|basedOn_Practitioner|Task": { FromType: "Practitioner", - EdgeLabel: "statusReason_reference_Practitioner", + EdgeLabel: "basedOn_Practitioner", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Task|statusReason_reference_PractitionerRole|PractitionerRole": { + "Task|basedOn_PractitionerRole|PractitionerRole": { FromType: "Task", - EdgeLabel: "statusReason_reference_PractitionerRole", + EdgeLabel: "basedOn_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "PractitionerRole|statusReason_reference_PractitionerRole|Task": { + "PractitionerRole|basedOn_PractitionerRole|Task": { FromType: "PractitionerRole", - EdgeLabel: "statusReason_reference_PractitionerRole", + EdgeLabel: "basedOn_PractitionerRole", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "Task|statusReason_reference_ResearchStudy|ResearchStudy": { + "Task|basedOn_ResearchStudy|ResearchStudy": { FromType: "Task", - EdgeLabel: "statusReason_reference_ResearchStudy", + EdgeLabel: "basedOn_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "ResearchStudy|statusReason_reference_ResearchStudy|Task": { + "ResearchStudy|basedOn_ResearchStudy|Task": { FromType: "ResearchStudy", - EdgeLabel: "statusReason_reference_ResearchStudy", + EdgeLabel: "basedOn_ResearchStudy", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "Task|statusReason_reference_Patient|Patient": { + "Task|basedOn_Patient|Patient": { FromType: "Task", - EdgeLabel: "statusReason_reference_Patient", + EdgeLabel: "basedOn_Patient", ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|statusReason_reference_Patient|Task": { + "Patient|basedOn_Patient|Task": { FromType: "Patient", - EdgeLabel: "statusReason_reference_Patient", + EdgeLabel: "basedOn_Patient", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Patient/*", }, }, - "Task|statusReason_reference_ResearchSubject|ResearchSubject": { + "Task|basedOn_ResearchSubject|ResearchSubject": { FromType: "Task", - EdgeLabel: "statusReason_reference_ResearchSubject", + EdgeLabel: "basedOn_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "ResearchSubject|statusReason_reference_ResearchSubject|Task": { + "ResearchSubject|basedOn_ResearchSubject|Task": { FromType: "ResearchSubject", - EdgeLabel: "statusReason_reference_ResearchSubject", + EdgeLabel: "basedOn_ResearchSubject", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "Task|statusReason_reference_Substance|Substance": { + "Task|basedOn_Substance|Substance": { FromType: "Task", - EdgeLabel: "statusReason_reference_Substance", + EdgeLabel: "basedOn_Substance", ToType: "Substance", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Substance/*", }, }, - "Substance|statusReason_reference_Substance|Task": { + "Substance|basedOn_Substance|Task": { FromType: "Substance", - EdgeLabel: "statusReason_reference_Substance", + EdgeLabel: "basedOn_Substance", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Substance/*", }, }, - "Task|statusReason_reference_SubstanceDefinition|SubstanceDefinition": { + "Task|basedOn_SubstanceDefinition|SubstanceDefinition": { FromType: "Task", - EdgeLabel: "statusReason_reference_SubstanceDefinition", + EdgeLabel: "basedOn_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|statusReason_reference_SubstanceDefinition|Task": { + "SubstanceDefinition|basedOn_SubstanceDefinition|Task": { FromType: "SubstanceDefinition", - EdgeLabel: "statusReason_reference_SubstanceDefinition", + EdgeLabel: "basedOn_SubstanceDefinition", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "Task|statusReason_reference_Specimen|Specimen": { + "Task|basedOn_Specimen|Specimen": { FromType: "Task", - EdgeLabel: "statusReason_reference_Specimen", + EdgeLabel: "basedOn_Specimen", ToType: "Specimen", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Specimen/*", }, }, - "Specimen|statusReason_reference_Specimen|Task": { + "Specimen|basedOn_Specimen|Task": { FromType: "Specimen", - EdgeLabel: "statusReason_reference_Specimen", + EdgeLabel: "basedOn_Specimen", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Specimen/*", }, }, - "Task|statusReason_reference_Observation|Observation": { + "Task|basedOn_Observation|Observation": { FromType: "Task", - EdgeLabel: "statusReason_reference_Observation", + EdgeLabel: "basedOn_Observation", ToType: "Observation", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Observation/*", }, }, - "Observation|statusReason_reference_Observation|Task": { + "Observation|basedOn_Observation|Task": { FromType: "Observation", - EdgeLabel: "statusReason_reference_Observation", + EdgeLabel: "basedOn_Observation", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Observation/*", }, }, - "Task|statusReason_reference_DiagnosticReport|DiagnosticReport": { + "Task|basedOn_DiagnosticReport|DiagnosticReport": { FromType: "Task", - EdgeLabel: "statusReason_reference_DiagnosticReport", + EdgeLabel: "basedOn_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "DiagnosticReport|statusReason_reference_DiagnosticReport|Task": { + "DiagnosticReport|basedOn_DiagnosticReport|Task": { FromType: "DiagnosticReport", - EdgeLabel: "statusReason_reference_DiagnosticReport", + EdgeLabel: "basedOn_DiagnosticReport", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "Task|statusReason_reference_Condition|Condition": { + "Task|basedOn_Condition|Condition": { FromType: "Task", - EdgeLabel: "statusReason_reference_Condition", + EdgeLabel: "basedOn_Condition", ToType: "Condition", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Condition/*", }, }, - "Condition|statusReason_reference_Condition|Task": { + "Condition|basedOn_Condition|Task": { FromType: "Condition", - EdgeLabel: "statusReason_reference_Condition", + EdgeLabel: "basedOn_Condition", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Condition/*", }, }, - "Task|statusReason_reference_Medication|Medication": { + "Task|basedOn_Medication|Medication": { FromType: "Task", - EdgeLabel: "statusReason_reference_Medication", + EdgeLabel: "basedOn_Medication", ToType: "Medication", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Medication/*", }, }, - "Medication|statusReason_reference_Medication|Task": { + "Medication|basedOn_Medication|Task": { FromType: "Medication", - EdgeLabel: "statusReason_reference_Medication", + EdgeLabel: "basedOn_Medication", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Medication/*", }, }, - "Task|statusReason_reference_MedicationAdministration|MedicationAdministration": { + "Task|basedOn_MedicationAdministration|MedicationAdministration": { FromType: "Task", - EdgeLabel: "statusReason_reference_MedicationAdministration", + EdgeLabel: "basedOn_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "MedicationAdministration|statusReason_reference_MedicationAdministration|Task": { + "MedicationAdministration|basedOn_MedicationAdministration|Task": { FromType: "MedicationAdministration", - EdgeLabel: "statusReason_reference_MedicationAdministration", + EdgeLabel: "basedOn_MedicationAdministration", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "Task|statusReason_reference_MedicationStatement|MedicationStatement": { + "Task|basedOn_MedicationStatement|MedicationStatement": { FromType: "Task", - EdgeLabel: "statusReason_reference_MedicationStatement", + EdgeLabel: "basedOn_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "MedicationStatement|statusReason_reference_MedicationStatement|Task": { + "MedicationStatement|basedOn_MedicationStatement|Task": { FromType: "MedicationStatement", - EdgeLabel: "statusReason_reference_MedicationStatement", + EdgeLabel: "basedOn_MedicationStatement", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "Task|statusReason_reference_MedicationRequest|MedicationRequest": { + "Task|basedOn_MedicationRequest|MedicationRequest": { FromType: "Task", - EdgeLabel: "statusReason_reference_MedicationRequest", + EdgeLabel: "basedOn_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "MedicationRequest|statusReason_reference_MedicationRequest|Task": { + "MedicationRequest|basedOn_MedicationRequest|Task": { FromType: "MedicationRequest", - EdgeLabel: "statusReason_reference_MedicationRequest", + EdgeLabel: "basedOn_MedicationRequest", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "Task|statusReason_reference_Procedure|Procedure": { + "Task|basedOn_Procedure|Procedure": { FromType: "Task", - EdgeLabel: "statusReason_reference_Procedure", + EdgeLabel: "basedOn_Procedure", ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Procedure/*", }, }, - "Procedure|statusReason_reference_Procedure|Task": { + "Procedure|basedOn_Procedure|Task": { FromType: "Procedure", - EdgeLabel: "statusReason_reference_Procedure", + EdgeLabel: "basedOn_Procedure", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Procedure/*", }, }, - "Task|statusReason_reference_DocumentReference|DocumentReference": { + "Task|basedOn_DocumentReference|DocumentReference": { FromType: "Task", - EdgeLabel: "statusReason_reference_DocumentReference", + EdgeLabel: "basedOn_DocumentReference", ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "DocumentReference/*", }, }, - "DocumentReference|statusReason_reference_DocumentReference|Task": { + "DocumentReference|basedOn_DocumentReference|Task": { FromType: "DocumentReference", - EdgeLabel: "statusReason_reference_DocumentReference", + EdgeLabel: "basedOn_DocumentReference", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "DocumentReference/*", }, }, - "Task|statusReason_reference_Task|Task": { + "Task|basedOn_Task|Task": { FromType: "Task", - EdgeLabel: "statusReason_reference_Task", + EdgeLabel: "basedOn_Task", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "Task/*", }, }, - "Task|statusReason_reference_ImagingStudy|ImagingStudy": { + "Task|basedOn_ImagingStudy|ImagingStudy": { FromType: "Task", - EdgeLabel: "statusReason_reference_ImagingStudy", + EdgeLabel: "basedOn_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "ImagingStudy/*", }, }, - "ImagingStudy|statusReason_reference_ImagingStudy|Task": { + "ImagingStudy|basedOn_ImagingStudy|Task": { FromType: "ImagingStudy", - EdgeLabel: "statusReason_reference_ImagingStudy", + EdgeLabel: "basedOn_ImagingStudy", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "ImagingStudy/*", }, }, - "Task|statusReason_reference_FamilyMemberHistory|FamilyMemberHistory": { + "Task|basedOn_FamilyMemberHistory|FamilyMemberHistory": { FromType: "Task", - EdgeLabel: "statusReason_reference_FamilyMemberHistory", + EdgeLabel: "basedOn_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|statusReason_reference_FamilyMemberHistory|Task": { + "FamilyMemberHistory|basedOn_FamilyMemberHistory|Task": { FromType: "FamilyMemberHistory", - EdgeLabel: "statusReason_reference_FamilyMemberHistory", + EdgeLabel: "basedOn_FamilyMemberHistory", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "FamilyMemberHistory/*", }, }, - "Task|statusReason_reference_BodyStructure|BodyStructure": { + "Task|basedOn_BodyStructure|BodyStructure": { FromType: "Task", - EdgeLabel: "statusReason_reference_BodyStructure", + EdgeLabel: "basedOn_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "BodyStructure/*", }, }, - "BodyStructure|statusReason_reference_BodyStructure|Task": { + "BodyStructure|basedOn_BodyStructure|Task": { FromType: "BodyStructure", - EdgeLabel: "statusReason_reference_BodyStructure", + EdgeLabel: "basedOn_BodyStructure", ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "codeable_reference", + "basedOn_task", }, RegexMatch: []string{ "BodyStructure/*", }, }, - "TaskInput|valueReference_Organization|Organization": { - FromType: "TaskInput", - EdgeLabel: "valueReference_Organization", + "Task|focus_Organization|Organization": { + FromType: "Task", + EdgeLabel: "focus_Organization", ToType: "Organization", Direction: []string{ "outbound", @@ -61702,16 +42281,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Organization/*", }, }, - "Organization|valueReference_Organization|TaskInput": { + "Organization|focus_Organization|Task": { FromType: "Organization", - EdgeLabel: "valueReference_Organization", - ToType: "TaskInput", + EdgeLabel: "focus_Organization", + ToType: "Task", Direction: []string{ "outbound", }, @@ -61719,15 +42298,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Organization/*", }, }, - "TaskInput|valueReference_Group|Group": { - FromType: "TaskInput", - EdgeLabel: "valueReference_Group", + "Task|focus_Group|Group": { + FromType: "Task", + EdgeLabel: "focus_Group", ToType: "Group", Direction: []string{ "outbound", @@ -61736,16 +42315,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Group/*", }, }, - "Group|valueReference_Group|TaskInput": { + "Group|focus_Group|Task": { FromType: "Group", - EdgeLabel: "valueReference_Group", - ToType: "TaskInput", + EdgeLabel: "focus_Group", + ToType: "Task", Direction: []string{ "outbound", }, @@ -61753,15 +42332,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Group/*", }, }, - "TaskInput|valueReference_Practitioner|Practitioner": { - FromType: "TaskInput", - EdgeLabel: "valueReference_Practitioner", + "Task|focus_Practitioner|Practitioner": { + FromType: "Task", + EdgeLabel: "focus_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", @@ -61770,16 +42349,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Practitioner|valueReference_Practitioner|TaskInput": { + "Practitioner|focus_Practitioner|Task": { FromType: "Practitioner", - EdgeLabel: "valueReference_Practitioner", - ToType: "TaskInput", + EdgeLabel: "focus_Practitioner", + ToType: "Task", Direction: []string{ "outbound", }, @@ -61787,15 +42366,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Practitioner/*", }, }, - "TaskInput|valueReference_PractitionerRole|PractitionerRole": { - FromType: "TaskInput", - EdgeLabel: "valueReference_PractitionerRole", + "Task|focus_PractitionerRole|PractitionerRole": { + FromType: "Task", + EdgeLabel: "focus_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", @@ -61804,16 +42383,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "PractitionerRole|valueReference_PractitionerRole|TaskInput": { + "PractitionerRole|focus_PractitionerRole|Task": { FromType: "PractitionerRole", - EdgeLabel: "valueReference_PractitionerRole", - ToType: "TaskInput", + EdgeLabel: "focus_PractitionerRole", + ToType: "Task", Direction: []string{ "outbound", }, @@ -61821,15 +42400,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "TaskInput|valueReference_ResearchStudy|ResearchStudy": { - FromType: "TaskInput", - EdgeLabel: "valueReference_ResearchStudy", + "Task|focus_ResearchStudy|ResearchStudy": { + FromType: "Task", + EdgeLabel: "focus_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -61838,16 +42417,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "ResearchStudy|valueReference_ResearchStudy|TaskInput": { + "ResearchStudy|focus_ResearchStudy|Task": { FromType: "ResearchStudy", - EdgeLabel: "valueReference_ResearchStudy", - ToType: "TaskInput", + EdgeLabel: "focus_ResearchStudy", + ToType: "Task", Direction: []string{ "outbound", }, @@ -61855,15 +42434,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "TaskInput|valueReference_Patient|Patient": { - FromType: "TaskInput", - EdgeLabel: "valueReference_Patient", + "Task|focus_Patient|Patient": { + FromType: "Task", + EdgeLabel: "focus_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -61872,16 +42451,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|valueReference_Patient|TaskInput": { + "Patient|focus_Patient|Task": { FromType: "Patient", - EdgeLabel: "valueReference_Patient", - ToType: "TaskInput", + EdgeLabel: "focus_Patient", + ToType: "Task", Direction: []string{ "outbound", }, @@ -61889,15 +42468,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Patient/*", }, }, - "TaskInput|valueReference_ResearchSubject|ResearchSubject": { - FromType: "TaskInput", - EdgeLabel: "valueReference_ResearchSubject", + "Task|focus_ResearchSubject|ResearchSubject": { + FromType: "Task", + EdgeLabel: "focus_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -61906,16 +42485,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "ResearchSubject|valueReference_ResearchSubject|TaskInput": { + "ResearchSubject|focus_ResearchSubject|Task": { FromType: "ResearchSubject", - EdgeLabel: "valueReference_ResearchSubject", - ToType: "TaskInput", + EdgeLabel: "focus_ResearchSubject", + ToType: "Task", Direction: []string{ "outbound", }, @@ -61923,15 +42502,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "TaskInput|valueReference_Substance|Substance": { - FromType: "TaskInput", - EdgeLabel: "valueReference_Substance", + "Task|focus_Substance|Substance": { + FromType: "Task", + EdgeLabel: "focus_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -61940,16 +42519,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Substance/*", }, }, - "Substance|valueReference_Substance|TaskInput": { + "Substance|focus_Substance|Task": { FromType: "Substance", - EdgeLabel: "valueReference_Substance", - ToType: "TaskInput", + EdgeLabel: "focus_Substance", + ToType: "Task", Direction: []string{ "outbound", }, @@ -61957,15 +42536,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Substance/*", }, }, - "TaskInput|valueReference_SubstanceDefinition|SubstanceDefinition": { - FromType: "TaskInput", - EdgeLabel: "valueReference_SubstanceDefinition", + "Task|focus_SubstanceDefinition|SubstanceDefinition": { + FromType: "Task", + EdgeLabel: "focus_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -61974,16 +42553,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|valueReference_SubstanceDefinition|TaskInput": { + "SubstanceDefinition|focus_SubstanceDefinition|Task": { FromType: "SubstanceDefinition", - EdgeLabel: "valueReference_SubstanceDefinition", - ToType: "TaskInput", + EdgeLabel: "focus_SubstanceDefinition", + ToType: "Task", Direction: []string{ "outbound", }, @@ -61991,15 +42570,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "TaskInput|valueReference_Specimen|Specimen": { - FromType: "TaskInput", - EdgeLabel: "valueReference_Specimen", + "Task|focus_Specimen|Specimen": { + FromType: "Task", + EdgeLabel: "focus_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -62008,16 +42587,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Specimen/*", }, }, - "Specimen|valueReference_Specimen|TaskInput": { + "Specimen|focus_Specimen|Task": { FromType: "Specimen", - EdgeLabel: "valueReference_Specimen", - ToType: "TaskInput", + EdgeLabel: "focus_Specimen", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62025,15 +42604,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Specimen/*", }, }, - "TaskInput|valueReference_Observation|Observation": { - FromType: "TaskInput", - EdgeLabel: "valueReference_Observation", + "Task|focus_Observation|Observation": { + FromType: "Task", + EdgeLabel: "focus_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -62042,16 +42621,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Observation/*", }, }, - "Observation|valueReference_Observation|TaskInput": { + "Observation|focus_Observation|Task": { FromType: "Observation", - EdgeLabel: "valueReference_Observation", - ToType: "TaskInput", + EdgeLabel: "focus_Observation", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62059,15 +42638,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Observation/*", }, }, - "TaskInput|valueReference_DiagnosticReport|DiagnosticReport": { - FromType: "TaskInput", - EdgeLabel: "valueReference_DiagnosticReport", + "Task|focus_DiagnosticReport|DiagnosticReport": { + FromType: "Task", + EdgeLabel: "focus_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -62076,16 +42655,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "DiagnosticReport|valueReference_DiagnosticReport|TaskInput": { + "DiagnosticReport|focus_DiagnosticReport|Task": { FromType: "DiagnosticReport", - EdgeLabel: "valueReference_DiagnosticReport", - ToType: "TaskInput", + EdgeLabel: "focus_DiagnosticReport", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62093,15 +42672,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "TaskInput|valueReference_Condition|Condition": { - FromType: "TaskInput", - EdgeLabel: "valueReference_Condition", + "Task|focus_Condition|Condition": { + FromType: "Task", + EdgeLabel: "focus_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -62110,16 +42689,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Condition/*", }, }, - "Condition|valueReference_Condition|TaskInput": { + "Condition|focus_Condition|Task": { FromType: "Condition", - EdgeLabel: "valueReference_Condition", - ToType: "TaskInput", + EdgeLabel: "focus_Condition", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62127,15 +42706,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Condition/*", }, }, - "TaskInput|valueReference_Medication|Medication": { - FromType: "TaskInput", - EdgeLabel: "valueReference_Medication", + "Task|focus_Medication|Medication": { + FromType: "Task", + EdgeLabel: "focus_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -62144,16 +42723,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Medication/*", }, }, - "Medication|valueReference_Medication|TaskInput": { + "Medication|focus_Medication|Task": { FromType: "Medication", - EdgeLabel: "valueReference_Medication", - ToType: "TaskInput", + EdgeLabel: "focus_Medication", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62161,15 +42740,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Medication/*", }, }, - "TaskInput|valueReference_MedicationAdministration|MedicationAdministration": { - FromType: "TaskInput", - EdgeLabel: "valueReference_MedicationAdministration", + "Task|focus_MedicationAdministration|MedicationAdministration": { + FromType: "Task", + EdgeLabel: "focus_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -62178,16 +42757,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "MedicationAdministration|valueReference_MedicationAdministration|TaskInput": { + "MedicationAdministration|focus_MedicationAdministration|Task": { FromType: "MedicationAdministration", - EdgeLabel: "valueReference_MedicationAdministration", - ToType: "TaskInput", + EdgeLabel: "focus_MedicationAdministration", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62195,15 +42774,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "TaskInput|valueReference_MedicationStatement|MedicationStatement": { - FromType: "TaskInput", - EdgeLabel: "valueReference_MedicationStatement", + "Task|focus_MedicationStatement|MedicationStatement": { + FromType: "Task", + EdgeLabel: "focus_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -62212,16 +42791,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "MedicationStatement|valueReference_MedicationStatement|TaskInput": { + "MedicationStatement|focus_MedicationStatement|Task": { FromType: "MedicationStatement", - EdgeLabel: "valueReference_MedicationStatement", - ToType: "TaskInput", + EdgeLabel: "focus_MedicationStatement", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62229,15 +42808,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "TaskInput|valueReference_MedicationRequest|MedicationRequest": { - FromType: "TaskInput", - EdgeLabel: "valueReference_MedicationRequest", + "Task|focus_MedicationRequest|MedicationRequest": { + FromType: "Task", + EdgeLabel: "focus_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -62246,16 +42825,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "MedicationRequest|valueReference_MedicationRequest|TaskInput": { + "MedicationRequest|focus_MedicationRequest|Task": { FromType: "MedicationRequest", - EdgeLabel: "valueReference_MedicationRequest", - ToType: "TaskInput", + EdgeLabel: "focus_MedicationRequest", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62263,15 +42842,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "TaskInput|valueReference_Procedure|Procedure": { - FromType: "TaskInput", - EdgeLabel: "valueReference_Procedure", + "Task|focus_Procedure|Procedure": { + FromType: "Task", + EdgeLabel: "focus_Procedure", ToType: "Procedure", Direction: []string{ "outbound", @@ -62280,16 +42859,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Procedure/*", }, }, - "Procedure|valueReference_Procedure|TaskInput": { + "Procedure|focus_Procedure|Task": { FromType: "Procedure", - EdgeLabel: "valueReference_Procedure", - ToType: "TaskInput", + EdgeLabel: "focus_Procedure", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62297,15 +42876,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Procedure/*", }, }, - "TaskInput|valueReference_DocumentReference|DocumentReference": { - FromType: "TaskInput", - EdgeLabel: "valueReference_DocumentReference", + "Task|focus_DocumentReference|DocumentReference": { + FromType: "Task", + EdgeLabel: "focus_DocumentReference", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -62314,16 +42893,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "DocumentReference/*", }, }, - "DocumentReference|valueReference_DocumentReference|TaskInput": { + "DocumentReference|focus_DocumentReference|Task": { FromType: "DocumentReference", - EdgeLabel: "valueReference_DocumentReference", - ToType: "TaskInput", + EdgeLabel: "focus_DocumentReference", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62331,15 +42910,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "DocumentReference/*", }, }, - "TaskInput|valueReference_Task|Task": { - FromType: "TaskInput", - EdgeLabel: "valueReference_Task", + "Task|focus_Task|Task": { + FromType: "Task", + EdgeLabel: "focus_Task", ToType: "Task", Direction: []string{ "outbound", @@ -62348,32 +42927,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "Task/*", }, }, - "Task|valueReference_Task|TaskInput": { + "Task|focus_ImagingStudy|ImagingStudy": { FromType: "Task", - EdgeLabel: "valueReference_Task", - ToType: "TaskInput", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "task_input", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "TaskInput|valueReference_ImagingStudy|ImagingStudy": { - FromType: "TaskInput", - EdgeLabel: "valueReference_ImagingStudy", + EdgeLabel: "focus_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", @@ -62382,16 +42944,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "ImagingStudy/*", }, }, - "ImagingStudy|valueReference_ImagingStudy|TaskInput": { + "ImagingStudy|focus_ImagingStudy|Task": { FromType: "ImagingStudy", - EdgeLabel: "valueReference_ImagingStudy", - ToType: "TaskInput", + EdgeLabel: "focus_ImagingStudy", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62399,15 +42961,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "ImagingStudy/*", }, }, - "TaskInput|valueReference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "TaskInput", - EdgeLabel: "valueReference_FamilyMemberHistory", + "Task|focus_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "Task", + EdgeLabel: "focus_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -62416,16 +42978,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|valueReference_FamilyMemberHistory|TaskInput": { + "FamilyMemberHistory|focus_FamilyMemberHistory|Task": { FromType: "FamilyMemberHistory", - EdgeLabel: "valueReference_FamilyMemberHistory", - ToType: "TaskInput", + EdgeLabel: "focus_FamilyMemberHistory", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62433,15 +42995,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "FamilyMemberHistory/*", }, }, - "TaskInput|valueReference_BodyStructure|BodyStructure": { - FromType: "TaskInput", - EdgeLabel: "valueReference_BodyStructure", + "Task|focus_BodyStructure|BodyStructure": { + FromType: "Task", + EdgeLabel: "focus_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", @@ -62450,16 +43012,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "BodyStructure/*", }, }, - "BodyStructure|valueReference_BodyStructure|TaskInput": { + "BodyStructure|focus_BodyStructure|Task": { FromType: "BodyStructure", - EdgeLabel: "valueReference_BodyStructure", - ToType: "TaskInput", + EdgeLabel: "focus_BodyStructure", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62467,151 +43029,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_input", + "focus_task", }, RegexMatch: []string{ "BodyStructure/*", }, }, - "TaskInput|valueAnnotation_authorReference_Practitioner|Practitioner": { - FromType: "TaskInput", - EdgeLabel: "valueAnnotation_authorReference_Practitioner", - ToType: "Practitioner", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "Practitioner|valueAnnotation_authorReference_Practitioner|TaskInput": { - FromType: "Practitioner", - EdgeLabel: "valueAnnotation_authorReference_Practitioner", - ToType: "TaskInput", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Practitioner/*", - }, - }, - "TaskInput|valueAnnotation_authorReference_PractitionerRole|PractitionerRole": { - FromType: "TaskInput", - EdgeLabel: "valueAnnotation_authorReference_PractitionerRole", - ToType: "PractitionerRole", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "PractitionerRole|valueAnnotation_authorReference_PractitionerRole|TaskInput": { - FromType: "PractitionerRole", - EdgeLabel: "valueAnnotation_authorReference_PractitionerRole", - ToType: "TaskInput", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "PractitionerRole/*", - }, - }, - "TaskInput|valueAnnotation_authorReference_Patient|Patient": { - FromType: "TaskInput", - EdgeLabel: "valueAnnotation_authorReference_Patient", - ToType: "Patient", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "Patient|valueAnnotation_authorReference_Patient|TaskInput": { - FromType: "Patient", - EdgeLabel: "valueAnnotation_authorReference_Patient", - ToType: "TaskInput", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Patient/*", - }, - }, - "TaskInput|valueAnnotation_authorReference_Organization|Organization": { - FromType: "TaskInput", - EdgeLabel: "valueAnnotation_authorReference_Organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|valueAnnotation_authorReference_Organization|TaskInput": { - FromType: "Organization", - EdgeLabel: "valueAnnotation_authorReference_Organization", - ToType: "TaskInput", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "annotation", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "TaskInput|valueCodeableReference_reference_Organization|Organization": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_Organization", + "Task|for_fhir_Organization|Organization": { + FromType: "Task", + EdgeLabel: "for_fhir_Organization", ToType: "Organization", Direction: []string{ "outbound", @@ -62620,16 +43046,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Organization/*", }, }, - "Organization|valueCodeableReference_reference_Organization|TaskInput": { + "Organization|for_fhir_Organization|Task": { FromType: "Organization", - EdgeLabel: "valueCodeableReference_reference_Organization", - ToType: "TaskInput", + EdgeLabel: "for_fhir_Organization", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62637,15 +43063,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Organization/*", }, }, - "TaskInput|valueCodeableReference_reference_Group|Group": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_Group", + "Task|for_fhir_Group|Group": { + FromType: "Task", + EdgeLabel: "for_fhir_Group", ToType: "Group", Direction: []string{ "outbound", @@ -62654,16 +43080,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Group/*", }, }, - "Group|valueCodeableReference_reference_Group|TaskInput": { + "Group|for_fhir_Group|Task": { FromType: "Group", - EdgeLabel: "valueCodeableReference_reference_Group", - ToType: "TaskInput", + EdgeLabel: "for_fhir_Group", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62671,15 +43097,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Group/*", }, }, - "TaskInput|valueCodeableReference_reference_Practitioner|Practitioner": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_Practitioner", + "Task|for_fhir_Practitioner|Practitioner": { + FromType: "Task", + EdgeLabel: "for_fhir_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", @@ -62688,16 +43114,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Practitioner|valueCodeableReference_reference_Practitioner|TaskInput": { + "Practitioner|for_fhir_Practitioner|Task": { FromType: "Practitioner", - EdgeLabel: "valueCodeableReference_reference_Practitioner", - ToType: "TaskInput", + EdgeLabel: "for_fhir_Practitioner", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62705,15 +43131,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Practitioner/*", }, }, - "TaskInput|valueCodeableReference_reference_PractitionerRole|PractitionerRole": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_PractitionerRole", + "Task|for_fhir_PractitionerRole|PractitionerRole": { + FromType: "Task", + EdgeLabel: "for_fhir_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", @@ -62722,16 +43148,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "PractitionerRole|valueCodeableReference_reference_PractitionerRole|TaskInput": { + "PractitionerRole|for_fhir_PractitionerRole|Task": { FromType: "PractitionerRole", - EdgeLabel: "valueCodeableReference_reference_PractitionerRole", - ToType: "TaskInput", + EdgeLabel: "for_fhir_PractitionerRole", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62739,15 +43165,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "TaskInput|valueCodeableReference_reference_ResearchStudy|ResearchStudy": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_ResearchStudy", + "Task|for_fhir_ResearchStudy|ResearchStudy": { + FromType: "Task", + EdgeLabel: "for_fhir_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -62756,16 +43182,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "ResearchStudy|valueCodeableReference_reference_ResearchStudy|TaskInput": { + "ResearchStudy|for_fhir_ResearchStudy|Task": { FromType: "ResearchStudy", - EdgeLabel: "valueCodeableReference_reference_ResearchStudy", - ToType: "TaskInput", + EdgeLabel: "for_fhir_ResearchStudy", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62773,15 +43199,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "TaskInput|valueCodeableReference_reference_Patient|Patient": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_Patient", + "Task|for_fhir_Patient|Patient": { + FromType: "Task", + EdgeLabel: "for_fhir_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -62790,16 +43216,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|valueCodeableReference_reference_Patient|TaskInput": { + "Patient|for_fhir_Patient|Task": { FromType: "Patient", - EdgeLabel: "valueCodeableReference_reference_Patient", - ToType: "TaskInput", + EdgeLabel: "for_fhir_Patient", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62807,15 +43233,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Patient/*", }, }, - "TaskInput|valueCodeableReference_reference_ResearchSubject|ResearchSubject": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_ResearchSubject", + "Task|for_fhir_ResearchSubject|ResearchSubject": { + FromType: "Task", + EdgeLabel: "for_fhir_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -62824,16 +43250,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "ResearchSubject|valueCodeableReference_reference_ResearchSubject|TaskInput": { + "ResearchSubject|for_fhir_ResearchSubject|Task": { FromType: "ResearchSubject", - EdgeLabel: "valueCodeableReference_reference_ResearchSubject", - ToType: "TaskInput", + EdgeLabel: "for_fhir_ResearchSubject", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62841,15 +43267,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "TaskInput|valueCodeableReference_reference_Substance|Substance": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_Substance", + "Task|for_fhir_Substance|Substance": { + FromType: "Task", + EdgeLabel: "for_fhir_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -62858,16 +43284,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Substance/*", }, }, - "Substance|valueCodeableReference_reference_Substance|TaskInput": { + "Substance|for_fhir_Substance|Task": { FromType: "Substance", - EdgeLabel: "valueCodeableReference_reference_Substance", - ToType: "TaskInput", + EdgeLabel: "for_fhir_Substance", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62875,15 +43301,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Substance/*", }, }, - "TaskInput|valueCodeableReference_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_SubstanceDefinition", + "Task|for_fhir_SubstanceDefinition|SubstanceDefinition": { + FromType: "Task", + EdgeLabel: "for_fhir_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -62892,16 +43318,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|valueCodeableReference_reference_SubstanceDefinition|TaskInput": { + "SubstanceDefinition|for_fhir_SubstanceDefinition|Task": { FromType: "SubstanceDefinition", - EdgeLabel: "valueCodeableReference_reference_SubstanceDefinition", - ToType: "TaskInput", + EdgeLabel: "for_fhir_SubstanceDefinition", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62909,15 +43335,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "TaskInput|valueCodeableReference_reference_Specimen|Specimen": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_Specimen", + "Task|for_fhir_Specimen|Specimen": { + FromType: "Task", + EdgeLabel: "for_fhir_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -62926,16 +43352,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Specimen/*", }, }, - "Specimen|valueCodeableReference_reference_Specimen|TaskInput": { + "Specimen|for_fhir_Specimen|Task": { FromType: "Specimen", - EdgeLabel: "valueCodeableReference_reference_Specimen", - ToType: "TaskInput", + EdgeLabel: "for_fhir_Specimen", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62943,15 +43369,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Specimen/*", }, }, - "TaskInput|valueCodeableReference_reference_Observation|Observation": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_Observation", + "Task|for_fhir_Observation|Observation": { + FromType: "Task", + EdgeLabel: "for_fhir_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -62960,16 +43386,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Observation/*", }, }, - "Observation|valueCodeableReference_reference_Observation|TaskInput": { + "Observation|for_fhir_Observation|Task": { FromType: "Observation", - EdgeLabel: "valueCodeableReference_reference_Observation", - ToType: "TaskInput", + EdgeLabel: "for_fhir_Observation", + ToType: "Task", Direction: []string{ "outbound", }, @@ -62977,15 +43403,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Observation/*", }, }, - "TaskInput|valueCodeableReference_reference_DiagnosticReport|DiagnosticReport": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_DiagnosticReport", + "Task|for_fhir_DiagnosticReport|DiagnosticReport": { + FromType: "Task", + EdgeLabel: "for_fhir_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -62994,16 +43420,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "DiagnosticReport|valueCodeableReference_reference_DiagnosticReport|TaskInput": { + "DiagnosticReport|for_fhir_DiagnosticReport|Task": { FromType: "DiagnosticReport", - EdgeLabel: "valueCodeableReference_reference_DiagnosticReport", - ToType: "TaskInput", + EdgeLabel: "for_fhir_DiagnosticReport", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63011,15 +43437,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "TaskInput|valueCodeableReference_reference_Condition|Condition": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_Condition", + "Task|for_fhir_Condition|Condition": { + FromType: "Task", + EdgeLabel: "for_fhir_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -63028,16 +43454,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Condition/*", }, }, - "Condition|valueCodeableReference_reference_Condition|TaskInput": { + "Condition|for_fhir_Condition|Task": { FromType: "Condition", - EdgeLabel: "valueCodeableReference_reference_Condition", - ToType: "TaskInput", + EdgeLabel: "for_fhir_Condition", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63045,15 +43471,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Condition/*", }, }, - "TaskInput|valueCodeableReference_reference_Medication|Medication": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_Medication", + "Task|for_fhir_Medication|Medication": { + FromType: "Task", + EdgeLabel: "for_fhir_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -63062,16 +43488,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Medication/*", }, }, - "Medication|valueCodeableReference_reference_Medication|TaskInput": { + "Medication|for_fhir_Medication|Task": { FromType: "Medication", - EdgeLabel: "valueCodeableReference_reference_Medication", - ToType: "TaskInput", + EdgeLabel: "for_fhir_Medication", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63079,15 +43505,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Medication/*", }, }, - "TaskInput|valueCodeableReference_reference_MedicationAdministration|MedicationAdministration": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_MedicationAdministration", + "Task|for_fhir_MedicationAdministration|MedicationAdministration": { + FromType: "Task", + EdgeLabel: "for_fhir_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -63096,16 +43522,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "MedicationAdministration|valueCodeableReference_reference_MedicationAdministration|TaskInput": { + "MedicationAdministration|for_fhir_MedicationAdministration|Task": { FromType: "MedicationAdministration", - EdgeLabel: "valueCodeableReference_reference_MedicationAdministration", - ToType: "TaskInput", + EdgeLabel: "for_fhir_MedicationAdministration", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63113,15 +43539,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "TaskInput|valueCodeableReference_reference_MedicationStatement|MedicationStatement": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_MedicationStatement", + "Task|for_fhir_MedicationStatement|MedicationStatement": { + FromType: "Task", + EdgeLabel: "for_fhir_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -63130,16 +43556,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "MedicationStatement|valueCodeableReference_reference_MedicationStatement|TaskInput": { + "MedicationStatement|for_fhir_MedicationStatement|Task": { FromType: "MedicationStatement", - EdgeLabel: "valueCodeableReference_reference_MedicationStatement", - ToType: "TaskInput", + EdgeLabel: "for_fhir_MedicationStatement", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63147,15 +43573,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "TaskInput|valueCodeableReference_reference_MedicationRequest|MedicationRequest": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_MedicationRequest", + "Task|for_fhir_MedicationRequest|MedicationRequest": { + FromType: "Task", + EdgeLabel: "for_fhir_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -63164,16 +43590,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "MedicationRequest|valueCodeableReference_reference_MedicationRequest|TaskInput": { + "MedicationRequest|for_fhir_MedicationRequest|Task": { FromType: "MedicationRequest", - EdgeLabel: "valueCodeableReference_reference_MedicationRequest", - ToType: "TaskInput", + EdgeLabel: "for_fhir_MedicationRequest", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63181,15 +43607,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "TaskInput|valueCodeableReference_reference_Procedure|Procedure": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_Procedure", + "Task|for_fhir_Procedure|Procedure": { + FromType: "Task", + EdgeLabel: "for_fhir_Procedure", ToType: "Procedure", Direction: []string{ "outbound", @@ -63198,16 +43624,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Procedure/*", }, }, - "Procedure|valueCodeableReference_reference_Procedure|TaskInput": { + "Procedure|for_fhir_Procedure|Task": { FromType: "Procedure", - EdgeLabel: "valueCodeableReference_reference_Procedure", - ToType: "TaskInput", + EdgeLabel: "for_fhir_Procedure", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63215,15 +43641,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Procedure/*", }, }, - "TaskInput|valueCodeableReference_reference_DocumentReference|DocumentReference": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_DocumentReference", + "Task|for_fhir_DocumentReference|DocumentReference": { + FromType: "Task", + EdgeLabel: "for_fhir_DocumentReference", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -63232,16 +43658,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "DocumentReference/*", }, }, - "DocumentReference|valueCodeableReference_reference_DocumentReference|TaskInput": { + "DocumentReference|for_fhir_DocumentReference|Task": { FromType: "DocumentReference", - EdgeLabel: "valueCodeableReference_reference_DocumentReference", - ToType: "TaskInput", + EdgeLabel: "for_fhir_DocumentReference", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63249,15 +43675,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "DocumentReference/*", }, }, - "TaskInput|valueCodeableReference_reference_Task|Task": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_Task", + "Task|for_fhir_Task|Task": { + FromType: "Task", + EdgeLabel: "for_fhir_Task", ToType: "Task", Direction: []string{ "outbound", @@ -63266,32 +43692,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "Task/*", }, }, - "Task|valueCodeableReference_reference_Task|TaskInput": { + "Task|for_fhir_ImagingStudy|ImagingStudy": { FromType: "Task", - EdgeLabel: "valueCodeableReference_reference_Task", - ToType: "TaskInput", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "TaskInput|valueCodeableReference_reference_ImagingStudy|ImagingStudy": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_ImagingStudy", + EdgeLabel: "for_fhir_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", @@ -63300,16 +43709,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "ImagingStudy/*", }, }, - "ImagingStudy|valueCodeableReference_reference_ImagingStudy|TaskInput": { + "ImagingStudy|for_fhir_ImagingStudy|Task": { FromType: "ImagingStudy", - EdgeLabel: "valueCodeableReference_reference_ImagingStudy", - ToType: "TaskInput", + EdgeLabel: "for_fhir_ImagingStudy", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63317,15 +43726,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "ImagingStudy/*", }, }, - "TaskInput|valueCodeableReference_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_FamilyMemberHistory", + "Task|for_fhir_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "Task", + EdgeLabel: "for_fhir_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -63334,16 +43743,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|valueCodeableReference_reference_FamilyMemberHistory|TaskInput": { + "FamilyMemberHistory|for_fhir_FamilyMemberHistory|Task": { FromType: "FamilyMemberHistory", - EdgeLabel: "valueCodeableReference_reference_FamilyMemberHistory", - ToType: "TaskInput", + EdgeLabel: "for_fhir_FamilyMemberHistory", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63351,15 +43760,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "FamilyMemberHistory/*", }, }, - "TaskInput|valueCodeableReference_reference_BodyStructure|BodyStructure": { - FromType: "TaskInput", - EdgeLabel: "valueCodeableReference_reference_BodyStructure", + "Task|for_fhir_BodyStructure|BodyStructure": { + FromType: "Task", + EdgeLabel: "for_fhir_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", @@ -63368,16 +43777,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "BodyStructure/*", }, }, - "BodyStructure|valueCodeableReference_reference_BodyStructure|TaskInput": { + "BodyStructure|for_fhir_BodyStructure|Task": { FromType: "BodyStructure", - EdgeLabel: "valueCodeableReference_reference_BodyStructure", - ToType: "TaskInput", + EdgeLabel: "for_fhir_BodyStructure", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63385,16 +43794,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "codeable_reference", + "for_task", }, RegexMatch: []string{ "BodyStructure/*", }, }, - "TaskInput|valueDataRequirement_subjectReference|Group": { - FromType: "TaskInput", - EdgeLabel: "valueDataRequirement_subjectReference", - ToType: "Group", + "Task|owner_Practitioner|Practitioner": { + FromType: "Task", + EdgeLabel: "owner_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -63402,16 +43811,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "data_requirement", + "owner_task", }, RegexMatch: []string{ - "Group/*", + "Practitioner/*", }, }, - "Group|valueDataRequirement_subjectReference|TaskInput": { - FromType: "Group", - EdgeLabel: "valueDataRequirement_subjectReference", - ToType: "TaskInput", + "Practitioner|owner_Practitioner|Task": { + FromType: "Practitioner", + EdgeLabel: "owner_Practitioner", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63419,16 +43828,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "data_requirement", + "owner_task", }, RegexMatch: []string{ - "Group/*", + "Practitioner/*", }, }, - "TaskInput|valueExtendedContactDetail_organization|Organization": { - FromType: "TaskInput", - EdgeLabel: "valueExtendedContactDetail_organization", - ToType: "Organization", + "Task|owner_PractitionerRole|PractitionerRole": { + FromType: "Task", + EdgeLabel: "owner_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -63436,16 +43845,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extended_contact_detail", + "owner_task", }, RegexMatch: []string{ - "Organization/*", + "PractitionerRole/*", }, }, - "Organization|valueExtendedContactDetail_organization|TaskInput": { - FromType: "Organization", - EdgeLabel: "valueExtendedContactDetail_organization", - ToType: "TaskInput", + "PractitionerRole|owner_PractitionerRole|Task": { + FromType: "PractitionerRole", + EdgeLabel: "owner_PractitionerRole", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63453,15 +43862,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "extended_contact_detail", + "owner_task", }, RegexMatch: []string{ - "Organization/*", + "PractitionerRole/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_Organization|Organization": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Organization", + "Task|owner_Organization|Organization": { + FromType: "Task", + EdgeLabel: "owner_Organization", ToType: "Organization", Direction: []string{ "outbound", @@ -63470,16 +43879,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "owner_task", }, RegexMatch: []string{ "Organization/*", }, }, - "Organization|valueRelatedArtifact_resourceReference_Organization|TaskInput": { + "Organization|owner_Organization|Task": { FromType: "Organization", - EdgeLabel: "valueRelatedArtifact_resourceReference_Organization", - ToType: "TaskInput", + EdgeLabel: "owner_Organization", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63487,50 +43896,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "owner_task", }, RegexMatch: []string{ "Organization/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_Group|Group": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Group", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|valueRelatedArtifact_resourceReference_Group|TaskInput": { - FromType: "Group", - EdgeLabel: "valueRelatedArtifact_resourceReference_Group", - ToType: "TaskInput", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "related_artifact", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "TaskInput|valueRelatedArtifact_resourceReference_Practitioner|Practitioner": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Practitioner", - ToType: "Practitioner", + "Task|owner_Patient|Patient": { + FromType: "Task", + EdgeLabel: "owner_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -63538,16 +43913,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "owner_task", }, RegexMatch: []string{ - "Practitioner/*", + "Patient/*", }, }, - "Practitioner|valueRelatedArtifact_resourceReference_Practitioner|TaskInput": { - FromType: "Practitioner", - EdgeLabel: "valueRelatedArtifact_resourceReference_Practitioner", - ToType: "TaskInput", + "Patient|owner_Patient|Task": { + FromType: "Patient", + EdgeLabel: "owner_Patient", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63555,33 +43930,33 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "owner_task", }, RegexMatch: []string{ - "Practitioner/*", + "Patient/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_PractitionerRole|PractitionerRole": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_PractitionerRole", - ToType: "PractitionerRole", + "Task|partOf|Task": { + FromType: "Task", + EdgeLabel: "partOf", + ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "partOf_task", }, RegexMatch: []string{ - "PractitionerRole/*", + "Task/*", }, }, - "PractitionerRole|valueRelatedArtifact_resourceReference_PractitionerRole|TaskInput": { - FromType: "PractitionerRole", - EdgeLabel: "valueRelatedArtifact_resourceReference_PractitionerRole", - ToType: "TaskInput", + "Task|requester_Organization|Organization": { + FromType: "Task", + EdgeLabel: "requester_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -63589,16 +43964,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "requester_task", }, RegexMatch: []string{ - "PractitionerRole/*", + "Organization/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_ResearchStudy|ResearchStudy": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_ResearchStudy", - ToType: "ResearchStudy", + "Organization|requester_Organization|Task": { + FromType: "Organization", + EdgeLabel: "requester_Organization", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63606,16 +43981,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "requester_task", }, RegexMatch: []string{ - "ResearchStudy/*", + "Organization/*", }, }, - "ResearchStudy|valueRelatedArtifact_resourceReference_ResearchStudy|TaskInput": { - FromType: "ResearchStudy", - EdgeLabel: "valueRelatedArtifact_resourceReference_ResearchStudy", - ToType: "TaskInput", + "Task|requester_Patient|Patient": { + FromType: "Task", + EdgeLabel: "requester_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -63623,16 +43998,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "requester_task", }, RegexMatch: []string{ - "ResearchStudy/*", + "Patient/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_Patient|Patient": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Patient", - ToType: "Patient", + "Patient|requester_Patient|Task": { + FromType: "Patient", + EdgeLabel: "requester_Patient", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63640,16 +44015,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "requester_task", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|valueRelatedArtifact_resourceReference_Patient|TaskInput": { - FromType: "Patient", - EdgeLabel: "valueRelatedArtifact_resourceReference_Patient", - ToType: "TaskInput", + "Task|requester_Practitioner|Practitioner": { + FromType: "Task", + EdgeLabel: "requester_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -63657,16 +44032,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "requester_task", }, RegexMatch: []string{ - "Patient/*", + "Practitioner/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_ResearchSubject|ResearchSubject": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_ResearchSubject", - ToType: "ResearchSubject", + "Practitioner|requester_Practitioner|Task": { + FromType: "Practitioner", + EdgeLabel: "requester_Practitioner", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63674,16 +44049,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "requester_task", }, RegexMatch: []string{ - "ResearchSubject/*", + "Practitioner/*", }, }, - "ResearchSubject|valueRelatedArtifact_resourceReference_ResearchSubject|TaskInput": { - FromType: "ResearchSubject", - EdgeLabel: "valueRelatedArtifact_resourceReference_ResearchSubject", - ToType: "TaskInput", + "Task|requester_PractitionerRole|PractitionerRole": { + FromType: "Task", + EdgeLabel: "requester_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -63691,16 +44066,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "requester_task", }, RegexMatch: []string{ - "ResearchSubject/*", + "PractitionerRole/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_Substance|Substance": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Substance", - ToType: "Substance", + "PractitionerRole|requester_PractitionerRole|Task": { + FromType: "PractitionerRole", + EdgeLabel: "requester_PractitionerRole", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63708,16 +44083,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "requester_task", }, RegexMatch: []string{ - "Substance/*", + "PractitionerRole/*", }, }, - "Substance|valueRelatedArtifact_resourceReference_Substance|TaskInput": { - FromType: "Substance", - EdgeLabel: "valueRelatedArtifact_resourceReference_Substance", - ToType: "TaskInput", + "Task|input_valueReference_Organization|Organization": { + FromType: "Task", + EdgeLabel: "input_valueReference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -63725,16 +44100,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "Substance/*", + "Organization/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_SubstanceDefinition|SubstanceDefinition": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_SubstanceDefinition", - ToType: "SubstanceDefinition", + "Organization|input_valueReference_Organization|Task": { + FromType: "Organization", + EdgeLabel: "input_valueReference_Organization", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63742,16 +44117,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "Organization/*", }, }, - "SubstanceDefinition|valueRelatedArtifact_resourceReference_SubstanceDefinition|TaskInput": { - FromType: "SubstanceDefinition", - EdgeLabel: "valueRelatedArtifact_resourceReference_SubstanceDefinition", - ToType: "TaskInput", + "Task|input_valueReference_Group|Group": { + FromType: "Task", + EdgeLabel: "input_valueReference_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -63759,16 +44134,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "SubstanceDefinition/*", + "Group/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_Specimen|Specimen": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Specimen", - ToType: "Specimen", + "Group|input_valueReference_Group|Task": { + FromType: "Group", + EdgeLabel: "input_valueReference_Group", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63776,16 +44151,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "Specimen/*", + "Group/*", }, }, - "Specimen|valueRelatedArtifact_resourceReference_Specimen|TaskInput": { - FromType: "Specimen", - EdgeLabel: "valueRelatedArtifact_resourceReference_Specimen", - ToType: "TaskInput", + "Task|input_valueReference_Practitioner|Practitioner": { + FromType: "Task", + EdgeLabel: "input_valueReference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -63793,16 +44168,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "Specimen/*", + "Practitioner/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_Observation|Observation": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Observation", - ToType: "Observation", + "Practitioner|input_valueReference_Practitioner|Task": { + FromType: "Practitioner", + EdgeLabel: "input_valueReference_Practitioner", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63810,16 +44185,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "Observation/*", + "Practitioner/*", }, }, - "Observation|valueRelatedArtifact_resourceReference_Observation|TaskInput": { - FromType: "Observation", - EdgeLabel: "valueRelatedArtifact_resourceReference_Observation", - ToType: "TaskInput", + "Task|input_valueReference_PractitionerRole|PractitionerRole": { + FromType: "Task", + EdgeLabel: "input_valueReference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -63827,16 +44202,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "Observation/*", + "PractitionerRole/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_DiagnosticReport|DiagnosticReport": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_DiagnosticReport", - ToType: "DiagnosticReport", + "PractitionerRole|input_valueReference_PractitionerRole|Task": { + FromType: "PractitionerRole", + EdgeLabel: "input_valueReference_PractitionerRole", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63844,16 +44219,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "DiagnosticReport/*", + "PractitionerRole/*", }, }, - "DiagnosticReport|valueRelatedArtifact_resourceReference_DiagnosticReport|TaskInput": { - FromType: "DiagnosticReport", - EdgeLabel: "valueRelatedArtifact_resourceReference_DiagnosticReport", - ToType: "TaskInput", + "Task|input_valueReference_ResearchStudy|ResearchStudy": { + FromType: "Task", + EdgeLabel: "input_valueReference_ResearchStudy", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -63861,16 +44236,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "DiagnosticReport/*", + "ResearchStudy/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_Condition|Condition": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Condition", - ToType: "Condition", + "ResearchStudy|input_valueReference_ResearchStudy|Task": { + FromType: "ResearchStudy", + EdgeLabel: "input_valueReference_ResearchStudy", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63878,16 +44253,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "Condition/*", + "ResearchStudy/*", }, }, - "Condition|valueRelatedArtifact_resourceReference_Condition|TaskInput": { - FromType: "Condition", - EdgeLabel: "valueRelatedArtifact_resourceReference_Condition", - ToType: "TaskInput", + "Task|input_valueReference_Patient|Patient": { + FromType: "Task", + EdgeLabel: "input_valueReference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -63895,16 +44270,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "Condition/*", + "Patient/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_Medication|Medication": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Medication", - ToType: "Medication", + "Patient|input_valueReference_Patient|Task": { + FromType: "Patient", + EdgeLabel: "input_valueReference_Patient", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63912,16 +44287,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "Medication/*", + "Patient/*", }, }, - "Medication|valueRelatedArtifact_resourceReference_Medication|TaskInput": { - FromType: "Medication", - EdgeLabel: "valueRelatedArtifact_resourceReference_Medication", - ToType: "TaskInput", + "Task|input_valueReference_ResearchSubject|ResearchSubject": { + FromType: "Task", + EdgeLabel: "input_valueReference_ResearchSubject", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, @@ -63929,16 +44304,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "Medication/*", + "ResearchSubject/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_MedicationAdministration|MedicationAdministration": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_MedicationAdministration", - ToType: "MedicationAdministration", + "ResearchSubject|input_valueReference_ResearchSubject|Task": { + FromType: "ResearchSubject", + EdgeLabel: "input_valueReference_ResearchSubject", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63946,16 +44321,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "MedicationAdministration/*", + "ResearchSubject/*", }, }, - "MedicationAdministration|valueRelatedArtifact_resourceReference_MedicationAdministration|TaskInput": { - FromType: "MedicationAdministration", - EdgeLabel: "valueRelatedArtifact_resourceReference_MedicationAdministration", - ToType: "TaskInput", + "Task|input_valueReference_Substance|Substance": { + FromType: "Task", + EdgeLabel: "input_valueReference_Substance", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -63963,16 +44338,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "MedicationAdministration/*", + "Substance/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_MedicationStatement|MedicationStatement": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_MedicationStatement", - ToType: "MedicationStatement", + "Substance|input_valueReference_Substance|Task": { + FromType: "Substance", + EdgeLabel: "input_valueReference_Substance", + ToType: "Task", Direction: []string{ "outbound", }, @@ -63980,16 +44355,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "MedicationStatement/*", + "Substance/*", }, }, - "MedicationStatement|valueRelatedArtifact_resourceReference_MedicationStatement|TaskInput": { - FromType: "MedicationStatement", - EdgeLabel: "valueRelatedArtifact_resourceReference_MedicationStatement", - ToType: "TaskInput", + "Task|input_valueReference_SubstanceDefinition|SubstanceDefinition": { + FromType: "Task", + EdgeLabel: "input_valueReference_SubstanceDefinition", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, @@ -63997,16 +44372,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "MedicationStatement/*", + "SubstanceDefinition/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_MedicationRequest|MedicationRequest": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_MedicationRequest", - ToType: "MedicationRequest", + "SubstanceDefinition|input_valueReference_SubstanceDefinition|Task": { + FromType: "SubstanceDefinition", + EdgeLabel: "input_valueReference_SubstanceDefinition", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64014,16 +44389,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "MedicationRequest/*", + "SubstanceDefinition/*", }, }, - "MedicationRequest|valueRelatedArtifact_resourceReference_MedicationRequest|TaskInput": { - FromType: "MedicationRequest", - EdgeLabel: "valueRelatedArtifact_resourceReference_MedicationRequest", - ToType: "TaskInput", + "Task|input_valueReference_Specimen|Specimen": { + FromType: "Task", + EdgeLabel: "input_valueReference_Specimen", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -64031,16 +44406,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "MedicationRequest/*", + "Specimen/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_Procedure|Procedure": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Procedure", - ToType: "Procedure", + "Specimen|input_valueReference_Specimen|Task": { + FromType: "Specimen", + EdgeLabel: "input_valueReference_Specimen", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64048,16 +44423,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "Procedure/*", + "Specimen/*", }, }, - "Procedure|valueRelatedArtifact_resourceReference_Procedure|TaskInput": { - FromType: "Procedure", - EdgeLabel: "valueRelatedArtifact_resourceReference_Procedure", - ToType: "TaskInput", + "Task|input_valueReference_Observation|Observation": { + FromType: "Task", + EdgeLabel: "input_valueReference_Observation", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -64065,16 +44440,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "Procedure/*", + "Observation/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_DocumentReference|DocumentReference": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_DocumentReference", - ToType: "DocumentReference", + "Observation|input_valueReference_Observation|Task": { + FromType: "Observation", + EdgeLabel: "input_valueReference_Observation", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64082,16 +44457,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "DocumentReference/*", + "Observation/*", }, }, - "DocumentReference|valueRelatedArtifact_resourceReference_DocumentReference|TaskInput": { - FromType: "DocumentReference", - EdgeLabel: "valueRelatedArtifact_resourceReference_DocumentReference", - ToType: "TaskInput", + "Task|input_valueReference_DiagnosticReport|DiagnosticReport": { + FromType: "Task", + EdgeLabel: "input_valueReference_DiagnosticReport", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -64099,15 +44474,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "DocumentReference/*", + "DiagnosticReport/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_Task|Task": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Task", + "DiagnosticReport|input_valueReference_DiagnosticReport|Task": { + FromType: "DiagnosticReport", + EdgeLabel: "input_valueReference_DiagnosticReport", ToType: "Task", Direction: []string{ "outbound", @@ -64116,16 +44491,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "Task/*", + "DiagnosticReport/*", }, }, - "Task|valueRelatedArtifact_resourceReference_Task|TaskInput": { + "Task|input_valueReference_Condition|Condition": { FromType: "Task", - EdgeLabel: "valueRelatedArtifact_resourceReference_Task", - ToType: "TaskInput", + EdgeLabel: "input_valueReference_Condition", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -64133,16 +44508,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "Task/*", + "Condition/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_ImagingStudy|ImagingStudy": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_ImagingStudy", - ToType: "ImagingStudy", + "Condition|input_valueReference_Condition|Task": { + FromType: "Condition", + EdgeLabel: "input_valueReference_Condition", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64150,16 +44525,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "ImagingStudy/*", + "Condition/*", }, }, - "ImagingStudy|valueRelatedArtifact_resourceReference_ImagingStudy|TaskInput": { - FromType: "ImagingStudy", - EdgeLabel: "valueRelatedArtifact_resourceReference_ImagingStudy", - ToType: "TaskInput", + "Task|input_valueReference_Medication|Medication": { + FromType: "Task", + EdgeLabel: "input_valueReference_Medication", + ToType: "Medication", Direction: []string{ "outbound", }, @@ -64167,16 +44542,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "ImagingStudy/*", + "Medication/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", + "Medication|input_valueReference_Medication|Task": { + FromType: "Medication", + EdgeLabel: "input_valueReference_Medication", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64184,16 +44559,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Medication/*", }, }, - "FamilyMemberHistory|valueRelatedArtifact_resourceReference_FamilyMemberHistory|TaskInput": { - FromType: "FamilyMemberHistory", - EdgeLabel: "valueRelatedArtifact_resourceReference_FamilyMemberHistory", - ToType: "TaskInput", + "Task|input_valueReference_MedicationAdministration|MedicationAdministration": { + FromType: "Task", + EdgeLabel: "input_valueReference_MedicationAdministration", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, @@ -64201,16 +44576,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "MedicationAdministration/*", }, }, - "TaskInput|valueRelatedArtifact_resourceReference_BodyStructure|BodyStructure": { - FromType: "TaskInput", - EdgeLabel: "valueRelatedArtifact_resourceReference_BodyStructure", - ToType: "BodyStructure", + "MedicationAdministration|input_valueReference_MedicationAdministration|Task": { + FromType: "MedicationAdministration", + EdgeLabel: "input_valueReference_MedicationAdministration", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64218,16 +44593,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "BodyStructure/*", + "MedicationAdministration/*", }, }, - "BodyStructure|valueRelatedArtifact_resourceReference_BodyStructure|TaskInput": { - FromType: "BodyStructure", - EdgeLabel: "valueRelatedArtifact_resourceReference_BodyStructure", - ToType: "TaskInput", + "Task|input_valueReference_MedicationStatement|MedicationStatement": { + FromType: "Task", + EdgeLabel: "input_valueReference_MedicationStatement", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, @@ -64235,16 +44610,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "task_input", }, RegexMatch: []string{ - "BodyStructure/*", + "MedicationStatement/*", }, }, - "TaskInput|valueSignature_onBehalfOf_Practitioner|Practitioner": { - FromType: "TaskInput", - EdgeLabel: "valueSignature_onBehalfOf_Practitioner", - ToType: "Practitioner", + "MedicationStatement|input_valueReference_MedicationStatement|Task": { + FromType: "MedicationStatement", + EdgeLabel: "input_valueReference_MedicationStatement", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64252,16 +44627,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "onBehalfOf_signature", + "task_input", }, RegexMatch: []string{ - "Practitioner/*", + "MedicationStatement/*", }, }, - "Practitioner|valueSignature_onBehalfOf_Practitioner|TaskInput": { - FromType: "Practitioner", - EdgeLabel: "valueSignature_onBehalfOf_Practitioner", - ToType: "TaskInput", + "Task|input_valueReference_MedicationRequest|MedicationRequest": { + FromType: "Task", + EdgeLabel: "input_valueReference_MedicationRequest", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, @@ -64269,16 +44644,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "onBehalfOf_signature", + "task_input", }, RegexMatch: []string{ - "Practitioner/*", + "MedicationRequest/*", }, }, - "TaskInput|valueSignature_onBehalfOf_PractitionerRole|PractitionerRole": { - FromType: "TaskInput", - EdgeLabel: "valueSignature_onBehalfOf_PractitionerRole", - ToType: "PractitionerRole", + "MedicationRequest|input_valueReference_MedicationRequest|Task": { + FromType: "MedicationRequest", + EdgeLabel: "input_valueReference_MedicationRequest", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64286,16 +44661,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "onBehalfOf_signature", + "task_input", }, RegexMatch: []string{ - "PractitionerRole/*", + "MedicationRequest/*", }, }, - "PractitionerRole|valueSignature_onBehalfOf_PractitionerRole|TaskInput": { - FromType: "PractitionerRole", - EdgeLabel: "valueSignature_onBehalfOf_PractitionerRole", - ToType: "TaskInput", + "Task|input_valueReference_Procedure|Procedure": { + FromType: "Task", + EdgeLabel: "input_valueReference_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, @@ -64303,16 +44678,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "onBehalfOf_signature", + "task_input", }, RegexMatch: []string{ - "PractitionerRole/*", + "Procedure/*", }, }, - "TaskInput|valueSignature_onBehalfOf_Patient|Patient": { - FromType: "TaskInput", - EdgeLabel: "valueSignature_onBehalfOf_Patient", - ToType: "Patient", + "Procedure|input_valueReference_Procedure|Task": { + FromType: "Procedure", + EdgeLabel: "input_valueReference_Procedure", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64320,16 +44695,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "onBehalfOf_signature", + "task_input", }, RegexMatch: []string{ - "Patient/*", + "Procedure/*", }, }, - "Patient|valueSignature_onBehalfOf_Patient|TaskInput": { - FromType: "Patient", - EdgeLabel: "valueSignature_onBehalfOf_Patient", - ToType: "TaskInput", + "Task|input_valueReference_DocumentReference|DocumentReference": { + FromType: "Task", + EdgeLabel: "input_valueReference_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, @@ -64337,16 +44712,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "onBehalfOf_signature", + "task_input", }, RegexMatch: []string{ - "Patient/*", + "DocumentReference/*", }, }, - "TaskInput|valueSignature_onBehalfOf_Organization|Organization": { - FromType: "TaskInput", - EdgeLabel: "valueSignature_onBehalfOf_Organization", - ToType: "Organization", + "DocumentReference|input_valueReference_DocumentReference|Task": { + FromType: "DocumentReference", + EdgeLabel: "input_valueReference_DocumentReference", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64354,16 +44729,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "onBehalfOf_signature", + "task_input", }, RegexMatch: []string{ - "Organization/*", + "DocumentReference/*", }, }, - "Organization|valueSignature_onBehalfOf_Organization|TaskInput": { - FromType: "Organization", - EdgeLabel: "valueSignature_onBehalfOf_Organization", - ToType: "TaskInput", + "Task|input_valueReference_Task|Task": { + FromType: "Task", + EdgeLabel: "input_valueReference_Task", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64371,16 +44746,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "onBehalfOf_signature", + "task_input", }, RegexMatch: []string{ - "Organization/*", + "Task/*", }, }, - "TaskInput|valueSignature_who_Practitioner|Practitioner": { - FromType: "TaskInput", - EdgeLabel: "valueSignature_who_Practitioner", - ToType: "Practitioner", + "Task|input_valueReference_ImagingStudy|ImagingStudy": { + FromType: "Task", + EdgeLabel: "input_valueReference_ImagingStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -64388,16 +44763,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "task_input", }, RegexMatch: []string{ - "Practitioner/*", + "ImagingStudy/*", }, }, - "Practitioner|valueSignature_who_Practitioner|TaskInput": { - FromType: "Practitioner", - EdgeLabel: "valueSignature_who_Practitioner", - ToType: "TaskInput", + "ImagingStudy|input_valueReference_ImagingStudy|Task": { + FromType: "ImagingStudy", + EdgeLabel: "input_valueReference_ImagingStudy", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64405,16 +44780,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "task_input", }, RegexMatch: []string{ - "Practitioner/*", + "ImagingStudy/*", }, }, - "TaskInput|valueSignature_who_PractitionerRole|PractitionerRole": { - FromType: "TaskInput", - EdgeLabel: "valueSignature_who_PractitionerRole", - ToType: "PractitionerRole", + "Task|input_valueReference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "Task", + EdgeLabel: "input_valueReference_FamilyMemberHistory", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -64422,16 +44797,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "task_input", }, RegexMatch: []string{ - "PractitionerRole/*", + "FamilyMemberHistory/*", }, }, - "PractitionerRole|valueSignature_who_PractitionerRole|TaskInput": { - FromType: "PractitionerRole", - EdgeLabel: "valueSignature_who_PractitionerRole", - ToType: "TaskInput", + "FamilyMemberHistory|input_valueReference_FamilyMemberHistory|Task": { + FromType: "FamilyMemberHistory", + EdgeLabel: "input_valueReference_FamilyMemberHistory", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64439,16 +44814,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "task_input", }, RegexMatch: []string{ - "PractitionerRole/*", + "FamilyMemberHistory/*", }, }, - "TaskInput|valueSignature_who_Patient|Patient": { - FromType: "TaskInput", - EdgeLabel: "valueSignature_who_Patient", - ToType: "Patient", + "Task|input_valueReference_BodyStructure|BodyStructure": { + FromType: "Task", + EdgeLabel: "input_valueReference_BodyStructure", + ToType: "BodyStructure", Direction: []string{ "outbound", }, @@ -64456,16 +44831,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "task_input", }, RegexMatch: []string{ - "Patient/*", + "BodyStructure/*", }, }, - "Patient|valueSignature_who_Patient|TaskInput": { - FromType: "Patient", - EdgeLabel: "valueSignature_who_Patient", - ToType: "TaskInput", + "BodyStructure|input_valueReference_BodyStructure|Task": { + FromType: "BodyStructure", + EdgeLabel: "input_valueReference_BodyStructure", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64473,16 +44848,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "task_input", }, RegexMatch: []string{ - "Patient/*", + "BodyStructure/*", }, }, - "TaskInput|valueSignature_who_Organization|Organization": { - FromType: "TaskInput", - EdgeLabel: "valueSignature_who_Organization", - ToType: "Organization", + "Task|note_authorReference_Practitioner|Practitioner": { + FromType: "Task", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -64490,16 +44865,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "annotation", }, RegexMatch: []string{ - "Organization/*", + "Practitioner/*", }, }, - "Organization|valueSignature_who_Organization|TaskInput": { - FromType: "Organization", - EdgeLabel: "valueSignature_who_Organization", - ToType: "TaskInput", + "Practitioner|note_authorReference_Practitioner|Task": { + FromType: "Practitioner", + EdgeLabel: "note_authorReference_Practitioner", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64507,16 +44882,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "annotation", }, RegexMatch: []string{ - "Organization/*", + "Practitioner/*", }, }, - "TaskInput|valueUsageContext_valueReference_ResearchStudy|ResearchStudy": { - FromType: "TaskInput", - EdgeLabel: "valueUsageContext_valueReference_ResearchStudy", - ToType: "ResearchStudy", + "Task|note_authorReference_PractitionerRole|PractitionerRole": { + FromType: "Task", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -64524,16 +44899,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "annotation", }, RegexMatch: []string{ - "ResearchStudy/*", + "PractitionerRole/*", }, }, - "ResearchStudy|valueUsageContext_valueReference_ResearchStudy|TaskInput": { - FromType: "ResearchStudy", - EdgeLabel: "valueUsageContext_valueReference_ResearchStudy", - ToType: "TaskInput", + "PractitionerRole|note_authorReference_PractitionerRole|Task": { + FromType: "PractitionerRole", + EdgeLabel: "note_authorReference_PractitionerRole", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64541,16 +44916,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "annotation", }, RegexMatch: []string{ - "ResearchStudy/*", + "PractitionerRole/*", }, }, - "TaskInput|valueUsageContext_valueReference_Group|Group": { - FromType: "TaskInput", - EdgeLabel: "valueUsageContext_valueReference_Group", - ToType: "Group", + "Task|note_authorReference_Patient|Patient": { + FromType: "Task", + EdgeLabel: "note_authorReference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -64558,16 +44933,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "annotation", }, RegexMatch: []string{ - "Group/*", + "Patient/*", }, }, - "Group|valueUsageContext_valueReference_Group|TaskInput": { - FromType: "Group", - EdgeLabel: "valueUsageContext_valueReference_Group", - ToType: "TaskInput", + "Patient|note_authorReference_Patient|Task": { + FromType: "Patient", + EdgeLabel: "note_authorReference_Patient", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64575,15 +44950,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "annotation", }, RegexMatch: []string{ - "Group/*", + "Patient/*", }, }, - "TaskInput|valueUsageContext_valueReference_Organization|Organization": { - FromType: "TaskInput", - EdgeLabel: "valueUsageContext_valueReference_Organization", + "Task|note_authorReference_Organization|Organization": { + FromType: "Task", + EdgeLabel: "note_authorReference_Organization", ToType: "Organization", Direction: []string{ "outbound", @@ -64592,16 +44967,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "annotation", }, RegexMatch: []string{ "Organization/*", }, }, - "Organization|valueUsageContext_valueReference_Organization|TaskInput": { + "Organization|note_authorReference_Organization|Task": { FromType: "Organization", - EdgeLabel: "valueUsageContext_valueReference_Organization", - ToType: "TaskInput", + EdgeLabel: "note_authorReference_Organization", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64609,15 +44984,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "annotation", }, RegexMatch: []string{ "Organization/*", }, }, - "TaskOutput|valueReference_Organization|Organization": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_Organization", + "Task|output_valueReference_Organization|Organization": { + FromType: "Task", + EdgeLabel: "output_valueReference_Organization", ToType: "Organization", Direction: []string{ "outbound", @@ -64632,10 +45007,10 @@ var Traversals = map[string]Traversal{ "Organization/*", }, }, - "Organization|valueReference_Organization|TaskOutput": { + "Organization|output_valueReference_Organization|Task": { FromType: "Organization", - EdgeLabel: "valueReference_Organization", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_Organization", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64649,9 +45024,9 @@ var Traversals = map[string]Traversal{ "Organization/*", }, }, - "TaskOutput|valueReference_Group|Group": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_Group", + "Task|output_valueReference_Group|Group": { + FromType: "Task", + EdgeLabel: "output_valueReference_Group", ToType: "Group", Direction: []string{ "outbound", @@ -64666,10 +45041,10 @@ var Traversals = map[string]Traversal{ "Group/*", }, }, - "Group|valueReference_Group|TaskOutput": { + "Group|output_valueReference_Group|Task": { FromType: "Group", - EdgeLabel: "valueReference_Group", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_Group", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64683,9 +45058,9 @@ var Traversals = map[string]Traversal{ "Group/*", }, }, - "TaskOutput|valueReference_Practitioner|Practitioner": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_Practitioner", + "Task|output_valueReference_Practitioner|Practitioner": { + FromType: "Task", + EdgeLabel: "output_valueReference_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", @@ -64700,10 +45075,10 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "Practitioner|valueReference_Practitioner|TaskOutput": { + "Practitioner|output_valueReference_Practitioner|Task": { FromType: "Practitioner", - EdgeLabel: "valueReference_Practitioner", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_Practitioner", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64717,9 +45092,9 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "TaskOutput|valueReference_PractitionerRole|PractitionerRole": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_PractitionerRole", + "Task|output_valueReference_PractitionerRole|PractitionerRole": { + FromType: "Task", + EdgeLabel: "output_valueReference_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", @@ -64734,10 +45109,10 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "PractitionerRole|valueReference_PractitionerRole|TaskOutput": { + "PractitionerRole|output_valueReference_PractitionerRole|Task": { FromType: "PractitionerRole", - EdgeLabel: "valueReference_PractitionerRole", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_PractitionerRole", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64751,9 +45126,9 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "TaskOutput|valueReference_ResearchStudy|ResearchStudy": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_ResearchStudy", + "Task|output_valueReference_ResearchStudy|ResearchStudy": { + FromType: "Task", + EdgeLabel: "output_valueReference_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -64768,10 +45143,10 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "ResearchStudy|valueReference_ResearchStudy|TaskOutput": { + "ResearchStudy|output_valueReference_ResearchStudy|Task": { FromType: "ResearchStudy", - EdgeLabel: "valueReference_ResearchStudy", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_ResearchStudy", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64785,9 +45160,9 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "TaskOutput|valueReference_Patient|Patient": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_Patient", + "Task|output_valueReference_Patient|Patient": { + FromType: "Task", + EdgeLabel: "output_valueReference_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -64802,10 +45177,10 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "Patient|valueReference_Patient|TaskOutput": { + "Patient|output_valueReference_Patient|Task": { FromType: "Patient", - EdgeLabel: "valueReference_Patient", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_Patient", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64819,9 +45194,9 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "TaskOutput|valueReference_ResearchSubject|ResearchSubject": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_ResearchSubject", + "Task|output_valueReference_ResearchSubject|ResearchSubject": { + FromType: "Task", + EdgeLabel: "output_valueReference_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -64836,10 +45211,10 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "ResearchSubject|valueReference_ResearchSubject|TaskOutput": { + "ResearchSubject|output_valueReference_ResearchSubject|Task": { FromType: "ResearchSubject", - EdgeLabel: "valueReference_ResearchSubject", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_ResearchSubject", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64853,9 +45228,9 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "TaskOutput|valueReference_Substance|Substance": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_Substance", + "Task|output_valueReference_Substance|Substance": { + FromType: "Task", + EdgeLabel: "output_valueReference_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -64870,10 +45245,10 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "Substance|valueReference_Substance|TaskOutput": { + "Substance|output_valueReference_Substance|Task": { FromType: "Substance", - EdgeLabel: "valueReference_Substance", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_Substance", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64887,9 +45262,9 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "TaskOutput|valueReference_SubstanceDefinition|SubstanceDefinition": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_SubstanceDefinition", + "Task|output_valueReference_SubstanceDefinition|SubstanceDefinition": { + FromType: "Task", + EdgeLabel: "output_valueReference_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -64904,10 +45279,10 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|valueReference_SubstanceDefinition|TaskOutput": { + "SubstanceDefinition|output_valueReference_SubstanceDefinition|Task": { FromType: "SubstanceDefinition", - EdgeLabel: "valueReference_SubstanceDefinition", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_SubstanceDefinition", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64921,9 +45296,9 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "TaskOutput|valueReference_Specimen|Specimen": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_Specimen", + "Task|output_valueReference_Specimen|Specimen": { + FromType: "Task", + EdgeLabel: "output_valueReference_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -64938,10 +45313,10 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "Specimen|valueReference_Specimen|TaskOutput": { + "Specimen|output_valueReference_Specimen|Task": { FromType: "Specimen", - EdgeLabel: "valueReference_Specimen", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_Specimen", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64955,9 +45330,9 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "TaskOutput|valueReference_Observation|Observation": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_Observation", + "Task|output_valueReference_Observation|Observation": { + FromType: "Task", + EdgeLabel: "output_valueReference_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -64972,10 +45347,10 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "Observation|valueReference_Observation|TaskOutput": { + "Observation|output_valueReference_Observation|Task": { FromType: "Observation", - EdgeLabel: "valueReference_Observation", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_Observation", + ToType: "Task", Direction: []string{ "outbound", }, @@ -64989,9 +45364,9 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "TaskOutput|valueReference_DiagnosticReport|DiagnosticReport": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_DiagnosticReport", + "Task|output_valueReference_DiagnosticReport|DiagnosticReport": { + FromType: "Task", + EdgeLabel: "output_valueReference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -65006,10 +45381,10 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "DiagnosticReport|valueReference_DiagnosticReport|TaskOutput": { + "DiagnosticReport|output_valueReference_DiagnosticReport|Task": { FromType: "DiagnosticReport", - EdgeLabel: "valueReference_DiagnosticReport", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_DiagnosticReport", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65023,9 +45398,9 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "TaskOutput|valueReference_Condition|Condition": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_Condition", + "Task|output_valueReference_Condition|Condition": { + FromType: "Task", + EdgeLabel: "output_valueReference_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -65040,10 +45415,10 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "Condition|valueReference_Condition|TaskOutput": { + "Condition|output_valueReference_Condition|Task": { FromType: "Condition", - EdgeLabel: "valueReference_Condition", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_Condition", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65057,9 +45432,9 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "TaskOutput|valueReference_Medication|Medication": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_Medication", + "Task|output_valueReference_Medication|Medication": { + FromType: "Task", + EdgeLabel: "output_valueReference_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -65074,10 +45449,10 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "Medication|valueReference_Medication|TaskOutput": { + "Medication|output_valueReference_Medication|Task": { FromType: "Medication", - EdgeLabel: "valueReference_Medication", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_Medication", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65091,9 +45466,9 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "TaskOutput|valueReference_MedicationAdministration|MedicationAdministration": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_MedicationAdministration", + "Task|output_valueReference_MedicationAdministration|MedicationAdministration": { + FromType: "Task", + EdgeLabel: "output_valueReference_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -65108,10 +45483,10 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "MedicationAdministration|valueReference_MedicationAdministration|TaskOutput": { + "MedicationAdministration|output_valueReference_MedicationAdministration|Task": { FromType: "MedicationAdministration", - EdgeLabel: "valueReference_MedicationAdministration", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_MedicationAdministration", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65125,9 +45500,9 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "TaskOutput|valueReference_MedicationStatement|MedicationStatement": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_MedicationStatement", + "Task|output_valueReference_MedicationStatement|MedicationStatement": { + FromType: "Task", + EdgeLabel: "output_valueReference_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -65142,10 +45517,10 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "MedicationStatement|valueReference_MedicationStatement|TaskOutput": { + "MedicationStatement|output_valueReference_MedicationStatement|Task": { FromType: "MedicationStatement", - EdgeLabel: "valueReference_MedicationStatement", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_MedicationStatement", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65159,9 +45534,9 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "TaskOutput|valueReference_MedicationRequest|MedicationRequest": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_MedicationRequest", + "Task|output_valueReference_MedicationRequest|MedicationRequest": { + FromType: "Task", + EdgeLabel: "output_valueReference_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -65176,10 +45551,10 @@ var Traversals = map[string]Traversal{ "MedicationRequest/*", }, }, - "MedicationRequest|valueReference_MedicationRequest|TaskOutput": { + "MedicationRequest|output_valueReference_MedicationRequest|Task": { FromType: "MedicationRequest", - EdgeLabel: "valueReference_MedicationRequest", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_MedicationRequest", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65193,9 +45568,9 @@ var Traversals = map[string]Traversal{ "MedicationRequest/*", }, }, - "TaskOutput|valueReference_Procedure|Procedure": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_Procedure", + "Task|output_valueReference_Procedure|Procedure": { + FromType: "Task", + EdgeLabel: "output_valueReference_Procedure", ToType: "Procedure", Direction: []string{ "outbound", @@ -65210,10 +45585,10 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "Procedure|valueReference_Procedure|TaskOutput": { + "Procedure|output_valueReference_Procedure|Task": { FromType: "Procedure", - EdgeLabel: "valueReference_Procedure", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_Procedure", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65227,9 +45602,9 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "TaskOutput|valueReference_DocumentReference|DocumentReference": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_DocumentReference", + "Task|output_valueReference_DocumentReference|DocumentReference": { + FromType: "Task", + EdgeLabel: "output_valueReference_DocumentReference", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -65244,10 +45619,10 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "DocumentReference|valueReference_DocumentReference|TaskOutput": { + "DocumentReference|output_valueReference_DocumentReference|Task": { FromType: "DocumentReference", - EdgeLabel: "valueReference_DocumentReference", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_DocumentReference", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65261,9 +45636,9 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "TaskOutput|valueReference_Task|Task": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_Task", + "Task|output_valueReference_Task|Task": { + FromType: "Task", + EdgeLabel: "output_valueReference_Task", ToType: "Task", Direction: []string{ "outbound", @@ -65278,26 +45653,9 @@ var Traversals = map[string]Traversal{ "Task/*", }, }, - "Task|valueReference_Task|TaskOutput": { + "Task|output_valueReference_ImagingStudy|ImagingStudy": { FromType: "Task", - EdgeLabel: "valueReference_Task", - ToType: "TaskOutput", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "task_output", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "TaskOutput|valueReference_ImagingStudy|ImagingStudy": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_ImagingStudy", + EdgeLabel: "output_valueReference_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", @@ -65312,10 +45670,10 @@ var Traversals = map[string]Traversal{ "ImagingStudy/*", }, }, - "ImagingStudy|valueReference_ImagingStudy|TaskOutput": { + "ImagingStudy|output_valueReference_ImagingStudy|Task": { FromType: "ImagingStudy", - EdgeLabel: "valueReference_ImagingStudy", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_ImagingStudy", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65329,9 +45687,9 @@ var Traversals = map[string]Traversal{ "ImagingStudy/*", }, }, - "TaskOutput|valueReference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_FamilyMemberHistory", + "Task|output_valueReference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "Task", + EdgeLabel: "output_valueReference_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -65346,10 +45704,10 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|valueReference_FamilyMemberHistory|TaskOutput": { + "FamilyMemberHistory|output_valueReference_FamilyMemberHistory|Task": { FromType: "FamilyMemberHistory", - EdgeLabel: "valueReference_FamilyMemberHistory", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_FamilyMemberHistory", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65363,9 +45721,9 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "TaskOutput|valueReference_BodyStructure|BodyStructure": { - FromType: "TaskOutput", - EdgeLabel: "valueReference_BodyStructure", + "Task|output_valueReference_BodyStructure|BodyStructure": { + FromType: "Task", + EdgeLabel: "output_valueReference_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", @@ -65380,10 +45738,10 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "BodyStructure|valueReference_BodyStructure|TaskOutput": { + "BodyStructure|output_valueReference_BodyStructure|Task": { FromType: "BodyStructure", - EdgeLabel: "valueReference_BodyStructure", - ToType: "TaskOutput", + EdgeLabel: "output_valueReference_BodyStructure", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65397,9 +45755,9 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "TaskOutput|valueAnnotation_authorReference_Practitioner|Practitioner": { - FromType: "TaskOutput", - EdgeLabel: "valueAnnotation_authorReference_Practitioner", + "Task|performer_actor_Practitioner|Practitioner": { + FromType: "Task", + EdgeLabel: "performer_actor_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", @@ -65408,16 +45766,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "task_performer", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Practitioner|valueAnnotation_authorReference_Practitioner|TaskOutput": { + "Practitioner|performer_actor_Practitioner|Task": { FromType: "Practitioner", - EdgeLabel: "valueAnnotation_authorReference_Practitioner", - ToType: "TaskOutput", + EdgeLabel: "performer_actor_Practitioner", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65425,15 +45783,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "task_performer", }, RegexMatch: []string{ "Practitioner/*", }, }, - "TaskOutput|valueAnnotation_authorReference_PractitionerRole|PractitionerRole": { - FromType: "TaskOutput", - EdgeLabel: "valueAnnotation_authorReference_PractitionerRole", + "Task|performer_actor_PractitionerRole|PractitionerRole": { + FromType: "Task", + EdgeLabel: "performer_actor_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", @@ -65442,16 +45800,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "task_performer", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "PractitionerRole|valueAnnotation_authorReference_PractitionerRole|TaskOutput": { + "PractitionerRole|performer_actor_PractitionerRole|Task": { FromType: "PractitionerRole", - EdgeLabel: "valueAnnotation_authorReference_PractitionerRole", - ToType: "TaskOutput", + EdgeLabel: "performer_actor_PractitionerRole", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65459,16 +45817,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "task_performer", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "TaskOutput|valueAnnotation_authorReference_Patient|Patient": { - FromType: "TaskOutput", - EdgeLabel: "valueAnnotation_authorReference_Patient", - ToType: "Patient", + "Task|performer_actor_Organization|Organization": { + FromType: "Task", + EdgeLabel: "performer_actor_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -65476,16 +45834,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "task_performer", }, RegexMatch: []string{ - "Patient/*", + "Organization/*", }, }, - "Patient|valueAnnotation_authorReference_Patient|TaskOutput": { - FromType: "Patient", - EdgeLabel: "valueAnnotation_authorReference_Patient", - ToType: "TaskOutput", + "Organization|performer_actor_Organization|Task": { + FromType: "Organization", + EdgeLabel: "performer_actor_Organization", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65493,16 +45851,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "task_performer", }, RegexMatch: []string{ - "Patient/*", + "Organization/*", }, }, - "TaskOutput|valueAnnotation_authorReference_Organization|Organization": { - FromType: "TaskOutput", - EdgeLabel: "valueAnnotation_authorReference_Organization", - ToType: "Organization", + "Task|performer_actor_Patient|Patient": { + FromType: "Task", + EdgeLabel: "performer_actor_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -65510,16 +45868,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "task_performer", }, RegexMatch: []string{ - "Organization/*", + "Patient/*", }, }, - "Organization|valueAnnotation_authorReference_Organization|TaskOutput": { - FromType: "Organization", - EdgeLabel: "valueAnnotation_authorReference_Organization", - ToType: "TaskOutput", + "Patient|performer_actor_Patient|Task": { + FromType: "Patient", + EdgeLabel: "performer_actor_Patient", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65527,15 +45885,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "annotation", + "task_performer", }, RegexMatch: []string{ - "Organization/*", + "Patient/*", }, }, - "TaskOutput|valueCodeableReference_reference_Organization|Organization": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_Organization", + "Task|reason_reference_Organization|Organization": { + FromType: "Task", + EdgeLabel: "reason_reference_Organization", ToType: "Organization", Direction: []string{ "outbound", @@ -65550,10 +45908,10 @@ var Traversals = map[string]Traversal{ "Organization/*", }, }, - "Organization|valueCodeableReference_reference_Organization|TaskOutput": { + "Organization|reason_reference_Organization|Task": { FromType: "Organization", - EdgeLabel: "valueCodeableReference_reference_Organization", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_Organization", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65567,9 +45925,9 @@ var Traversals = map[string]Traversal{ "Organization/*", }, }, - "TaskOutput|valueCodeableReference_reference_Group|Group": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_Group", + "Task|reason_reference_Group|Group": { + FromType: "Task", + EdgeLabel: "reason_reference_Group", ToType: "Group", Direction: []string{ "outbound", @@ -65584,10 +45942,10 @@ var Traversals = map[string]Traversal{ "Group/*", }, }, - "Group|valueCodeableReference_reference_Group|TaskOutput": { + "Group|reason_reference_Group|Task": { FromType: "Group", - EdgeLabel: "valueCodeableReference_reference_Group", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_Group", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65601,9 +45959,9 @@ var Traversals = map[string]Traversal{ "Group/*", }, }, - "TaskOutput|valueCodeableReference_reference_Practitioner|Practitioner": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_Practitioner", + "Task|reason_reference_Practitioner|Practitioner": { + FromType: "Task", + EdgeLabel: "reason_reference_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", @@ -65618,10 +45976,10 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "Practitioner|valueCodeableReference_reference_Practitioner|TaskOutput": { + "Practitioner|reason_reference_Practitioner|Task": { FromType: "Practitioner", - EdgeLabel: "valueCodeableReference_reference_Practitioner", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_Practitioner", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65635,9 +45993,9 @@ var Traversals = map[string]Traversal{ "Practitioner/*", }, }, - "TaskOutput|valueCodeableReference_reference_PractitionerRole|PractitionerRole": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_PractitionerRole", + "Task|reason_reference_PractitionerRole|PractitionerRole": { + FromType: "Task", + EdgeLabel: "reason_reference_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", @@ -65652,10 +46010,10 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "PractitionerRole|valueCodeableReference_reference_PractitionerRole|TaskOutput": { + "PractitionerRole|reason_reference_PractitionerRole|Task": { FromType: "PractitionerRole", - EdgeLabel: "valueCodeableReference_reference_PractitionerRole", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_PractitionerRole", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65669,9 +46027,9 @@ var Traversals = map[string]Traversal{ "PractitionerRole/*", }, }, - "TaskOutput|valueCodeableReference_reference_ResearchStudy|ResearchStudy": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_ResearchStudy", + "Task|reason_reference_ResearchStudy|ResearchStudy": { + FromType: "Task", + EdgeLabel: "reason_reference_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -65686,10 +46044,10 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "ResearchStudy|valueCodeableReference_reference_ResearchStudy|TaskOutput": { + "ResearchStudy|reason_reference_ResearchStudy|Task": { FromType: "ResearchStudy", - EdgeLabel: "valueCodeableReference_reference_ResearchStudy", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_ResearchStudy", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65703,9 +46061,9 @@ var Traversals = map[string]Traversal{ "ResearchStudy/*", }, }, - "TaskOutput|valueCodeableReference_reference_Patient|Patient": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_Patient", + "Task|reason_reference_Patient|Patient": { + FromType: "Task", + EdgeLabel: "reason_reference_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -65720,10 +46078,10 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "Patient|valueCodeableReference_reference_Patient|TaskOutput": { + "Patient|reason_reference_Patient|Task": { FromType: "Patient", - EdgeLabel: "valueCodeableReference_reference_Patient", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_Patient", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65737,9 +46095,9 @@ var Traversals = map[string]Traversal{ "Patient/*", }, }, - "TaskOutput|valueCodeableReference_reference_ResearchSubject|ResearchSubject": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_ResearchSubject", + "Task|reason_reference_ResearchSubject|ResearchSubject": { + FromType: "Task", + EdgeLabel: "reason_reference_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -65754,10 +46112,10 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "ResearchSubject|valueCodeableReference_reference_ResearchSubject|TaskOutput": { + "ResearchSubject|reason_reference_ResearchSubject|Task": { FromType: "ResearchSubject", - EdgeLabel: "valueCodeableReference_reference_ResearchSubject", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_ResearchSubject", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65771,9 +46129,9 @@ var Traversals = map[string]Traversal{ "ResearchSubject/*", }, }, - "TaskOutput|valueCodeableReference_reference_Substance|Substance": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_Substance", + "Task|reason_reference_Substance|Substance": { + FromType: "Task", + EdgeLabel: "reason_reference_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -65788,10 +46146,10 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "Substance|valueCodeableReference_reference_Substance|TaskOutput": { + "Substance|reason_reference_Substance|Task": { FromType: "Substance", - EdgeLabel: "valueCodeableReference_reference_Substance", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_Substance", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65805,9 +46163,9 @@ var Traversals = map[string]Traversal{ "Substance/*", }, }, - "TaskOutput|valueCodeableReference_reference_SubstanceDefinition|SubstanceDefinition": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_SubstanceDefinition", + "Task|reason_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "Task", + EdgeLabel: "reason_reference_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -65822,10 +46180,10 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|valueCodeableReference_reference_SubstanceDefinition|TaskOutput": { + "SubstanceDefinition|reason_reference_SubstanceDefinition|Task": { FromType: "SubstanceDefinition", - EdgeLabel: "valueCodeableReference_reference_SubstanceDefinition", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_SubstanceDefinition", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65839,9 +46197,9 @@ var Traversals = map[string]Traversal{ "SubstanceDefinition/*", }, }, - "TaskOutput|valueCodeableReference_reference_Specimen|Specimen": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_Specimen", + "Task|reason_reference_Specimen|Specimen": { + FromType: "Task", + EdgeLabel: "reason_reference_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -65856,10 +46214,10 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "Specimen|valueCodeableReference_reference_Specimen|TaskOutput": { + "Specimen|reason_reference_Specimen|Task": { FromType: "Specimen", - EdgeLabel: "valueCodeableReference_reference_Specimen", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_Specimen", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65873,9 +46231,9 @@ var Traversals = map[string]Traversal{ "Specimen/*", }, }, - "TaskOutput|valueCodeableReference_reference_Observation|Observation": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_Observation", + "Task|reason_reference_Observation|Observation": { + FromType: "Task", + EdgeLabel: "reason_reference_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -65890,10 +46248,10 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "Observation|valueCodeableReference_reference_Observation|TaskOutput": { + "Observation|reason_reference_Observation|Task": { FromType: "Observation", - EdgeLabel: "valueCodeableReference_reference_Observation", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_Observation", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65907,9 +46265,9 @@ var Traversals = map[string]Traversal{ "Observation/*", }, }, - "TaskOutput|valueCodeableReference_reference_DiagnosticReport|DiagnosticReport": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_DiagnosticReport", + "Task|reason_reference_DiagnosticReport|DiagnosticReport": { + FromType: "Task", + EdgeLabel: "reason_reference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -65924,10 +46282,10 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "DiagnosticReport|valueCodeableReference_reference_DiagnosticReport|TaskOutput": { + "DiagnosticReport|reason_reference_DiagnosticReport|Task": { FromType: "DiagnosticReport", - EdgeLabel: "valueCodeableReference_reference_DiagnosticReport", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_DiagnosticReport", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65941,9 +46299,9 @@ var Traversals = map[string]Traversal{ "DiagnosticReport/*", }, }, - "TaskOutput|valueCodeableReference_reference_Condition|Condition": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_Condition", + "Task|reason_reference_Condition|Condition": { + FromType: "Task", + EdgeLabel: "reason_reference_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -65958,10 +46316,10 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "Condition|valueCodeableReference_reference_Condition|TaskOutput": { + "Condition|reason_reference_Condition|Task": { FromType: "Condition", - EdgeLabel: "valueCodeableReference_reference_Condition", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_Condition", + ToType: "Task", Direction: []string{ "outbound", }, @@ -65975,9 +46333,9 @@ var Traversals = map[string]Traversal{ "Condition/*", }, }, - "TaskOutput|valueCodeableReference_reference_Medication|Medication": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_Medication", + "Task|reason_reference_Medication|Medication": { + FromType: "Task", + EdgeLabel: "reason_reference_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -65992,10 +46350,10 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "Medication|valueCodeableReference_reference_Medication|TaskOutput": { + "Medication|reason_reference_Medication|Task": { FromType: "Medication", - EdgeLabel: "valueCodeableReference_reference_Medication", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_Medication", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66009,9 +46367,9 @@ var Traversals = map[string]Traversal{ "Medication/*", }, }, - "TaskOutput|valueCodeableReference_reference_MedicationAdministration|MedicationAdministration": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_MedicationAdministration", + "Task|reason_reference_MedicationAdministration|MedicationAdministration": { + FromType: "Task", + EdgeLabel: "reason_reference_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -66026,10 +46384,10 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "MedicationAdministration|valueCodeableReference_reference_MedicationAdministration|TaskOutput": { + "MedicationAdministration|reason_reference_MedicationAdministration|Task": { FromType: "MedicationAdministration", - EdgeLabel: "valueCodeableReference_reference_MedicationAdministration", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_MedicationAdministration", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66043,9 +46401,9 @@ var Traversals = map[string]Traversal{ "MedicationAdministration/*", }, }, - "TaskOutput|valueCodeableReference_reference_MedicationStatement|MedicationStatement": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_MedicationStatement", + "Task|reason_reference_MedicationStatement|MedicationStatement": { + FromType: "Task", + EdgeLabel: "reason_reference_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -66060,10 +46418,10 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "MedicationStatement|valueCodeableReference_reference_MedicationStatement|TaskOutput": { + "MedicationStatement|reason_reference_MedicationStatement|Task": { FromType: "MedicationStatement", - EdgeLabel: "valueCodeableReference_reference_MedicationStatement", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_MedicationStatement", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66077,9 +46435,9 @@ var Traversals = map[string]Traversal{ "MedicationStatement/*", }, }, - "TaskOutput|valueCodeableReference_reference_MedicationRequest|MedicationRequest": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_MedicationRequest", + "Task|reason_reference_MedicationRequest|MedicationRequest": { + FromType: "Task", + EdgeLabel: "reason_reference_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -66094,10 +46452,10 @@ var Traversals = map[string]Traversal{ "MedicationRequest/*", }, }, - "MedicationRequest|valueCodeableReference_reference_MedicationRequest|TaskOutput": { + "MedicationRequest|reason_reference_MedicationRequest|Task": { FromType: "MedicationRequest", - EdgeLabel: "valueCodeableReference_reference_MedicationRequest", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_MedicationRequest", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66111,9 +46469,9 @@ var Traversals = map[string]Traversal{ "MedicationRequest/*", }, }, - "TaskOutput|valueCodeableReference_reference_Procedure|Procedure": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_Procedure", + "Task|reason_reference_Procedure|Procedure": { + FromType: "Task", + EdgeLabel: "reason_reference_Procedure", ToType: "Procedure", Direction: []string{ "outbound", @@ -66128,10 +46486,10 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "Procedure|valueCodeableReference_reference_Procedure|TaskOutput": { + "Procedure|reason_reference_Procedure|Task": { FromType: "Procedure", - EdgeLabel: "valueCodeableReference_reference_Procedure", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_Procedure", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66145,9 +46503,9 @@ var Traversals = map[string]Traversal{ "Procedure/*", }, }, - "TaskOutput|valueCodeableReference_reference_DocumentReference|DocumentReference": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_DocumentReference", + "Task|reason_reference_DocumentReference|DocumentReference": { + FromType: "Task", + EdgeLabel: "reason_reference_DocumentReference", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -66162,10 +46520,10 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "DocumentReference|valueCodeableReference_reference_DocumentReference|TaskOutput": { + "DocumentReference|reason_reference_DocumentReference|Task": { FromType: "DocumentReference", - EdgeLabel: "valueCodeableReference_reference_DocumentReference", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_DocumentReference", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66179,9 +46537,9 @@ var Traversals = map[string]Traversal{ "DocumentReference/*", }, }, - "TaskOutput|valueCodeableReference_reference_Task|Task": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_Task", + "Task|reason_reference_Task|Task": { + FromType: "Task", + EdgeLabel: "reason_reference_Task", ToType: "Task", Direction: []string{ "outbound", @@ -66196,26 +46554,9 @@ var Traversals = map[string]Traversal{ "Task/*", }, }, - "Task|valueCodeableReference_reference_Task|TaskOutput": { + "Task|reason_reference_ImagingStudy|ImagingStudy": { FromType: "Task", - EdgeLabel: "valueCodeableReference_reference_Task", - ToType: "TaskOutput", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "codeable_reference", - }, - RegexMatch: []string{ - "Task/*", - }, - }, - "TaskOutput|valueCodeableReference_reference_ImagingStudy|ImagingStudy": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_ImagingStudy", + EdgeLabel: "reason_reference_ImagingStudy", ToType: "ImagingStudy", Direction: []string{ "outbound", @@ -66230,10 +46571,10 @@ var Traversals = map[string]Traversal{ "ImagingStudy/*", }, }, - "ImagingStudy|valueCodeableReference_reference_ImagingStudy|TaskOutput": { + "ImagingStudy|reason_reference_ImagingStudy|Task": { FromType: "ImagingStudy", - EdgeLabel: "valueCodeableReference_reference_ImagingStudy", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_ImagingStudy", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66247,9 +46588,9 @@ var Traversals = map[string]Traversal{ "ImagingStudy/*", }, }, - "TaskOutput|valueCodeableReference_reference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_FamilyMemberHistory", + "Task|reason_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "Task", + EdgeLabel: "reason_reference_FamilyMemberHistory", ToType: "FamilyMemberHistory", Direction: []string{ "outbound", @@ -66264,10 +46605,10 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "FamilyMemberHistory|valueCodeableReference_reference_FamilyMemberHistory|TaskOutput": { + "FamilyMemberHistory|reason_reference_FamilyMemberHistory|Task": { FromType: "FamilyMemberHistory", - EdgeLabel: "valueCodeableReference_reference_FamilyMemberHistory", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_FamilyMemberHistory", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66281,9 +46622,9 @@ var Traversals = map[string]Traversal{ "FamilyMemberHistory/*", }, }, - "TaskOutput|valueCodeableReference_reference_BodyStructure|BodyStructure": { - FromType: "TaskOutput", - EdgeLabel: "valueCodeableReference_reference_BodyStructure", + "Task|reason_reference_BodyStructure|BodyStructure": { + FromType: "Task", + EdgeLabel: "reason_reference_BodyStructure", ToType: "BodyStructure", Direction: []string{ "outbound", @@ -66298,10 +46639,10 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "BodyStructure|valueCodeableReference_reference_BodyStructure|TaskOutput": { + "BodyStructure|reason_reference_BodyStructure|Task": { FromType: "BodyStructure", - EdgeLabel: "valueCodeableReference_reference_BodyStructure", - ToType: "TaskOutput", + EdgeLabel: "reason_reference_BodyStructure", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66315,77 +46656,9 @@ var Traversals = map[string]Traversal{ "BodyStructure/*", }, }, - "TaskOutput|valueDataRequirement_subjectReference|Group": { - FromType: "TaskOutput", - EdgeLabel: "valueDataRequirement_subjectReference", - ToType: "Group", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "data_requirement", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "Group|valueDataRequirement_subjectReference|TaskOutput": { - FromType: "Group", - EdgeLabel: "valueDataRequirement_subjectReference", - ToType: "TaskOutput", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "data_requirement", - }, - RegexMatch: []string{ - "Group/*", - }, - }, - "TaskOutput|valueExtendedContactDetail_organization|Organization": { - FromType: "TaskOutput", - EdgeLabel: "valueExtendedContactDetail_organization", - ToType: "Organization", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "extended_contact_detail", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "Organization|valueExtendedContactDetail_organization|TaskOutput": { - FromType: "Organization", - EdgeLabel: "valueExtendedContactDetail_organization", - ToType: "TaskOutput", - Direction: []string{ - "outbound", - }, - Multiplicity: []string{ - "has_one", - }, - Backref: []string{ - "extended_contact_detail", - }, - RegexMatch: []string{ - "Organization/*", - }, - }, - "TaskOutput|valueRelatedArtifact_resourceReference_Organization|Organization": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Organization", + "Task|requestedPerformer_reference_Organization|Organization": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_Organization", ToType: "Organization", Direction: []string{ "outbound", @@ -66394,16 +46667,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Organization/*", }, }, - "Organization|valueRelatedArtifact_resourceReference_Organization|TaskOutput": { + "Organization|requestedPerformer_reference_Organization|Task": { FromType: "Organization", - EdgeLabel: "valueRelatedArtifact_resourceReference_Organization", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_Organization", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66411,15 +46684,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Organization/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_Group|Group": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Group", + "Task|requestedPerformer_reference_Group|Group": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_Group", ToType: "Group", Direction: []string{ "outbound", @@ -66428,16 +46701,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Group/*", }, }, - "Group|valueRelatedArtifact_resourceReference_Group|TaskOutput": { + "Group|requestedPerformer_reference_Group|Task": { FromType: "Group", - EdgeLabel: "valueRelatedArtifact_resourceReference_Group", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_Group", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66445,15 +46718,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Group/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_Practitioner|Practitioner": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Practitioner", + "Task|requestedPerformer_reference_Practitioner|Practitioner": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_Practitioner", ToType: "Practitioner", Direction: []string{ "outbound", @@ -66462,16 +46735,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Practitioner|valueRelatedArtifact_resourceReference_Practitioner|TaskOutput": { + "Practitioner|requestedPerformer_reference_Practitioner|Task": { FromType: "Practitioner", - EdgeLabel: "valueRelatedArtifact_resourceReference_Practitioner", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_Practitioner", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66479,15 +46752,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Practitioner/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_PractitionerRole|PractitionerRole": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_PractitionerRole", + "Task|requestedPerformer_reference_PractitionerRole|PractitionerRole": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_PractitionerRole", ToType: "PractitionerRole", Direction: []string{ "outbound", @@ -66496,16 +46769,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "PractitionerRole|valueRelatedArtifact_resourceReference_PractitionerRole|TaskOutput": { + "PractitionerRole|requestedPerformer_reference_PractitionerRole|Task": { FromType: "PractitionerRole", - EdgeLabel: "valueRelatedArtifact_resourceReference_PractitionerRole", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_PractitionerRole", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66513,15 +46786,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_ResearchStudy|ResearchStudy": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_ResearchStudy", + "Task|requestedPerformer_reference_ResearchStudy|ResearchStudy": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_ResearchStudy", ToType: "ResearchStudy", Direction: []string{ "outbound", @@ -66530,16 +46803,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "ResearchStudy|valueRelatedArtifact_resourceReference_ResearchStudy|TaskOutput": { + "ResearchStudy|requestedPerformer_reference_ResearchStudy|Task": { FromType: "ResearchStudy", - EdgeLabel: "valueRelatedArtifact_resourceReference_ResearchStudy", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_ResearchStudy", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66547,15 +46820,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "ResearchStudy/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_Patient|Patient": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Patient", + "Task|requestedPerformer_reference_Patient|Patient": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_Patient", ToType: "Patient", Direction: []string{ "outbound", @@ -66564,16 +46837,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Patient/*", }, }, - "Patient|valueRelatedArtifact_resourceReference_Patient|TaskOutput": { + "Patient|requestedPerformer_reference_Patient|Task": { FromType: "Patient", - EdgeLabel: "valueRelatedArtifact_resourceReference_Patient", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_Patient", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66581,15 +46854,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Patient/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_ResearchSubject|ResearchSubject": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_ResearchSubject", + "Task|requestedPerformer_reference_ResearchSubject|ResearchSubject": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_ResearchSubject", ToType: "ResearchSubject", Direction: []string{ "outbound", @@ -66598,16 +46871,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "ResearchSubject|valueRelatedArtifact_resourceReference_ResearchSubject|TaskOutput": { + "ResearchSubject|requestedPerformer_reference_ResearchSubject|Task": { FromType: "ResearchSubject", - EdgeLabel: "valueRelatedArtifact_resourceReference_ResearchSubject", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_ResearchSubject", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66615,15 +46888,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "ResearchSubject/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_Substance|Substance": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Substance", + "Task|requestedPerformer_reference_Substance|Substance": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_Substance", ToType: "Substance", Direction: []string{ "outbound", @@ -66632,16 +46905,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Substance/*", }, }, - "Substance|valueRelatedArtifact_resourceReference_Substance|TaskOutput": { + "Substance|requestedPerformer_reference_Substance|Task": { FromType: "Substance", - EdgeLabel: "valueRelatedArtifact_resourceReference_Substance", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_Substance", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66649,15 +46922,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Substance/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_SubstanceDefinition|SubstanceDefinition": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_SubstanceDefinition", + "Task|requestedPerformer_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_SubstanceDefinition", ToType: "SubstanceDefinition", Direction: []string{ "outbound", @@ -66666,16 +46939,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "SubstanceDefinition|valueRelatedArtifact_resourceReference_SubstanceDefinition|TaskOutput": { + "SubstanceDefinition|requestedPerformer_reference_SubstanceDefinition|Task": { FromType: "SubstanceDefinition", - EdgeLabel: "valueRelatedArtifact_resourceReference_SubstanceDefinition", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_SubstanceDefinition", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66683,15 +46956,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "SubstanceDefinition/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_Specimen|Specimen": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Specimen", + "Task|requestedPerformer_reference_Specimen|Specimen": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_Specimen", ToType: "Specimen", Direction: []string{ "outbound", @@ -66700,16 +46973,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Specimen/*", }, }, - "Specimen|valueRelatedArtifact_resourceReference_Specimen|TaskOutput": { + "Specimen|requestedPerformer_reference_Specimen|Task": { FromType: "Specimen", - EdgeLabel: "valueRelatedArtifact_resourceReference_Specimen", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_Specimen", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66717,15 +46990,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Specimen/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_Observation|Observation": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Observation", + "Task|requestedPerformer_reference_Observation|Observation": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_Observation", ToType: "Observation", Direction: []string{ "outbound", @@ -66734,16 +47007,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Observation/*", }, }, - "Observation|valueRelatedArtifact_resourceReference_Observation|TaskOutput": { + "Observation|requestedPerformer_reference_Observation|Task": { FromType: "Observation", - EdgeLabel: "valueRelatedArtifact_resourceReference_Observation", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_Observation", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66751,15 +47024,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Observation/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_DiagnosticReport|DiagnosticReport": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_DiagnosticReport", + "Task|requestedPerformer_reference_DiagnosticReport|DiagnosticReport": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_DiagnosticReport", ToType: "DiagnosticReport", Direction: []string{ "outbound", @@ -66768,16 +47041,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "DiagnosticReport|valueRelatedArtifact_resourceReference_DiagnosticReport|TaskOutput": { + "DiagnosticReport|requestedPerformer_reference_DiagnosticReport|Task": { FromType: "DiagnosticReport", - EdgeLabel: "valueRelatedArtifact_resourceReference_DiagnosticReport", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_DiagnosticReport", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66785,15 +47058,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "DiagnosticReport/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_Condition|Condition": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Condition", + "Task|requestedPerformer_reference_Condition|Condition": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_Condition", ToType: "Condition", Direction: []string{ "outbound", @@ -66802,16 +47075,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Condition/*", }, }, - "Condition|valueRelatedArtifact_resourceReference_Condition|TaskOutput": { + "Condition|requestedPerformer_reference_Condition|Task": { FromType: "Condition", - EdgeLabel: "valueRelatedArtifact_resourceReference_Condition", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_Condition", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66819,15 +47092,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Condition/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_Medication|Medication": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Medication", + "Task|requestedPerformer_reference_Medication|Medication": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_Medication", ToType: "Medication", Direction: []string{ "outbound", @@ -66836,16 +47109,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Medication/*", }, }, - "Medication|valueRelatedArtifact_resourceReference_Medication|TaskOutput": { + "Medication|requestedPerformer_reference_Medication|Task": { FromType: "Medication", - EdgeLabel: "valueRelatedArtifact_resourceReference_Medication", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_Medication", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66853,15 +47126,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Medication/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_MedicationAdministration|MedicationAdministration": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_MedicationAdministration", + "Task|requestedPerformer_reference_MedicationAdministration|MedicationAdministration": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_MedicationAdministration", ToType: "MedicationAdministration", Direction: []string{ "outbound", @@ -66870,16 +47143,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "MedicationAdministration|valueRelatedArtifact_resourceReference_MedicationAdministration|TaskOutput": { + "MedicationAdministration|requestedPerformer_reference_MedicationAdministration|Task": { FromType: "MedicationAdministration", - EdgeLabel: "valueRelatedArtifact_resourceReference_MedicationAdministration", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_MedicationAdministration", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66887,15 +47160,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "MedicationAdministration/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_MedicationStatement|MedicationStatement": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_MedicationStatement", + "Task|requestedPerformer_reference_MedicationStatement|MedicationStatement": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_MedicationStatement", ToType: "MedicationStatement", Direction: []string{ "outbound", @@ -66904,16 +47177,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "MedicationStatement|valueRelatedArtifact_resourceReference_MedicationStatement|TaskOutput": { + "MedicationStatement|requestedPerformer_reference_MedicationStatement|Task": { FromType: "MedicationStatement", - EdgeLabel: "valueRelatedArtifact_resourceReference_MedicationStatement", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_MedicationStatement", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66921,15 +47194,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "MedicationStatement/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_MedicationRequest|MedicationRequest": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_MedicationRequest", + "Task|requestedPerformer_reference_MedicationRequest|MedicationRequest": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_MedicationRequest", ToType: "MedicationRequest", Direction: []string{ "outbound", @@ -66938,16 +47211,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "MedicationRequest|valueRelatedArtifact_resourceReference_MedicationRequest|TaskOutput": { + "MedicationRequest|requestedPerformer_reference_MedicationRequest|Task": { FromType: "MedicationRequest", - EdgeLabel: "valueRelatedArtifact_resourceReference_MedicationRequest", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_MedicationRequest", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66955,15 +47228,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "MedicationRequest/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_Procedure|Procedure": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Procedure", + "Task|requestedPerformer_reference_Procedure|Procedure": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_Procedure", ToType: "Procedure", Direction: []string{ "outbound", @@ -66972,16 +47245,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Procedure/*", }, }, - "Procedure|valueRelatedArtifact_resourceReference_Procedure|TaskOutput": { + "Procedure|requestedPerformer_reference_Procedure|Task": { FromType: "Procedure", - EdgeLabel: "valueRelatedArtifact_resourceReference_Procedure", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_Procedure", + ToType: "Task", Direction: []string{ "outbound", }, @@ -66989,15 +47262,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "Procedure/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_DocumentReference|DocumentReference": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_DocumentReference", + "Task|requestedPerformer_reference_DocumentReference|DocumentReference": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_DocumentReference", ToType: "DocumentReference", Direction: []string{ "outbound", @@ -67006,16 +47279,118 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ "DocumentReference/*", }, }, - "DocumentReference|valueRelatedArtifact_resourceReference_DocumentReference|TaskOutput": { + "DocumentReference|requestedPerformer_reference_DocumentReference|Task": { FromType: "DocumentReference", - EdgeLabel: "valueRelatedArtifact_resourceReference_DocumentReference", - ToType: "TaskOutput", + EdgeLabel: "requestedPerformer_reference_DocumentReference", + ToType: "Task", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "DocumentReference/*", + }, + }, + "Task|requestedPerformer_reference_Task|Task": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_Task", + ToType: "Task", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "Task/*", + }, + }, + "Task|requestedPerformer_reference_ImagingStudy|ImagingStudy": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_ImagingStudy", + ToType: "ImagingStudy", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "ImagingStudy/*", + }, + }, + "ImagingStudy|requestedPerformer_reference_ImagingStudy|Task": { + FromType: "ImagingStudy", + EdgeLabel: "requestedPerformer_reference_ImagingStudy", + ToType: "Task", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "ImagingStudy/*", + }, + }, + "Task|requestedPerformer_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_FamilyMemberHistory", + ToType: "FamilyMemberHistory", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "FamilyMemberHistory/*", + }, + }, + "FamilyMemberHistory|requestedPerformer_reference_FamilyMemberHistory|Task": { + FromType: "FamilyMemberHistory", + EdgeLabel: "requestedPerformer_reference_FamilyMemberHistory", + ToType: "Task", + Direction: []string{ + "outbound", + }, + Multiplicity: []string{ + "has_one", + }, + Backref: []string{ + "codeable_reference", + }, + RegexMatch: []string{ + "FamilyMemberHistory/*", + }, + }, + "Task|requestedPerformer_reference_BodyStructure|BodyStructure": { + FromType: "Task", + EdgeLabel: "requestedPerformer_reference_BodyStructure", + ToType: "BodyStructure", Direction: []string{ "outbound", }, @@ -67023,15 +47398,15 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ - "DocumentReference/*", + "BodyStructure/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_Task|Task": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_Task", + "BodyStructure|requestedPerformer_reference_BodyStructure|Task": { + FromType: "BodyStructure", + EdgeLabel: "requestedPerformer_reference_BodyStructure", ToType: "Task", Direction: []string{ "outbound", @@ -67040,186 +47415,186 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "related_artifact", + "codeable_reference", }, RegexMatch: []string{ - "Task/*", + "BodyStructure/*", }, }, - "Task|valueRelatedArtifact_resourceReference_Task|TaskOutput": { + "Task|restriction_recipient_Patient|Patient": { FromType: "Task", - EdgeLabel: "valueRelatedArtifact_resourceReference_Task", - ToType: "TaskOutput", + EdgeLabel: "restriction_recipient_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "recipient_task_restriction", }, RegexMatch: []string{ - "Task/*", + "Patient/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_ImagingStudy|ImagingStudy": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_ImagingStudy", - ToType: "ImagingStudy", + "Patient|restriction_recipient_Patient|Task": { + FromType: "Patient", + EdgeLabel: "restriction_recipient_Patient", + ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "recipient_task_restriction", }, RegexMatch: []string{ - "ImagingStudy/*", + "Patient/*", }, }, - "ImagingStudy|valueRelatedArtifact_resourceReference_ImagingStudy|TaskOutput": { - FromType: "ImagingStudy", - EdgeLabel: "valueRelatedArtifact_resourceReference_ImagingStudy", - ToType: "TaskOutput", + "Task|restriction_recipient_Practitioner|Practitioner": { + FromType: "Task", + EdgeLabel: "restriction_recipient_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "recipient_task_restriction", }, RegexMatch: []string{ - "ImagingStudy/*", + "Practitioner/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_FamilyMemberHistory|FamilyMemberHistory": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_FamilyMemberHistory", - ToType: "FamilyMemberHistory", + "Practitioner|restriction_recipient_Practitioner|Task": { + FromType: "Practitioner", + EdgeLabel: "restriction_recipient_Practitioner", + ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "recipient_task_restriction", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "Practitioner/*", }, }, - "FamilyMemberHistory|valueRelatedArtifact_resourceReference_FamilyMemberHistory|TaskOutput": { - FromType: "FamilyMemberHistory", - EdgeLabel: "valueRelatedArtifact_resourceReference_FamilyMemberHistory", - ToType: "TaskOutput", + "Task|restriction_recipient_PractitionerRole|PractitionerRole": { + FromType: "Task", + EdgeLabel: "restriction_recipient_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "recipient_task_restriction", }, RegexMatch: []string{ - "FamilyMemberHistory/*", + "PractitionerRole/*", }, }, - "TaskOutput|valueRelatedArtifact_resourceReference_BodyStructure|BodyStructure": { - FromType: "TaskOutput", - EdgeLabel: "valueRelatedArtifact_resourceReference_BodyStructure", - ToType: "BodyStructure", + "PractitionerRole|restriction_recipient_PractitionerRole|Task": { + FromType: "PractitionerRole", + EdgeLabel: "restriction_recipient_PractitionerRole", + ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "recipient_task_restriction", }, RegexMatch: []string{ - "BodyStructure/*", + "PractitionerRole/*", }, }, - "BodyStructure|valueRelatedArtifact_resourceReference_BodyStructure|TaskOutput": { - FromType: "BodyStructure", - EdgeLabel: "valueRelatedArtifact_resourceReference_BodyStructure", - ToType: "TaskOutput", + "Task|restriction_recipient_Group|Group": { + FromType: "Task", + EdgeLabel: "restriction_recipient_Group", + ToType: "Group", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "related_artifact", + "recipient_task_restriction", }, RegexMatch: []string{ - "BodyStructure/*", + "Group/*", }, }, - "TaskOutput|valueSignature_onBehalfOf_Practitioner|Practitioner": { - FromType: "TaskOutput", - EdgeLabel: "valueSignature_onBehalfOf_Practitioner", - ToType: "Practitioner", + "Group|restriction_recipient_Group|Task": { + FromType: "Group", + EdgeLabel: "restriction_recipient_Group", + ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "onBehalfOf_signature", + "recipient_task_restriction", }, RegexMatch: []string{ - "Practitioner/*", + "Group/*", }, }, - "Practitioner|valueSignature_onBehalfOf_Practitioner|TaskOutput": { - FromType: "Practitioner", - EdgeLabel: "valueSignature_onBehalfOf_Practitioner", - ToType: "TaskOutput", + "Task|restriction_recipient_Organization|Organization": { + FromType: "Task", + EdgeLabel: "restriction_recipient_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "onBehalfOf_signature", + "recipient_task_restriction", }, RegexMatch: []string{ - "Practitioner/*", + "Organization/*", }, }, - "TaskOutput|valueSignature_onBehalfOf_PractitionerRole|PractitionerRole": { - FromType: "TaskOutput", - EdgeLabel: "valueSignature_onBehalfOf_PractitionerRole", - ToType: "PractitionerRole", + "Organization|restriction_recipient_Organization|Task": { + FromType: "Organization", + EdgeLabel: "restriction_recipient_Organization", + ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_one", + "has_many", }, Backref: []string{ - "onBehalfOf_signature", + "recipient_task_restriction", }, RegexMatch: []string{ - "PractitionerRole/*", + "Organization/*", }, }, - "PractitionerRole|valueSignature_onBehalfOf_PractitionerRole|TaskOutput": { - FromType: "PractitionerRole", - EdgeLabel: "valueSignature_onBehalfOf_PractitionerRole", - ToType: "TaskOutput", + "Task|statusReason_reference_Organization|Organization": { + FromType: "Task", + EdgeLabel: "statusReason_reference_Organization", + ToType: "Organization", Direction: []string{ "outbound", }, @@ -67227,16 +47602,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "onBehalfOf_signature", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Organization/*", }, }, - "TaskOutput|valueSignature_onBehalfOf_Patient|Patient": { - FromType: "TaskOutput", - EdgeLabel: "valueSignature_onBehalfOf_Patient", - ToType: "Patient", + "Organization|statusReason_reference_Organization|Task": { + FromType: "Organization", + EdgeLabel: "statusReason_reference_Organization", + ToType: "Task", Direction: []string{ "outbound", }, @@ -67244,16 +47619,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "onBehalfOf_signature", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "Organization/*", }, }, - "Patient|valueSignature_onBehalfOf_Patient|TaskOutput": { - FromType: "Patient", - EdgeLabel: "valueSignature_onBehalfOf_Patient", - ToType: "TaskOutput", + "Task|statusReason_reference_Group|Group": { + FromType: "Task", + EdgeLabel: "statusReason_reference_Group", + ToType: "Group", Direction: []string{ "outbound", }, @@ -67261,16 +47636,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "onBehalfOf_signature", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "Group/*", }, }, - "TaskOutput|valueSignature_onBehalfOf_Organization|Organization": { - FromType: "TaskOutput", - EdgeLabel: "valueSignature_onBehalfOf_Organization", - ToType: "Organization", + "Group|statusReason_reference_Group|Task": { + FromType: "Group", + EdgeLabel: "statusReason_reference_Group", + ToType: "Task", Direction: []string{ "outbound", }, @@ -67278,16 +47653,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "onBehalfOf_signature", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Group/*", }, }, - "Organization|valueSignature_onBehalfOf_Organization|TaskOutput": { - FromType: "Organization", - EdgeLabel: "valueSignature_onBehalfOf_Organization", - ToType: "TaskOutput", + "Task|statusReason_reference_Practitioner|Practitioner": { + FromType: "Task", + EdgeLabel: "statusReason_reference_Practitioner", + ToType: "Practitioner", Direction: []string{ "outbound", }, @@ -67295,16 +47670,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "onBehalfOf_signature", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Practitioner/*", }, }, - "TaskOutput|valueSignature_who_Practitioner|Practitioner": { - FromType: "TaskOutput", - EdgeLabel: "valueSignature_who_Practitioner", - ToType: "Practitioner", + "Practitioner|statusReason_reference_Practitioner|Task": { + FromType: "Practitioner", + EdgeLabel: "statusReason_reference_Practitioner", + ToType: "Task", Direction: []string{ "outbound", }, @@ -67312,16 +47687,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "codeable_reference", }, RegexMatch: []string{ "Practitioner/*", }, }, - "Practitioner|valueSignature_who_Practitioner|TaskOutput": { - FromType: "Practitioner", - EdgeLabel: "valueSignature_who_Practitioner", - ToType: "TaskOutput", + "Task|statusReason_reference_PractitionerRole|PractitionerRole": { + FromType: "Task", + EdgeLabel: "statusReason_reference_PractitionerRole", + ToType: "PractitionerRole", Direction: []string{ "outbound", }, @@ -67329,16 +47704,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "PractitionerRole/*", }, }, - "TaskOutput|valueSignature_who_PractitionerRole|PractitionerRole": { - FromType: "TaskOutput", - EdgeLabel: "valueSignature_who_PractitionerRole", - ToType: "PractitionerRole", + "PractitionerRole|statusReason_reference_PractitionerRole|Task": { + FromType: "PractitionerRole", + EdgeLabel: "statusReason_reference_PractitionerRole", + ToType: "Task", Direction: []string{ "outbound", }, @@ -67346,16 +47721,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "codeable_reference", }, RegexMatch: []string{ "PractitionerRole/*", }, }, - "PractitionerRole|valueSignature_who_PractitionerRole|TaskOutput": { - FromType: "PractitionerRole", - EdgeLabel: "valueSignature_who_PractitionerRole", - ToType: "TaskOutput", + "Task|statusReason_reference_ResearchStudy|ResearchStudy": { + FromType: "Task", + EdgeLabel: "statusReason_reference_ResearchStudy", + ToType: "ResearchStudy", Direction: []string{ "outbound", }, @@ -67363,16 +47738,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "ResearchStudy/*", }, }, - "TaskOutput|valueSignature_who_Patient|Patient": { - FromType: "TaskOutput", - EdgeLabel: "valueSignature_who_Patient", - ToType: "Patient", + "ResearchStudy|statusReason_reference_ResearchStudy|Task": { + FromType: "ResearchStudy", + EdgeLabel: "statusReason_reference_ResearchStudy", + ToType: "Task", Direction: []string{ "outbound", }, @@ -67380,16 +47755,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "ResearchStudy/*", }, }, - "Patient|valueSignature_who_Patient|TaskOutput": { - FromType: "Patient", - EdgeLabel: "valueSignature_who_Patient", - ToType: "TaskOutput", + "Task|statusReason_reference_Patient|Patient": { + FromType: "Task", + EdgeLabel: "statusReason_reference_Patient", + ToType: "Patient", Direction: []string{ "outbound", }, @@ -67397,16 +47772,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "codeable_reference", }, RegexMatch: []string{ "Patient/*", }, }, - "TaskOutput|valueSignature_who_Organization|Organization": { - FromType: "TaskOutput", - EdgeLabel: "valueSignature_who_Organization", - ToType: "Organization", + "Patient|statusReason_reference_Patient|Task": { + FromType: "Patient", + EdgeLabel: "statusReason_reference_Patient", + ToType: "Task", Direction: []string{ "outbound", }, @@ -67414,16 +47789,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Patient/*", }, }, - "Organization|valueSignature_who_Organization|TaskOutput": { - FromType: "Organization", - EdgeLabel: "valueSignature_who_Organization", - ToType: "TaskOutput", + "Task|statusReason_reference_ResearchSubject|ResearchSubject": { + FromType: "Task", + EdgeLabel: "statusReason_reference_ResearchSubject", + ToType: "ResearchSubject", Direction: []string{ "outbound", }, @@ -67431,16 +47806,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "who_signature", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "ResearchSubject/*", }, }, - "TaskOutput|valueUsageContext_valueReference_ResearchStudy|ResearchStudy": { - FromType: "TaskOutput", - EdgeLabel: "valueUsageContext_valueReference_ResearchStudy", - ToType: "ResearchStudy", + "ResearchSubject|statusReason_reference_ResearchSubject|Task": { + FromType: "ResearchSubject", + EdgeLabel: "statusReason_reference_ResearchSubject", + ToType: "Task", Direction: []string{ "outbound", }, @@ -67448,16 +47823,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "codeable_reference", }, RegexMatch: []string{ - "ResearchStudy/*", + "ResearchSubject/*", }, }, - "ResearchStudy|valueUsageContext_valueReference_ResearchStudy|TaskOutput": { - FromType: "ResearchStudy", - EdgeLabel: "valueUsageContext_valueReference_ResearchStudy", - ToType: "TaskOutput", + "Task|statusReason_reference_Substance|Substance": { + FromType: "Task", + EdgeLabel: "statusReason_reference_Substance", + ToType: "Substance", Direction: []string{ "outbound", }, @@ -67465,16 +47840,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "codeable_reference", }, RegexMatch: []string{ - "ResearchStudy/*", + "Substance/*", }, }, - "TaskOutput|valueUsageContext_valueReference_Group|Group": { - FromType: "TaskOutput", - EdgeLabel: "valueUsageContext_valueReference_Group", - ToType: "Group", + "Substance|statusReason_reference_Substance|Task": { + FromType: "Substance", + EdgeLabel: "statusReason_reference_Substance", + ToType: "Task", Direction: []string{ "outbound", }, @@ -67482,16 +47857,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "Substance/*", }, }, - "Group|valueUsageContext_valueReference_Group|TaskOutput": { - FromType: "Group", - EdgeLabel: "valueUsageContext_valueReference_Group", - ToType: "TaskOutput", + "Task|statusReason_reference_SubstanceDefinition|SubstanceDefinition": { + FromType: "Task", + EdgeLabel: "statusReason_reference_SubstanceDefinition", + ToType: "SubstanceDefinition", Direction: []string{ "outbound", }, @@ -67499,16 +47874,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "SubstanceDefinition/*", }, }, - "TaskOutput|valueUsageContext_valueReference_Organization|Organization": { - FromType: "TaskOutput", - EdgeLabel: "valueUsageContext_valueReference_Organization", - ToType: "Organization", + "SubstanceDefinition|statusReason_reference_SubstanceDefinition|Task": { + FromType: "SubstanceDefinition", + EdgeLabel: "statusReason_reference_SubstanceDefinition", + ToType: "Task", Direction: []string{ "outbound", }, @@ -67516,16 +47891,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "SubstanceDefinition/*", }, }, - "Organization|valueUsageContext_valueReference_Organization|TaskOutput": { - FromType: "Organization", - EdgeLabel: "valueUsageContext_valueReference_Organization", - ToType: "TaskOutput", + "Task|statusReason_reference_Specimen|Specimen": { + FromType: "Task", + EdgeLabel: "statusReason_reference_Specimen", + ToType: "Specimen", Direction: []string{ "outbound", }, @@ -67533,16 +47908,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Specimen/*", }, }, - "TaskPerformer|actor_Practitioner|Practitioner": { - FromType: "TaskPerformer", - EdgeLabel: "actor_Practitioner", - ToType: "Practitioner", + "Specimen|statusReason_reference_Specimen|Task": { + FromType: "Specimen", + EdgeLabel: "statusReason_reference_Specimen", + ToType: "Task", Direction: []string{ "outbound", }, @@ -67550,16 +47925,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_performer", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Specimen/*", }, }, - "Practitioner|actor_Practitioner|TaskPerformer": { - FromType: "Practitioner", - EdgeLabel: "actor_Practitioner", - ToType: "TaskPerformer", + "Task|statusReason_reference_Observation|Observation": { + FromType: "Task", + EdgeLabel: "statusReason_reference_Observation", + ToType: "Observation", Direction: []string{ "outbound", }, @@ -67567,16 +47942,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_performer", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "Observation/*", }, }, - "TaskPerformer|actor_PractitionerRole|PractitionerRole": { - FromType: "TaskPerformer", - EdgeLabel: "actor_PractitionerRole", - ToType: "PractitionerRole", + "Observation|statusReason_reference_Observation|Task": { + FromType: "Observation", + EdgeLabel: "statusReason_reference_Observation", + ToType: "Task", Direction: []string{ "outbound", }, @@ -67584,16 +47959,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_performer", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "Observation/*", }, }, - "PractitionerRole|actor_PractitionerRole|TaskPerformer": { - FromType: "PractitionerRole", - EdgeLabel: "actor_PractitionerRole", - ToType: "TaskPerformer", + "Task|statusReason_reference_DiagnosticReport|DiagnosticReport": { + FromType: "Task", + EdgeLabel: "statusReason_reference_DiagnosticReport", + ToType: "DiagnosticReport", Direction: []string{ "outbound", }, @@ -67601,16 +47976,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_performer", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "DiagnosticReport/*", }, }, - "TaskPerformer|actor_Organization|Organization": { - FromType: "TaskPerformer", - EdgeLabel: "actor_Organization", - ToType: "Organization", + "DiagnosticReport|statusReason_reference_DiagnosticReport|Task": { + FromType: "DiagnosticReport", + EdgeLabel: "statusReason_reference_DiagnosticReport", + ToType: "Task", Direction: []string{ "outbound", }, @@ -67618,16 +47993,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_performer", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "DiagnosticReport/*", }, }, - "Organization|actor_Organization|TaskPerformer": { - FromType: "Organization", - EdgeLabel: "actor_Organization", - ToType: "TaskPerformer", + "Task|statusReason_reference_Condition|Condition": { + FromType: "Task", + EdgeLabel: "statusReason_reference_Condition", + ToType: "Condition", Direction: []string{ "outbound", }, @@ -67635,16 +48010,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_performer", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Condition/*", }, }, - "TaskPerformer|actor_Patient|Patient": { - FromType: "TaskPerformer", - EdgeLabel: "actor_Patient", - ToType: "Patient", + "Condition|statusReason_reference_Condition|Task": { + FromType: "Condition", + EdgeLabel: "statusReason_reference_Condition", + ToType: "Task", Direction: []string{ "outbound", }, @@ -67652,16 +48027,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_performer", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "Condition/*", }, }, - "Patient|actor_Patient|TaskPerformer": { - FromType: "Patient", - EdgeLabel: "actor_Patient", - ToType: "TaskPerformer", + "Task|statusReason_reference_Medication|Medication": { + FromType: "Task", + EdgeLabel: "statusReason_reference_Medication", + ToType: "Medication", Direction: []string{ "outbound", }, @@ -67669,186 +48044,186 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "task_performer", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "Medication/*", }, }, - "TaskRestriction|recipient_Patient|Patient": { - FromType: "TaskRestriction", - EdgeLabel: "recipient_Patient", - ToType: "Patient", + "Medication|statusReason_reference_Medication|Task": { + FromType: "Medication", + EdgeLabel: "statusReason_reference_Medication", + ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "recipient_task_restriction", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "Medication/*", }, }, - "Patient|recipient_Patient|TaskRestriction": { - FromType: "Patient", - EdgeLabel: "recipient_Patient", - ToType: "TaskRestriction", + "Task|statusReason_reference_MedicationAdministration|MedicationAdministration": { + FromType: "Task", + EdgeLabel: "statusReason_reference_MedicationAdministration", + ToType: "MedicationAdministration", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "recipient_task_restriction", + "codeable_reference", }, RegexMatch: []string{ - "Patient/*", + "MedicationAdministration/*", }, }, - "TaskRestriction|recipient_Practitioner|Practitioner": { - FromType: "TaskRestriction", - EdgeLabel: "recipient_Practitioner", - ToType: "Practitioner", + "MedicationAdministration|statusReason_reference_MedicationAdministration|Task": { + FromType: "MedicationAdministration", + EdgeLabel: "statusReason_reference_MedicationAdministration", + ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "recipient_task_restriction", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "MedicationAdministration/*", }, }, - "Practitioner|recipient_Practitioner|TaskRestriction": { - FromType: "Practitioner", - EdgeLabel: "recipient_Practitioner", - ToType: "TaskRestriction", + "Task|statusReason_reference_MedicationStatement|MedicationStatement": { + FromType: "Task", + EdgeLabel: "statusReason_reference_MedicationStatement", + ToType: "MedicationStatement", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "recipient_task_restriction", + "codeable_reference", }, RegexMatch: []string{ - "Practitioner/*", + "MedicationStatement/*", }, }, - "TaskRestriction|recipient_PractitionerRole|PractitionerRole": { - FromType: "TaskRestriction", - EdgeLabel: "recipient_PractitionerRole", - ToType: "PractitionerRole", + "MedicationStatement|statusReason_reference_MedicationStatement|Task": { + FromType: "MedicationStatement", + EdgeLabel: "statusReason_reference_MedicationStatement", + ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "recipient_task_restriction", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "MedicationStatement/*", }, }, - "PractitionerRole|recipient_PractitionerRole|TaskRestriction": { - FromType: "PractitionerRole", - EdgeLabel: "recipient_PractitionerRole", - ToType: "TaskRestriction", + "Task|statusReason_reference_MedicationRequest|MedicationRequest": { + FromType: "Task", + EdgeLabel: "statusReason_reference_MedicationRequest", + ToType: "MedicationRequest", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "recipient_task_restriction", + "codeable_reference", }, RegexMatch: []string{ - "PractitionerRole/*", + "MedicationRequest/*", }, }, - "TaskRestriction|recipient_Group|Group": { - FromType: "TaskRestriction", - EdgeLabel: "recipient_Group", - ToType: "Group", + "MedicationRequest|statusReason_reference_MedicationRequest|Task": { + FromType: "MedicationRequest", + EdgeLabel: "statusReason_reference_MedicationRequest", + ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "recipient_task_restriction", + "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "MedicationRequest/*", }, }, - "Group|recipient_Group|TaskRestriction": { - FromType: "Group", - EdgeLabel: "recipient_Group", - ToType: "TaskRestriction", + "Task|statusReason_reference_Procedure|Procedure": { + FromType: "Task", + EdgeLabel: "statusReason_reference_Procedure", + ToType: "Procedure", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "recipient_task_restriction", + "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "Procedure/*", }, }, - "TaskRestriction|recipient_Organization|Organization": { - FromType: "TaskRestriction", - EdgeLabel: "recipient_Organization", - ToType: "Organization", + "Procedure|statusReason_reference_Procedure|Task": { + FromType: "Procedure", + EdgeLabel: "statusReason_reference_Procedure", + ToType: "Task", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "recipient_task_restriction", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "Procedure/*", }, }, - "Organization|recipient_Organization|TaskRestriction": { - FromType: "Organization", - EdgeLabel: "recipient_Organization", - ToType: "TaskRestriction", + "Task|statusReason_reference_DocumentReference|DocumentReference": { + FromType: "Task", + EdgeLabel: "statusReason_reference_DocumentReference", + ToType: "DocumentReference", Direction: []string{ "outbound", }, Multiplicity: []string{ - "has_many", + "has_one", }, Backref: []string{ - "recipient_task_restriction", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "DocumentReference/*", }, }, - "TriggerDefinition|data_subjectReference|Group": { - FromType: "TriggerDefinition", - EdgeLabel: "data_subjectReference", - ToType: "Group", + "DocumentReference|statusReason_reference_DocumentReference|Task": { + FromType: "DocumentReference", + EdgeLabel: "statusReason_reference_DocumentReference", + ToType: "Task", Direction: []string{ "outbound", }, @@ -67856,16 +48231,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "data_requirement", + "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "DocumentReference/*", }, }, - "Group|data_subjectReference|TriggerDefinition": { - FromType: "Group", - EdgeLabel: "data_subjectReference", - ToType: "TriggerDefinition", + "Task|statusReason_reference_Task|Task": { + FromType: "Task", + EdgeLabel: "statusReason_reference_Task", + ToType: "Task", Direction: []string{ "outbound", }, @@ -67873,16 +48248,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "data_requirement", + "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "Task/*", }, }, - "UsageContext|valueReference_ResearchStudy|ResearchStudy": { - FromType: "UsageContext", - EdgeLabel: "valueReference_ResearchStudy", - ToType: "ResearchStudy", + "Task|statusReason_reference_ImagingStudy|ImagingStudy": { + FromType: "Task", + EdgeLabel: "statusReason_reference_ImagingStudy", + ToType: "ImagingStudy", Direction: []string{ "outbound", }, @@ -67890,16 +48265,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "codeable_reference", }, RegexMatch: []string{ - "ResearchStudy/*", + "ImagingStudy/*", }, }, - "ResearchStudy|valueReference_ResearchStudy|UsageContext": { - FromType: "ResearchStudy", - EdgeLabel: "valueReference_ResearchStudy", - ToType: "UsageContext", + "ImagingStudy|statusReason_reference_ImagingStudy|Task": { + FromType: "ImagingStudy", + EdgeLabel: "statusReason_reference_ImagingStudy", + ToType: "Task", Direction: []string{ "outbound", }, @@ -67907,16 +48282,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "codeable_reference", }, RegexMatch: []string{ - "ResearchStudy/*", + "ImagingStudy/*", }, }, - "UsageContext|valueReference_Group|Group": { - FromType: "UsageContext", - EdgeLabel: "valueReference_Group", - ToType: "Group", + "Task|statusReason_reference_FamilyMemberHistory|FamilyMemberHistory": { + FromType: "Task", + EdgeLabel: "statusReason_reference_FamilyMemberHistory", + ToType: "FamilyMemberHistory", Direction: []string{ "outbound", }, @@ -67924,16 +48299,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "FamilyMemberHistory/*", }, }, - "Group|valueReference_Group|UsageContext": { - FromType: "Group", - EdgeLabel: "valueReference_Group", - ToType: "UsageContext", + "FamilyMemberHistory|statusReason_reference_FamilyMemberHistory|Task": { + FromType: "FamilyMemberHistory", + EdgeLabel: "statusReason_reference_FamilyMemberHistory", + ToType: "Task", Direction: []string{ "outbound", }, @@ -67941,16 +48316,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "codeable_reference", }, RegexMatch: []string{ - "Group/*", + "FamilyMemberHistory/*", }, }, - "UsageContext|valueReference_Organization|Organization": { - FromType: "UsageContext", - EdgeLabel: "valueReference_Organization", - ToType: "Organization", + "Task|statusReason_reference_BodyStructure|BodyStructure": { + FromType: "Task", + EdgeLabel: "statusReason_reference_BodyStructure", + ToType: "BodyStructure", Direction: []string{ "outbound", }, @@ -67958,16 +48333,16 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "BodyStructure/*", }, }, - "Organization|valueReference_Organization|UsageContext": { - FromType: "Organization", - EdgeLabel: "valueReference_Organization", - ToType: "UsageContext", + "BodyStructure|statusReason_reference_BodyStructure|Task": { + FromType: "BodyStructure", + EdgeLabel: "statusReason_reference_BodyStructure", + ToType: "Task", Direction: []string{ "outbound", }, @@ -67975,10 +48350,10 @@ var Traversals = map[string]Traversal{ "has_one", }, Backref: []string{ - "usage_context", + "codeable_reference", }, RegexMatch: []string{ - "Organization/*", + "BodyStructure/*", }, }, } diff --git a/internal/api/http/errors.go b/internal/api/http/errors.go index 150f9506..12872b5f 100644 --- a/internal/api/http/errors.go +++ b/internal/api/http/errors.go @@ -154,7 +154,7 @@ func normalizeHTTPCode(code string) string { code = strings.ToUpper(strings.TrimSpace(code)) code = strings.ReplaceAll(code, "-", "_") switch code { - case "PROJECT_REQUIRED", "ROOT_RESOURCE_TYPE_REQUIRED", "UNAUTHORIZED_PROJECT", "UNKNOWN_FIELD", "FIELD_NOT_POPULATED", "INVALID_TRAVERSAL", "UNSAFE_TRAVERSAL_ROUTE", "INVALID_FILTER", "UNBOUNDED_PIVOT", "INVALID_PIVOT_COLUMN", "INVALID_SLICE", "PLAN_TOO_EXPENSIVE", "INVALID_CURSOR", "STALE_CURSOR", "DATASET_GENERATION_CHANGED", "UNSUPPORTED_EXPORT_FORMAT", "CLIENT_CANCELED", "BACKEND_UNAVAILABLE", "DATASET_NOT_FOUND", "SCHEMA_CONFLICT", "INVALID_RESOURCE_TYPE", "NO_ACTIVE_GENERATION", "RESOURCE_DECODE_FAILED", "REFERENCE_NOT_RESOLVED", "QUERY_DEPTH_EXCEEDED", "INVALID_REQUEST", "INVALID_DATA", "INVALID_SELECTOR", "UNAUTHENTICATED", "FORBIDDEN", "RECIPE_NOT_FOUND", "RECIPE_RESOLUTION_FAILED", "RECIPE_EXECUTION_NOT_FOUND", "EXPORT_LIMIT_EXCEEDED", "INGEST_PREFLIGHT_FAILED", "GENERATION_LOAD_INCOMPLETE", "GENERATION_ACTIVATION_UNKNOWN", "INVALID_GENERATION_FILE", "DUPLICATE_GENERATION_FILE", "PUBLICATION_IN_PROGRESS", "PUBLICATION_CONFLICT", "PUBLICATION_LEASE_LOST", "OUTPUT_ENCODING_FAILED", "NOT_FOUND", "METHOD_NOT_ALLOWED", "PAYLOAD_TOO_LARGE", "GRAPHQL_VALIDATION_FAILED": + case "PROJECT_REQUIRED", "ROOT_RESOURCE_TYPE_REQUIRED", "UNAUTHORIZED_PROJECT", "UNKNOWN_FIELD", "FIELD_NOT_POPULATED", "INVALID_TRAVERSAL", "UNSAFE_TRAVERSAL_ROUTE", "INVALID_FILTER", "UNBOUNDED_PIVOT", "INVALID_PIVOT_COLUMN", "INVALID_SLICE", "PLAN_TOO_EXPENSIVE", "INVALID_CURSOR", "STALE_CURSOR", "DATASET_GENERATION_CHANGED", "UNSUPPORTED_EXPORT_FORMAT", "CLIENT_CANCELED", "BACKEND_UNAVAILABLE", "RECEIPT_STORE_UNAVAILABLE", "PREVIEW_TIMEOUT", "PREVIEW_RESPONSE_TOO_LARGE", "DYNAMIC_SCHEMA_DRIFT", "RECIPE_CONTRACT_VIOLATION", "DATASET_NOT_FOUND", "SCHEMA_CONFLICT", "INVALID_RESOURCE_TYPE", "NO_ACTIVE_GENERATION", "RESOURCE_DECODE_FAILED", "REFERENCE_NOT_RESOLVED", "QUERY_DEPTH_EXCEEDED", "INVALID_REQUEST", "INVALID_DATA", "INVALID_SELECTOR", "UNAUTHENTICATED", "FORBIDDEN", "RECIPE_NOT_FOUND", "RECIPE_RESOLUTION_FAILED", "RECIPE_EXECUTION_NOT_FOUND", "EXPORT_LIMIT_EXCEEDED", "INGEST_PREFLIGHT_FAILED", "GENERATION_LOAD_INCOMPLETE", "GENERATION_ACTIVATION_UNKNOWN", "INVALID_GENERATION_FILE", "DUPLICATE_GENERATION_FILE", "PUBLICATION_IN_PROGRESS", "PUBLICATION_CONFLICT", "PUBLICATION_LEASE_LOST", "OUTPUT_ENCODING_FAILED", "NOT_FOUND", "METHOD_NOT_ALLOWED", "PAYLOAD_TOO_LARGE", "GRAPHQL_VALIDATION_FAILED": return code default: return "INTERNAL_ERROR" @@ -169,7 +169,7 @@ func statusForCode(code string, fallback int) int { return http.StatusForbidden case "DATASET_NOT_FOUND", "NO_ACTIVE_GENERATION", "RECIPE_NOT_FOUND", "RECIPE_EXECUTION_NOT_FOUND": return http.StatusNotFound - case "SCHEMA_CONFLICT", "STALE_CURSOR", "DATASET_GENERATION_CHANGED": + case "SCHEMA_CONFLICT", "STALE_CURSOR", "DATASET_GENERATION_CHANGED", "DYNAMIC_SCHEMA_DRIFT", "RECIPE_CONTRACT_VIOLATION": return http.StatusConflict case "INVALID_DATA", "RECIPE_RESOLUTION_FAILED", "INGEST_PREFLIGHT_FAILED", "GENERATION_LOAD_INCOMPLETE": return http.StatusUnprocessableEntity @@ -185,10 +185,16 @@ func statusForCode(code string, fallback int) int { return http.StatusInternalServerError case "EXPORT_LIMIT_EXCEEDED": return http.StatusRequestEntityTooLarge + case "PREVIEW_RESPONSE_TOO_LARGE": + return http.StatusRequestEntityTooLarge + case "PLAN_TOO_EXPENSIVE": + return http.StatusTooManyRequests case "UNSUPPORTED_MEDIA_TYPE": return http.StatusUnsupportedMediaType - case "BACKEND_UNAVAILABLE": + case "BACKEND_UNAVAILABLE", "RECEIPT_STORE_UNAVAILABLE": return http.StatusServiceUnavailable + case "PREVIEW_TIMEOUT": + return http.StatusGatewayTimeout case "CLIENT_CANCELED": return 499 case "INTERNAL_ERROR": diff --git a/internal/api/http/errors_test.go b/internal/api/http/errors_test.go index 06918617..dffa6659 100644 --- a/internal/api/http/errors_test.go +++ b/internal/api/http/errors_test.go @@ -60,6 +60,29 @@ func TestMapDataframeErrorBackendIsRetryable(t *testing.T) { } } +func TestMapDataframeErrorPreviewClassifications(t *testing.T) { + for _, test := range []struct { + code dataframeerrors.ErrorCode + status int + retryable bool + }{ + {dataframeerrors.CodePlanTooExpensive, http.StatusTooManyRequests, false}, + {dataframeerrors.CodeReceiptStoreUnavailable, http.StatusServiceUnavailable, true}, + {dataframeerrors.CodePreviewTimeout, http.StatusGatewayTimeout, true}, + {dataframeerrors.CodePreviewResponseTooLarge, http.StatusRequestEntityTooLarge, false}, + {dataframeerrors.CodeDynamicSchemaDrift, http.StatusConflict, false}, + {dataframeerrors.CodeRecipeContractViolation, http.StatusConflict, false}, + } { + mapped := MapDataframeError(dataframeerrors.NewError(test.code, "private", dataframeerrors.WithRetryable(test.retryable)), "req-preview") + if mapped.Status != test.status || mapped.Body.Error.Code != string(test.code) || mapped.Body.Error.Retryable != test.retryable { + t.Errorf("%s mapped = %#v", test.code, mapped) + } + if mapped.Body.Error.Message == "private" { + t.Errorf("%s leaked private message", test.code) + } + } +} + func TestMapDataframeErrorFiberStatus(t *testing.T) { for _, test := range []struct { err error diff --git a/internal/api/http/http_test.go b/internal/api/http/http_test.go index fe6cda90..fc2e7758 100644 --- a/internal/api/http/http_test.go +++ b/internal/api/http/http_test.go @@ -1,14 +1,18 @@ package httpapi import ( + "bytes" "context" "encoding/json" "errors" + "log/slog" "net/http" "net/http/httptest" + "strings" "testing" "github.com/calypr/loom/internal/authscope" + "github.com/gofiber/fiber/v3" ) func TestHealthDoesNotRequireAuthentication(t *testing.T) { @@ -150,3 +154,57 @@ func TestNewHTTPServerRequiresAuthorizer(t *testing.T) { t.Fatal("expected missing authorizer error") } } + +func TestLoggingMiddlewareEmitsStructuredResponseDiagnostics(t *testing.T) { + var logs bytes.Buffer + logger := slog.New(slog.NewTextHandler(&logs, &slog.HandlerOptions{Level: slog.LevelInfo})) + server, err := NewHTTPServer(HTTPConfig{ + Authenticator: authscope.StaticAuthenticator{}, + Authorizer: authscope.AllowAllAuthorizer{}, + Logger: logger, + }) + if err != nil { + t.Fatal(err) + } + server.App().Put("/authoring-failure", func(c fiber.Ctx) error { + return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{ + "error": fiber.Map{ + "code": "UNSUPPORTED_ROW_GRAIN", + "message": "the selected base resource has no supported row grain", + }, + "diagnostics": []fiber.Map{{ + "stage": "lower", + "code": "UNSUPPORTED_ROW_GRAIN", + "jsonPath": "$.document.baseNodeId", + "resourceType": "patient", + }}, + }) + }) + + request := httptest.NewRequest(http.MethodPut, "/authoring-failure?auth_resource_path=%2Fprograms%2FHTAN_INT%2Fprojects%2FBForePC", nil) + request.Header.Set("X-Request-ID", "request-diagnostic") + response, err := server.App().Test(request) + if err != nil { + t.Fatal(err) + } + response.Body.Close() + if response.StatusCode != http.StatusUnprocessableEntity { + t.Fatalf("status = %d, want 422", response.StatusCode) + } + + logText := logs.String() + for _, want := range []string{ + "http request failed", + "request_id=request-diagnostic", + "error_code=UNSUPPORTED_ROW_GRAIN", + "error_message=", + "supported row grain", + "error_diagnostics=", + "resourceType", + "patient", + } { + if !strings.Contains(logText, want) { + t.Fatalf("logs missing %q:\n%s", want, logText) + } + } +} diff --git a/internal/api/http/middleware.go b/internal/api/http/middleware.go index eefb903b..94059f59 100644 --- a/internal/api/http/middleware.go +++ b/internal/api/http/middleware.go @@ -1,6 +1,7 @@ package httpapi import ( + "encoding/json" "errors" "time" @@ -11,6 +12,59 @@ import ( "github.com/google/uuid" ) +const maxLoggedErrorResponseBytes = 32 * 1024 + +// errorResponseLogAttrs extracts the useful, server-owned diagnostic fields +// from responses that were already written by a handler. Authoring routes +// intentionally write their 4xx response and return nil, so the Fiber error +// handler cannot log the underlying diagnostic. Keeping this extraction in +// the request middleware gives every route the same failure visibility while +// bounding the raw packet retained in logs. +func errorResponseLogAttrs(body []byte) []any { + if len(body) == 0 { + return nil + } + logged := body + truncated := false + if len(logged) > maxLoggedErrorResponseBytes { + logged = logged[:maxLoggedErrorResponseBytes] + truncated = true + } + attrs := []any{"response_body", string(logged)} + if truncated { + attrs = append(attrs, "response_body_truncated", true, "response_body_bytes", len(body)) + } + + var envelope struct { + Error struct { + Code string `json:"code"` + Message string `json:"message"` + RequestID string `json:"requestId"` + Diagnostic json.RawMessage `json:"diagnostic"` + } `json:"error"` + Diagnostics json.RawMessage `json:"diagnostics"` + } + if err := json.Unmarshal(body, &envelope); err != nil { + return attrs + } + if envelope.Error.Code != "" { + attrs = append(attrs, "error_code", envelope.Error.Code) + } + if envelope.Error.Message != "" { + attrs = append(attrs, "error_message", envelope.Error.Message) + } + if envelope.Error.RequestID != "" { + attrs = append(attrs, "error_request_id", envelope.Error.RequestID) + } + if len(envelope.Error.Diagnostic) > 0 && string(envelope.Error.Diagnostic) != "null" { + attrs = append(attrs, "error_diagnostic", string(envelope.Error.Diagnostic)) + } + if len(envelope.Diagnostics) > 0 && string(envelope.Diagnostics) != "null" { + attrs = append(attrs, "error_diagnostics", string(envelope.Diagnostics)) + } + return attrs +} + func (s *HTTPServer) requestIDMiddleware(c fiber.Ctx) error { requestID := c.Get("X-Request-ID") if requestID == "" { @@ -40,7 +94,24 @@ func (s *HTTPServer) loggingMiddleware(c fiber.Ctx) error { c.Status(MapDataframeError(err, requestIDFromCtx(c)).Status) } } - s.logger.Info("http request", "request_id", requestIDFromCtx(c), "method", c.Method(), "path", c.Path(), "status", c.Response().StatusCode(), "duration_ms", time.Since(start).Milliseconds()) + status := c.Response().StatusCode() + duration := time.Since(start).Milliseconds() + if status >= 400 { + attrs := []any{ + "request_id", requestIDFromCtx(c), + "method", c.Method(), + "path", c.Path(), + "url", c.OriginalURL(), + "status", status, + "duration_ms", duration, + } + attrs = append(attrs, errorResponseLogAttrs(c.Response().Body())...) + if err != nil { + attrs = append(attrs, "handler_error", err) + } + s.logger.Error("http request failed", attrs...) + } + s.logger.Info("http request", "request_id", requestIDFromCtx(c), "method", c.Method(), "path", c.Path(), "status", status, "duration_ms", duration) return err } diff --git a/internal/authscope/principal.go b/internal/authscope/principal.go index 0b1b2787..4ae7e99a 100644 --- a/internal/authscope/principal.go +++ b/internal/authscope/principal.go @@ -4,6 +4,8 @@ import ( "context" "errors" "fmt" + + "github.com/calypr/loom/internal/projectid" ) // Transport-neutral authorization conditions. Callers classify these @@ -54,8 +56,9 @@ func AuthorizeProject(principal *Principal, project string, ignorePrincipalProje if ignorePrincipalProjects || principal == nil || len(principal.Projects) == 0 { return nil } + project = projectid.Canonical(project) for _, candidate := range principal.Projects { - if candidate == project { + if projectid.Canonical(candidate) == project { return nil } } diff --git a/internal/authscope/scope_resolver.go b/internal/authscope/scope_resolver.go index f31998d0..625eaaf1 100644 --- a/internal/authscope/scope_resolver.go +++ b/internal/authscope/scope_resolver.go @@ -8,6 +8,7 @@ import ( "time" "github.com/calypr/loom/internal/catalog" + "github.com/calypr/loom/internal/projectid" ) type ResourceAccessClient interface { @@ -201,6 +202,30 @@ func (r *ScopeResolver) AuthorizeWrite(ctx context.Context, principal *Principal return fmt.Errorf("%w: auth_resource_path %q is outside caller scope for project %q", ErrForbidden, normalized, project) } +// AuthorizeReadProject verifies project-level read access without attempting +// to resolve a dataset-generation scope. Explorer lifecycle metadata is +// stored independently of a dataframe generation, so using +// ResolveReadScope here would intersect the caller's Fence grants with the +// empty-generation catalog namespace and incorrectly reject valid users. +// Generation-specific catalog and dataframe callers must continue using +// ResolveReadScopeForGeneration. +func (r *ScopeResolver) AuthorizeReadProject(ctx context.Context, principal *Principal, project string) error { + callerPaths, restricted, err := r.resolveCallerPaths(ctx, principal, PermissionRead, "*") + if err != nil { + return err + } + if !restricted { + return nil + } + projectKey := projectid.Legacy(projectid.Canonical(project)) + for _, path := range callerPaths { + if path == projectKey { + return nil + } + } + return fmt.Errorf("%w: caller has no read access to project %q", ErrForbidden, project) +} + // ResolveWriteScopeForGeneration proves that the caller may publish or mutate // data for the selected project. It mirrors read-scope resolution but asks // Fence for write permission and never treats an empty intersection as an diff --git a/internal/authscope/scope_test.go b/internal/authscope/scope_test.go index 3aba2a65..16e875a9 100644 --- a/internal/authscope/scope_test.go +++ b/internal/authscope/scope_test.go @@ -213,6 +213,31 @@ func TestAuthorizeProjectUsesPrincipalAllowlist(t *testing.T) { } } +func TestAuthorizeReadProjectDoesNotRequireEmptyGenerationCatalog(t *testing.T) { + client := &recordingResourceAccessClient{resources: []string{"/programs/HTAN_INT/projects/BForePC"}} + resolver := NewScopeResolver(ScopeResolverConfig{ + ResourceAccess: client, + ListExistingAuthResourcePaths: func(context.Context, catalog.AuthResourcePathOptions) ([]string, error) { + t.Fatalf("project authorization must not resolve a generation catalog") + return nil, nil + }, + }) + + if err := resolver.AuthorizeReadProject(context.Background(), &Principal{AuthorizationHeader: "Bearer token"}, "HTAN_INT/BForePC"); err != nil { + t.Fatalf("expected project read access, got %v", err) + } +} + +func TestAuthorizeReadProjectRejectsMissingProjectGrant(t *testing.T) { + client := &recordingResourceAccessClient{resources: []string{"/programs/HTAN_INT/projects/Other"}} + resolver := NewScopeResolver(ScopeResolverConfig{ResourceAccess: client}) + + err := resolver.AuthorizeReadProject(context.Background(), &Principal{AuthorizationHeader: "Bearer token"}, "HTAN_INT/BForePC") + if !errors.Is(err, ErrForbidden) { + t.Fatalf("expected forbidden project read, got %v", err) + } +} + func TestScopeResolverUsesWritePermissionForWriteScope(t *testing.T) { client := &recordingResourceAccessClient{resources: []string{"/programs/example/projects/allowed"}} resolver := NewScopeResolver(ScopeResolverConfig{ diff --git a/internal/catalog/arango/store.go b/internal/catalog/arango/store.go index d8ee306f..b72dd2b2 100644 --- a/internal/catalog/arango/store.go +++ b/internal/catalog/arango/store.go @@ -10,6 +10,7 @@ import ( "time" "github.com/calypr/loom/internal/catalog" + fhirschema "github.com/calypr/loom/internal/fhir/schema" store "github.com/calypr/loom/internal/store/arango" ) @@ -45,6 +46,11 @@ func (s *Store) DiscoverFields(ctx context.Context, opts catalog.PopulatedFieldO if err := decode(row, &out); err != nil { return err } + resourceType, ok := fhirschema.ConcreteResourceType(out.ResourceType) + if !ok { + return nil + } + out.ResourceType = resourceType rows = append(rows, out) return nil }) @@ -75,16 +81,56 @@ func (s *Store) DiscoverReferences(ctx context.Context, opts catalog.PopulatedRe } rows := make([]catalog.PopulatedReference, 0, 64) err := s.client.QueryRows(ctx, query, opts.CursorBatch, vars, func(row map[string]any) error { + fromType, fromOK := fhirschema.ConcreteResourceType(stringValue(row["from_type"])) + toType, toOK := fhirschema.ConcreteResourceType(stringValue(row["to_type"])) + if !fromOK || !toOK { + return nil + } + if _, ok := fhirschema.LookupTraversal(fromType, stringValue(row["label"]), toType); !ok { + return nil + } count, err := decodeInt64(row["edge_count"]) if err != nil { - return fmt.Errorf("decode edge_count for %s/%s/%s: %w", stringValue(row["from_type"]), stringValue(row["label"]), stringValue(row["to_type"]), err) + return fmt.Errorf("decode edge_count for %s/%s/%s: %w", fromType, stringValue(row["label"]), toType, err) } - rows = append(rows, catalog.PopulatedReference{DatasetGeneration: stringValue(row["dataset_generation"]), FromType: stringValue(row["from_type"]), Label: stringValue(row["label"]), ToType: stringValue(row["to_type"]), EdgeCount: count}) + rows = append(rows, catalog.PopulatedReference{DatasetGeneration: stringValue(row["dataset_generation"]), FromType: fromType, Label: stringValue(row["label"]), ToType: toType, EdgeCount: count}) return nil }) return rows, err } +func (s *Store) AuditRelationshipEdges(ctx context.Context, opts catalog.RelationshipAuditOptions) (catalog.RelationshipAuditSummary, error) { + if opts.CursorBatch <= 0 { + opts.CursorBatch = 1000 + } + vars := map[string]any{ + "project": opts.Project, + "dataset_generation": generation(opts.DatasetGeneration), + "auth_resource_paths": append([]string(nil), opts.AuthResourcePaths...), + "auth_resource_paths_unrestricted": catalog.EffectiveAuthResourcePathsUnrestricted(opts.AuthResourcePaths, opts.AuthResourcePathsUnrestricted), + "resource_types": fhirschema.ResourceTypes(), + } + summary := catalog.RelationshipAuditSummary{Project: opts.Project, DatasetGeneration: catalog.NormalizeDatasetGeneration(opts.DatasetGeneration)} + err := s.client.QueryRows(ctx, relationshipAuditAQL, opts.CursorBatch, vars, func(row map[string]any) error { + count, err := decodeInt64(row["edge_count"]) + if err != nil { + return err + } + summary.InvalidEdgeCount += count + summary.InvalidRelations = append(summary.InvalidRelations, catalog.InvalidRelationship{ + FromType: stringValue(row["from_type"]), + Label: stringValue(row["label"]), + ToType: stringValue(row["to_type"]), + EdgeCount: count, + }) + return nil + }) + if err != nil { + return catalog.RelationshipAuditSummary{}, err + } + return summary, nil +} + func (s *Store) DiscoverExistingAuthResourcePaths(ctx context.Context, opts catalog.AuthResourcePathOptions) ([]string, error) { if opts.CursorBatch <= 0 { opts.CursorBatch = 1000 @@ -103,6 +149,278 @@ func (s *Store) DiscoverExistingAuthResourcePaths(ctx context.Context, opts cata return result, nil } +// DiscoverResourceInventory reads the concrete resource collections directly. +// Field profiler rows are deliberately not consulted: a populated field is +// not evidence that a resource collection is a valid row root. +func (s *Store) DiscoverResourceInventory(ctx context.Context, opts catalog.ResourceInventoryOptions) (catalog.ResourceInventoryResult, error) { + if opts.CursorBatch <= 0 { + opts.CursorBatch = 1000 + } + resourceTypes, diagnostics := evidenceResourceTypes(opts.ResourceTypes) + result := catalog.ResourceInventoryResult{Values: make([]catalog.ResourceInventoryObservation, 0, len(resourceTypes)), Available: true, Complete: true, Diagnostics: diagnostics} + vars := map[string]any{ + "project": opts.Project, + "dataset_generation": generation(opts.DatasetGeneration), + "auth_resource_paths": append([]string(nil), opts.AuthResourcePaths...), + "auth_resource_paths_unrestricted": catalog.EffectiveAuthResourcePathsUnrestricted(opts.AuthResourcePaths, opts.AuthResourcePathsUnrestricted), + } + for _, resourceType := range resourceTypes { + vars["resource_collection"] = resourceType + vars["resource_type"] = resourceType + var rowSeen bool + err := s.client.QueryRows(ctx, resourceInventoryAQL, opts.CursorBatch, vars, func(row map[string]any) error { + rowSeen = true + count, err := decodeInt64(row["document_count"]) + if err != nil { + return fmt.Errorf("decode inventory count for %s: %w", resourceType, err) + } + result.Values = append(result.Values, catalog.ResourceInventoryObservation{ + Project: stringValue(row["project"]), DatasetGeneration: stringValue(row["dataset_generation"]), AuthResourcePath: stringValue(row["auth_resource_path"]), ResourceType: resourceType, DocumentCount: count, + }) + return nil + }) + if err != nil { + result.Available, result.Complete, result.Status = false, false, catalog.EvidenceUnavailable + result.Diagnostics = append(result.Diagnostics, catalog.EvidenceDiagnostic{Code: "RESOURCE_INVENTORY_UNAVAILABLE", Message: err.Error(), ResourceType: resourceType}) + return result, err + } + // Arango's COUNT query always returns one row. A defensive fallback + // preserves a valid zero count when a compatible client omits it. + if !rowSeen { + result.Values = append(result.Values, catalog.ResourceInventoryObservation{Project: opts.Project, DatasetGeneration: catalog.NormalizeDatasetGeneration(opts.DatasetGeneration), ResourceType: resourceType, DocumentCount: 0}) + } + } + sort.Slice(result.Values, func(i, j int) bool { + return inventoryObservationLess(result.Values[i], result.Values[j]) + }) + result.Digest, _ = catalog.ResourceInventoryDigest(result.Values) + result.Status = evidenceStatus(result.Available, result.Complete, result.Truncated, len(result.Values)) + return result, nil +} + +// DiscoverRelationshipObservations returns both storage and Builder views of +// each aggregate. The catalog stores physical fhir_edge direction; Builder +// usually traverses its inverse, so dropping the storage provenance here is a +// correctness bug rather than a presentation detail. +func (s *Store) DiscoverRelationshipObservations(ctx context.Context, opts catalog.RelationshipObservationOptions) (catalog.RelationshipObservationResult, error) { + if opts.CursorBatch <= 0 { + opts.CursorBatch = 1000 + } + resourceTypes, diagnostics := evidenceResourceTypes(opts.ResourceTypes) + result := catalog.RelationshipObservationResult{Values: []catalog.RelationshipObservation{}, Available: true, Complete: true, Diagnostics: diagnostics} + vars := map[string]any{ + "project": opts.Project, + "dataset_generation": generation(opts.DatasetGeneration), + "auth_resource_paths": append([]string(nil), opts.AuthResourcePaths...), + "auth_resource_paths_unrestricted": catalog.EffectiveAuthResourcePathsUnrestricted(opts.AuthResourcePaths, opts.AuthResourcePathsUnrestricted), + } + if len(opts.ResourceTypes) > 0 { + vars["resource_types"] = resourceTypes + } else { + vars["resource_types"] = nil + } + counts := make(map[relationshipObservationKey]int64) + var queryErr error + err := s.client.QueryRows(ctx, relationshipObservationsAQL, opts.CursorBatch, vars, func(row map[string]any) error { + storageFrom := stringValue(row["storage_from_type"]) + label := stringValue(row["label"]) + storageTo := stringValue(row["storage_to_type"]) + count, err := decodeInt64(row["edge_count"]) + if err != nil { + return fmt.Errorf("decode relationship count for %s/%s/%s: %w", storageFrom, label, storageTo, err) + } + from, fromOK := fhirschema.ConcreteResourceType(storageFrom) + to, toOK := fhirschema.ConcreteResourceType(storageTo) + if !fromOK || !toOK { + result.Diagnostics = append(result.Diagnostics, catalog.EvidenceDiagnostic{Code: "INVALID_RELATIONSHIP_ENDPOINT", Message: "relationship endpoint is not a concrete generated FHIR resource", StorageFromType: storageFrom, Label: label, StorageToType: storageTo, Count: count}) + return nil + } + observation, ok, diagnostic := relationshipObservation(stringValue(row["project"]), stringValue(row["dataset_generation"]), stringValue(row["auth_resource_path"]), from, label, to, count) + if !ok { + result.Diagnostics = append(result.Diagnostics, diagnostic) + return nil + } + key := relationshipObservationKey{project: observation.Project, generation: observation.DatasetGeneration, auth: observation.AuthResourcePath, storageFrom: observation.StorageFromType, label: observation.Label, storageTo: observation.StorageToType, builderFrom: observation.BuilderFromType, builderTo: observation.BuilderToType, builderDirection: observation.BuilderDirection} + counts[key] += observation.EdgeCount + return nil + }) + queryErr = err + if queryErr != nil { + result.Available, result.Complete, result.Status = false, false, catalog.EvidenceUnavailable + result.Diagnostics = append(result.Diagnostics, catalog.EvidenceDiagnostic{Code: "RELATIONSHIP_EVIDENCE_UNAVAILABLE", Message: queryErr.Error()}) + return result, queryErr + } + for key, count := range counts { + result.Values = append(result.Values, catalog.RelationshipObservation{Project: key.project, DatasetGeneration: key.generation, AuthResourcePath: key.auth, FromType: key.builderFrom, Label: key.label, ToType: key.builderTo, EdgeCount: count, StorageFromType: key.storageFrom, StorageToType: key.storageTo, StorageDirection: "OUTBOUND", BuilderFromType: key.builderFrom, BuilderToType: key.builderTo, BuilderDirection: key.builderDirection}) + } + sort.Slice(result.Values, func(i, j int) bool { return relationshipLess(result.Values[i], result.Values[j]) }) + result.Digest, _ = catalog.RelationshipObservationDigest(result.Values) + result.Status = evidenceStatus(result.Available, result.Complete, result.Truncated, len(result.Values)) + return result, nil +} + +// DiscoverFieldEnrichment reads profiler rows as optional, fail-closed +// enrichment. A successful empty result is valid evidence; a query failure or +// bounded distinct-value set is explicitly unavailable/incomplete. +func (s *Store) DiscoverFieldEnrichment(ctx context.Context, opts catalog.FieldEnrichmentOptions) (catalog.FieldEnrichmentResult, error) { + if opts.CursorBatch <= 0 { + opts.CursorBatch = 1000 + } + resourceTypes, diagnostics := evidenceResourceTypes(opts.ResourceTypes) + result := catalog.FieldEnrichmentResult{Values: []catalog.FieldEnrichmentObservation{}, Available: true, Complete: true, Diagnostics: diagnostics} + vars := map[string]any{ + "project": opts.Project, + "dataset_generation": generation(opts.DatasetGeneration), + "auth_resource_paths": append([]string(nil), opts.AuthResourcePaths...), + "auth_resource_paths_unrestricted": catalog.EffectiveAuthResourcePathsUnrestricted(opts.AuthResourcePaths, opts.AuthResourcePathsUnrestricted), + } + if len(opts.ResourceTypes) > 0 { + vars["resource_types"] = resourceTypes + } else { + vars["resource_types"] = nil + } + err := s.client.QueryRows(ctx, fieldEnrichmentAQL, opts.CursorBatch, vars, func(row map[string]any) error { + var field catalog.PopulatedField + if err := decode(row, &field); err != nil { + return err + } + resourceType, ok := fhirschema.ConcreteResourceType(field.ResourceType) + if !ok { + result.Diagnostics = append(result.Diagnostics, catalog.EvidenceDiagnostic{Code: "INVALID_FIELD_RESOURCE_TYPE", Message: "field enrichment resource type is not concrete/generated", ResourceType: field.ResourceType}) + return nil + } + field.ResourceType = resourceType + result.Values = append(result.Values, catalog.FieldEnrichmentObservation{Project: field.Project, DatasetGeneration: field.DatasetGeneration, AuthResourcePath: field.AuthResourcePath, ResourceType: field.ResourceType, Path: field.Path, Kind: field.Kind, DocCount: field.DocCount, SampleCount: field.SampleCount, DistinctValues: append([]string(nil), field.DistinctValues...), DistinctTruncated: field.DistinctTruncated, ExtensionValues: append([]catalog.ExtensionValueObservation(nil), field.ExtensionValues...), PivotCandidate: field.PivotCandidate, PivotKind: field.PivotKind, PivotColumns: append([]string(nil), field.PivotColumns...), PivotFamily: field.PivotFamily, PivotColumnSelect: field.PivotColumnSelect, PivotValueSelect: field.PivotValueSelect, PivotItemSource: field.PivotItemSource, PivotItemResourceType: field.PivotItemResourceType, PivotValueSelectors: append([]string(nil), field.PivotValueSelectors...)}) + // DistinctTruncated is per-field suggestion metadata. It is retained + // on the observation but does not make the complete enrichment artifact + // unusable; only an artifact-level marker can fail the snapshot. + if truncated, ok := row["enrichment_truncated"].(bool); ok && truncated { + result.Truncated = true + } + if complete, ok := row["enrichment_complete"].(bool); ok && !complete { + result.Complete = false + } + return nil + }) + if err != nil { + result.Available, result.Complete, result.Status = false, false, catalog.EvidenceUnavailable + result.Diagnostics = append(result.Diagnostics, catalog.EvidenceDiagnostic{Code: "FIELD_ENRICHMENT_UNAVAILABLE", Message: err.Error()}) + return result, err + } + if result.Truncated { + result.Complete = false + } + sort.Slice(result.Values, func(i, j int) bool { return fieldLess(result.Values[i], result.Values[j]) }) + result.Digest, _ = catalog.FieldEnrichmentDigest(result.Values) + result.Status = evidenceStatus(result.Available, result.Complete, result.Truncated, len(result.Values)) + return result, nil +} + +// Read* aliases make the capability boundary explicit while retaining the +// Discover* naming used by the pre-existing catalog reader. +func (s *Store) ReadResourceInventory(ctx context.Context, opts catalog.ResourceInventoryOptions) (catalog.ResourceInventoryResult, error) { + return s.DiscoverResourceInventory(ctx, opts) +} +func (s *Store) ReadRelationshipObservations(ctx context.Context, opts catalog.RelationshipObservationOptions) (catalog.RelationshipObservationResult, error) { + return s.DiscoverRelationshipObservations(ctx, opts) +} +func (s *Store) ReadFieldEnrichment(ctx context.Context, opts catalog.FieldEnrichmentOptions) (catalog.FieldEnrichmentResult, error) { + return s.DiscoverFieldEnrichment(ctx, opts) +} + +type relationshipObservationKey struct { + project, generation, auth string + storageFrom, label, storageTo string + builderFrom, builderTo, builderDirection string +} + +func evidenceResourceTypes(requested []string) ([]string, []catalog.EvidenceDiagnostic) { + if len(requested) == 0 { + return fhirschema.ResourceTypes(), nil + } + seen := make(map[string]struct{}, len(requested)) + diagnostics := make([]catalog.EvidenceDiagnostic, 0) + for _, requestedType := range requested { + canonical, ok := fhirschema.ConcreteResourceType(requestedType) + if !ok { + diagnostics = append(diagnostics, catalog.EvidenceDiagnostic{Code: "INVALID_RESOURCE_TYPE", Message: "requested resource type is not a concrete generated FHIR resource", ResourceType: requestedType}) + continue + } + seen[canonical] = struct{}{} + } + result := make([]string, 0, len(seen)) + for resourceType := range seen { + result = append(result, resourceType) + } + sort.Strings(result) + return result, diagnostics +} + +func inventoryObservationLess(a, b catalog.ResourceInventoryObservation) bool { + for _, pair := range [][2]string{{a.Project, b.Project}, {a.DatasetGeneration, b.DatasetGeneration}, {a.AuthResourcePath, b.AuthResourcePath}, {a.ResourceType, b.ResourceType}} { + if pair[0] != pair[1] { + return pair[0] < pair[1] + } + } + return a.DocumentCount < b.DocumentCount +} + +func relationshipLess(a, b catalog.RelationshipObservation) bool { + for _, pair := range [][2]string{{a.Project, b.Project}, {a.DatasetGeneration, b.DatasetGeneration}, {a.AuthResourcePath, b.AuthResourcePath}, {a.FromType, b.FromType}, {a.Label, b.Label}, {a.ToType, b.ToType}, {a.StorageFromType, b.StorageFromType}, {a.StorageToType, b.StorageToType}} { + if pair[0] != pair[1] { + return pair[0] < pair[1] + } + } + return a.EdgeCount < b.EdgeCount +} + +func fieldLess(a, b catalog.FieldEnrichmentObservation) bool { + for _, pair := range [][2]string{{a.Project, b.Project}, {a.DatasetGeneration, b.DatasetGeneration}, {a.AuthResourcePath, b.AuthResourcePath}, {a.ResourceType, b.ResourceType}, {a.Path, b.Path}, {a.Kind, b.Kind}} { + if pair[0] != pair[1] { + return pair[0] < pair[1] + } + } + return a.DocCount < b.DocCount +} + +func relationshipObservation(project, datasetGeneration, auth, storageFrom, label, storageTo string, count int64) (catalog.RelationshipObservation, bool, catalog.EvidenceDiagnostic) { + diagnostic := catalog.EvidenceDiagnostic{StorageFromType: storageFrom, Label: label, StorageToType: storageTo, Count: count} + if count <= 0 { + diagnostic.Code = "INVALID_RELATIONSHIP_COUNT" + diagnostic.Message = "relationship evidence count must be positive" + return catalog.RelationshipObservation{}, false, diagnostic + } + // Stored fhir_edge is always _from -> _to. Builder's normal projection is + // the inverse generated traversal, which is physically INBOUND from the + // stored target. Keep a direct generated traversal as a valid fallback for + // labels whose generated schema only exposes the storage orientation. + if _, found, err := fhirschema.ResolveCompilerTraversal(storageTo, label, storageFrom); found && err == nil { + return catalog.RelationshipObservation{Project: project, DatasetGeneration: datasetGeneration, AuthResourcePath: auth, FromType: storageTo, Label: label, ToType: storageFrom, EdgeCount: count, StorageFromType: storageFrom, StorageToType: storageTo, StorageDirection: "OUTBOUND", BuilderFromType: storageTo, BuilderToType: storageFrom, BuilderDirection: "INBOUND"}, true, diagnostic + } + if _, found, err := fhirschema.ResolveCompilerTraversal(storageFrom, label, storageTo); found && err == nil { + return catalog.RelationshipObservation{Project: project, DatasetGeneration: datasetGeneration, AuthResourcePath: auth, FromType: storageFrom, Label: label, ToType: storageTo, EdgeCount: count, StorageFromType: storageFrom, StorageToType: storageTo, StorageDirection: "OUTBOUND", BuilderFromType: storageFrom, BuilderToType: storageTo, BuilderDirection: "OUTBOUND"}, true, diagnostic + } + diagnostic.Code = "UNSUPPORTED_GENERATED_TRAVERSAL" + diagnostic.Message = "relationship endpoints and label are not a supported generated traversal" + return catalog.RelationshipObservation{}, false, diagnostic +} + +func evidenceStatus(available, complete, truncated bool, count int) catalog.EvidenceStatus { + if !available { + return catalog.EvidenceUnavailable + } + if truncated { + return catalog.EvidenceTruncated + } + if !complete { + return catalog.EvidenceIncomplete + } + if count == 0 { + return catalog.EvidenceEmpty + } + return catalog.EvidenceAvailable +} + func (s *Store) WriteFieldCatalog(ctx context.Context, collection string, docs []catalog.FieldCatalogDocument, batchSize int, overwrite bool, writeAPI string, timings map[string]float64) error { return catalog.WriteFieldCatalog(ctx, s.client, collection, docs, batchSize, overwrite, writeAPI, timings) } @@ -134,7 +452,11 @@ func (s *Store) RebuildRelationshipCatalog(ctx context.Context, opts catalog.Rel }}}); err != nil { return catalog.RelationshipRebuildSummary{}, err } - vars := map[string]any{"project": opts.Project, "dataset_generation": generation(opts.DatasetGeneration), "auth_resource_paths": opts.AuthResourcePaths, "auth_resource_paths_unrestricted": catalog.EffectiveAuthResourcePathsUnrestricted(opts.AuthResourcePaths, opts.AuthResourcePathsUnrestricted)} + audit, err := s.AuditRelationshipEdges(ctx, catalog.RelationshipAuditOptions{Project: opts.Project, DatasetGeneration: opts.DatasetGeneration, AuthResourcePaths: opts.AuthResourcePaths, AuthResourcePathsUnrestricted: opts.AuthResourcePathsUnrestricted, CursorBatch: opts.CursorBatch}) + if err != nil { + return catalog.RelationshipRebuildSummary{}, err + } + vars := map[string]any{"project": opts.Project, "dataset_generation": generation(opts.DatasetGeneration), "auth_resource_paths": opts.AuthResourcePaths, "auth_resource_paths_unrestricted": catalog.EffectiveAuthResourcePathsUnrestricted(opts.AuthResourcePaths, opts.AuthResourcePathsUnrestricted), "resource_types": fhirschema.ResourceTypes()} if err := s.client.QueryRows(ctx, relationshipClearAQL, opts.CursorBatch, vars, func(map[string]any) error { return nil }); err != nil { return catalog.RelationshipRebuildSummary{}, err } @@ -158,10 +480,11 @@ func (s *Store) RebuildRelationshipCatalog(ctx context.Context, opts catalog.Rel for _, count := range counts { total += count } - return catalog.RelationshipRebuildSummary{Project: opts.Project, DatasetGeneration: catalog.NormalizeDatasetGeneration(opts.DatasetGeneration), Rows: len(docs), EdgeCount: total, Seconds: time.Since(started).Seconds()}, nil + return catalog.RelationshipRebuildSummary{Project: opts.Project, DatasetGeneration: catalog.NormalizeDatasetGeneration(opts.DatasetGeneration), Rows: len(docs), EdgeCount: total, InvalidEdgeCount: audit.InvalidEdgeCount, Seconds: time.Since(started).Seconds()}, nil } func generation(value string) any { + value = catalog.NormalizeDatasetGeneration(value) if value == "" { return nil } @@ -334,6 +657,67 @@ FOR d IN fhir_field_catalog pivot_item_resource_type: d.pivot_item_resource_type, pivot_value_selectors: d.pivot_value_selectors }` + +// resourceInventoryAQL is executed once per concrete generated resource +// collection because Arango collection bind parameters cannot be safely +// interpolated from a caller-supplied type. Every identity predicate remains +// a bind variable, including the explicit restricted-empty authorization mode. +const resourceInventoryAQL = ` +FOR d IN @@resource_collection + FILTER d.project == @project + FILTER d.dataset_generation == @dataset_generation + FILTER @auth_resource_paths_unrestricted == true OR d.auth_resource_path IN @auth_resource_paths + COLLECT WITH COUNT INTO document_count + RETURN { + project: @project, + dataset_generation: @dataset_generation, + resource_type: @resource_type, + document_count + }` + +const relationshipObservationsAQL = ` +FOR d IN fhir_relationship_catalog + FILTER d.project == @project + FILTER d.dataset_generation == @dataset_generation + FILTER @auth_resource_paths_unrestricted == true OR d.auth_resource_path IN @auth_resource_paths + FILTER @resource_types == null OR (d.from_type IN @resource_types AND d.to_type IN @resource_types) + COLLECT project = d.project, dataset_generation = d.dataset_generation, auth_resource_path = d.auth_resource_path, + storage_from_type = d.from_type, label = d.label, storage_to_type = d.to_type + AGGREGATE edge_count = SUM(d.edge_count) + SORT project, dataset_generation, auth_resource_path, storage_from_type, label, storage_to_type, edge_count + RETURN { project, dataset_generation, auth_resource_path, storage_from_type, label, storage_to_type, edge_count }` + +const fieldEnrichmentAQL = ` +FOR d IN fhir_field_catalog + FILTER d.project == @project + FILTER d.dataset_generation == @dataset_generation + FILTER @auth_resource_paths_unrestricted == true OR d.auth_resource_path IN @auth_resource_paths + FILTER @resource_types == null OR d.resource_type IN @resource_types + SORT d.resource_type, d.path, d.auth_resource_path, d.doc_count + RETURN { + project: d.project, + dataset_generation: d.dataset_generation, + auth_resource_path: d.auth_resource_path, + resource_type: d.resource_type, + path: d.path, + kind: d.kind, + doc_count: d.doc_count, + sample_count: d.sample_count, + distinct_values: d.distinct_values, + distinct_truncated: d.distinct_truncated, + extension_values: d.extension_values, + pivot_candidate: d.pivot_candidate, + pivot_kind: d.pivot_kind, + pivot_columns: d.pivot_columns, + pivot_family: d.pivot_family, + pivot_column_selector: d.pivot_column_selector, + pivot_value_selector: d.pivot_value_selector, + pivot_item_source: d.pivot_item_source, + pivot_item_resource_type: d.pivot_item_resource_type, + pivot_value_selectors: d.pivot_value_selectors, + enrichment_complete: d.enrichment_complete, + enrichment_truncated: d.enrichment_truncated + }` const relationshipCatalogStorageAQL = ` FOR d IN fhir_relationship_catalog FILTER d.project == @project @@ -374,6 +758,16 @@ FOR e IN fhir_edge FILTER e.project == @project FILTER e.dataset_generation == @dataset_generation FILTER @auth_resource_paths_unrestricted == true OR e.auth_resource_path IN @auth_resource_paths + FILTER e.from_type IN @resource_types AND e.to_type IN @resource_types COLLECT project = e.project, dataset_generation = e.dataset_generation, auth_resource_path = e.auth_resource_path, from_type = e.from_type, label = e.label, to_type = e.to_type WITH COUNT INTO edge_count RETURN { project, dataset_generation, auth_resource_path, from_type, label, to_type, edge_count }` +const relationshipAuditAQL = ` +FOR e IN fhir_edge + FILTER e.project == @project + FILTER e.dataset_generation == @dataset_generation + FILTER @auth_resource_paths_unrestricted == true OR e.auth_resource_path IN @auth_resource_paths + FILTER e.from_type NOT IN @resource_types OR e.to_type NOT IN @resource_types + COLLECT from_type = e.from_type, label = e.label, to_type = e.to_type WITH COUNT INTO edge_count + SORT edge_count DESC, from_type, label, to_type + RETURN { from_type, label, to_type, edge_count }` diff --git a/internal/catalog/arango/store_test.go b/internal/catalog/arango/store_test.go index 16d48c1e..6e25da4e 100644 --- a/internal/catalog/arango/store_test.go +++ b/internal/catalog/arango/store_test.go @@ -3,6 +3,8 @@ package arango import ( "context" "encoding/json" + "errors" + "strings" "testing" "github.com/calypr/loom/internal/catalog" @@ -14,12 +16,46 @@ type fakeClient struct { row map[string]any } +type evidenceClient struct { + queries []string + vars []map[string]any + rows map[string][]map[string]any + err error +} + +func (f *evidenceClient) QueryRows(_ context.Context, query string, _ int, vars map[string]any, visit store.RowVisitor) error { + f.queries = append(f.queries, query) + copyVars := make(map[string]any, len(vars)) + for key, value := range vars { + copyVars[key] = value + } + f.vars = append(f.vars, copyVars) + if f.err != nil { + return f.err + } + for _, row := range f.rows[query] { + if err := visit(row); err != nil { + return err + } + } + return nil +} +func (*evidenceClient) InsertBatchRaw(context.Context, string, []json.RawMessage, bool, string) error { + return nil +} +func (*evidenceClient) ExecuteAQL(context.Context, string, map[string]any) error { return nil } +func (*evidenceClient) Bootstrap(context.Context, store.BootstrapSpec) error { return nil } + func (f *fakeClient) QueryRows(_ context.Context, query string, _ int, _ map[string]any, visit store.RowVisitor) error { f.queries = append(f.queries, query) - if query == populatedFieldsAQL { + if query == populatedFieldsAQL || query == relationshipAuditAQL { row := f.row if row == nil { - row = map[string]any{"project": "p", "resource_type": "Patient", "path": "id", "doc_count": int64(1), "sample_count": int64(1)} + if query == relationshipAuditAQL { + row = map[string]any{"from_type": "qualification", "label": "link", "to_type": "issuer", "edge_count": int64(2)} + } else { + row = map[string]any{"project": "p", "resource_type": "Patient", "path": "id", "doc_count": int64(1), "sample_count": int64(1)} + } } return visit(row) } @@ -73,3 +109,99 @@ func TestStorePreservesFieldMetadataAndRejectsMalformedRows(t *testing.T) { t.Fatal("malformed numeric field row was accepted") } } + +func TestStoreAuditsInvalidRelationshipEndpoints(t *testing.T) { + adapter, err := New(&fakeClient{}) + if err != nil { + t.Fatal(err) + } + summary, err := adapter.AuditRelationshipEdges(context.Background(), catalog.RelationshipAuditOptions{Project: "p"}) + if err != nil { + t.Fatal(err) + } + if summary.InvalidEdgeCount != 2 || len(summary.InvalidRelations) != 1 || summary.InvalidRelations[0].FromType != "qualification" || summary.InvalidRelations[0].ToType != "issuer" { + t.Fatalf("audit summary = %#v", summary) + } +} + +func TestRelationshipRebuildFiltersNonResourceEndpoints(t *testing.T) { + if !strings.Contains(relationshipRebuildAQL, "e.from_type IN @resource_types") || !strings.Contains(relationshipRebuildAQL, "e.to_type IN @resource_types") { + t.Fatal("relationship rebuild does not filter invalid resource endpoints") + } +} + +func TestCapabilityEvidenceRelationshipPreservesBuilderAndStorageProvenance(t *testing.T) { + client := &evidenceClient{rows: map[string][]map[string]any{relationshipObservationsAQL: {{ + "project": "p", "dataset_generation": "g", "auth_resource_path": "scope", + "storage_from_type": "Condition", "label": "subject_Patient", "storage_to_type": "Patient", "edge_count": int64(7), + }}}} + adapter, err := New(client) + if err != nil { + t.Fatal(err) + } + result, err := adapter.DiscoverRelationshipObservations(context.Background(), catalog.RelationshipObservationOptions{Project: "p", DatasetGeneration: "g", AuthResourcePaths: []string{}, AuthResourcePathsUnrestricted: catalog.ExplicitAuthResourcePathsUnrestricted(false), ResourceTypes: []string{"Patient", "Condition"}}) + if err != nil || len(result.Values) != 1 { + t.Fatalf("result=%#v err=%v", result, err) + } + got := result.Values[0] + if got.FromType != "Patient" || got.ToType != "Condition" || got.BuilderDirection != "INBOUND" || got.StorageFromType != "Condition" || got.StorageToType != "Patient" || got.StorageDirection != "OUTBOUND" || got.EdgeCount != 7 { + t.Fatalf("provenance = %#v", got) + } + if vars := client.vars[0]; vars["project"] != "p" || vars["dataset_generation"] != "g" || vars["auth_resource_paths_unrestricted"] != false { + t.Fatalf("identity binds = %#v", vars) + } + if paths, ok := client.vars[0]["auth_resource_paths"].([]string); !ok || len(paths) != 0 { + t.Fatalf("restricted-empty paths bind = %#v", client.vars[0]["auth_resource_paths"]) + } + for _, name := range []string{"@project", "@dataset_generation", "@auth_resource_paths", "@auth_resource_paths_unrestricted", "COLLECT", "SUM(d.edge_count)"} { + if !strings.Contains(client.queries[0], name) { + t.Fatalf("relationship query missing %q: %s", name, client.queries[0]) + } + } +} + +func TestCapabilityEvidenceInventoryBindsCollectionAndIdentity(t *testing.T) { + client := &evidenceClient{rows: map[string][]map[string]any{resourceInventoryAQL: {{ + "project": "p", "dataset_generation": "g", "resource_type": "Patient", "document_count": int64(4), + }}}} + adapter, _ := New(client) + result, err := adapter.DiscoverResourceInventory(context.Background(), catalog.ResourceInventoryOptions{Project: "p", DatasetGeneration: "g", AuthResourcePaths: []string{}, AuthResourcePathsUnrestricted: catalog.ExplicitAuthResourcePathsUnrestricted(false), ResourceTypes: []string{"Patient"}}) + if err != nil || len(result.Values) != 1 || result.Values[0].DocumentCount != 4 { + t.Fatalf("inventory = %#v err=%v", result, err) + } + vars := client.vars[0] + if vars["project"] != "p" || vars["dataset_generation"] != "g" || vars["resource_collection"] != "Patient" || vars["auth_resource_paths_unrestricted"] != false { + t.Fatalf("inventory binds = %#v", vars) + } + for _, name := range []string{"@@resource_collection", "@project", "@dataset_generation", "@auth_resource_paths", "@auth_resource_paths_unrestricted", "COLLECT WITH COUNT"} { + if !strings.Contains(client.queries[0], name) { + t.Fatalf("inventory query missing %q: %s", name, client.queries[0]) + } + } +} + +func TestCapabilityEvidenceFieldEmptyAndFailureAreDistinct(t *testing.T) { + emptyClient := &evidenceClient{rows: map[string][]map[string]any{fieldEnrichmentAQL: nil}} + emptyStore, _ := New(emptyClient) + empty, err := emptyStore.DiscoverFieldEnrichment(context.Background(), catalog.FieldEnrichmentOptions{Project: "p"}) + if err != nil || empty.Status != catalog.EvidenceEmpty || !empty.Available || !empty.Complete { + t.Fatalf("empty enrichment = %#v err=%v", empty, err) + } + failingClient := &evidenceClient{err: errors.New("catalog unavailable")} + failingStore, _ := New(failingClient) + failing, err := failingStore.DiscoverFieldEnrichment(context.Background(), catalog.FieldEnrichmentOptions{Project: "p"}) + if err == nil || failing.Status != catalog.EvidenceUnavailable || failing.Available || failing.Complete { + t.Fatalf("failed enrichment = %#v err=%v", failing, err) + } +} + +func TestCapabilityEvidenceFieldSuggestionTruncationIsPerField(t *testing.T) { + client := &evidenceClient{rows: map[string][]map[string]any{fieldEnrichmentAQL: {{ + "project": "p", "resource_type": "Patient", "path": "name", "kind": "scalar", "doc_count": int64(1), "sample_count": int64(1), "distinct_values": []any{"a"}, "distinct_truncated": true, + }}}} + adapter, _ := New(client) + result, err := adapter.DiscoverFieldEnrichment(context.Background(), catalog.FieldEnrichmentOptions{Project: "p"}) + if err != nil || result.Status != catalog.EvidenceAvailable || !result.Complete || result.Truncated || len(result.Values) != 1 || !result.Values[0].DistinctTruncated { + t.Fatalf("per-field truncation = %#v err=%v", result, err) + } +} diff --git a/internal/catalog/capability_evidence.go b/internal/catalog/capability_evidence.go new file mode 100644 index 00000000..3ba0a784 --- /dev/null +++ b/internal/catalog/capability_evidence.go @@ -0,0 +1,143 @@ +package catalog + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "sort" +) + +// newEvidenceStatus centralizes the empty/partial distinction. A successful +// query with no rows is valid empty evidence; a failed query is unavailable, +// and a bounded profiler result is incomplete/truncated. +func newEvidenceStatus(available, complete, truncated bool, count int) EvidenceStatus { + if !available { + return EvidenceUnavailable + } + if truncated { + return EvidenceTruncated + } + if !complete { + return EvidenceIncomplete + } + if count == 0 { + return EvidenceEmpty + } + return EvidenceAvailable +} + +func unavailableInventory(diagnostics []EvidenceDiagnostic) ResourceInventoryResult { + return ResourceInventoryResult{Values: []ResourceInventoryObservation{}, Status: EvidenceUnavailable, Diagnostics: append([]EvidenceDiagnostic(nil), diagnostics...)} +} + +func unavailableRelationships(diagnostics []EvidenceDiagnostic) RelationshipObservationResult { + return RelationshipObservationResult{Values: []RelationshipObservation{}, Status: EvidenceUnavailable, Diagnostics: append([]EvidenceDiagnostic(nil), diagnostics...)} +} + +func unavailableEnrichment(diagnostics []EvidenceDiagnostic) FieldEnrichmentResult { + return FieldEnrichmentResult{Values: []FieldEnrichmentObservation{}, Status: EvidenceUnavailable, Diagnostics: append([]EvidenceDiagnostic(nil), diagnostics...)} +} + +func canonicalDigest(value any) (string, error) { + encoded, err := json.Marshal(value) + if err != nil { + return "", err + } + sum := sha256.Sum256(encoded) + return "sha256:" + hex.EncodeToString(sum[:]), nil +} + +func ResourceInventoryDigest(records []ResourceInventoryObservation) (string, error) { + canonical := append([]ResourceInventoryObservation(nil), records...) + sort.SliceStable(canonical, func(i, j int) bool { + return inventoryLess(canonical[i], canonical[j]) + }) + return canonicalDigest(canonical) +} + +func inventoryLess(a, b ResourceInventoryObservation) bool { + for _, pair := range [][2]string{{a.Project, b.Project}, {a.DatasetGeneration, b.DatasetGeneration}, {a.AuthResourcePath, b.AuthResourcePath}, {a.ResourceType, b.ResourceType}} { + if pair[0] != pair[1] { + return pair[0] < pair[1] + } + } + return a.DocumentCount < b.DocumentCount +} + +func RelationshipObservationDigest(records []RelationshipObservation) (string, error) { + canonical := append([]RelationshipObservation(nil), records...) + sort.SliceStable(canonical, func(i, j int) bool { + return relationshipObservationLess(canonical[i], canonical[j]) + }) + return canonicalDigest(canonical) +} + +func relationshipObservationLess(a, b RelationshipObservation) bool { + left := [12]string{a.Project, a.DatasetGeneration, a.AuthResourcePath, a.StorageFromType, a.Label, a.StorageToType, a.StorageDirection, a.BuilderFromType, a.BuilderToType, a.BuilderDirection, a.FromType, a.ToType} + right := [12]string{b.Project, b.DatasetGeneration, b.AuthResourcePath, b.StorageFromType, b.Label, b.StorageToType, b.StorageDirection, b.BuilderFromType, b.BuilderToType, b.BuilderDirection, b.FromType, b.ToType} + for i := range left { + if left[i] != right[i] { + return left[i] < right[i] + } + } + return a.EdgeCount < b.EdgeCount +} + +func FieldEnrichmentDigest(records []FieldEnrichmentObservation) (string, error) { + canonical := cloneFieldEnrichment(records) + sort.SliceStable(canonical, func(i, j int) bool { + a, b := canonical[i], canonical[j] + for _, pair := range [][2]string{{a.Project, b.Project}, {a.DatasetGeneration, b.DatasetGeneration}, {a.AuthResourcePath, b.AuthResourcePath}, {a.ResourceType, b.ResourceType}, {a.Path, b.Path}, {a.Kind, b.Kind}} { + if pair[0] != pair[1] { + return pair[0] < pair[1] + } + } + return a.DocCount < b.DocCount + }) + return canonicalDigest(canonical) +} + +func cloneFieldEnrichment(in []FieldEnrichmentObservation) []FieldEnrichmentObservation { + if len(in) == 0 { + return []FieldEnrichmentObservation{} + } + out := make([]FieldEnrichmentObservation, len(in)) + for i := range in { + out[i] = in[i] + out[i].DistinctValues = append([]string(nil), in[i].DistinctValues...) + out[i].PivotColumns = append([]string(nil), in[i].PivotColumns...) + out[i].PivotValueSelectors = append([]string(nil), in[i].PivotValueSelectors...) + out[i].ExtensionValues = append([]ExtensionValueObservation(nil), in[i].ExtensionValues...) + for j := range out[i].ExtensionValues { + out[i].ExtensionValues[j].URLPath = append([]string(nil), in[i].ExtensionValues[j].URLPath...) + } + } + return out +} + +// ReadCapabilityEvidence keeps the three evidence sources independent while +// providing a convenient aggregate for snapshot compilers. It returns the +// first dependency error but still returns all successfully read evidence. +func ReadCapabilityEvidence(ctx context.Context, reader CapabilityEvidenceReader, opts CapabilityEvidenceOptions) (CapabilityEvidence, error) { + var result CapabilityEvidence + var firstErr error + inventory, err := reader.DiscoverResourceInventory(ctx, opts) + result.ResourceInventory = inventory + if err != nil { + firstErr = err + } + relationships, err := reader.DiscoverRelationshipObservations(ctx, opts) + result.Relationships = relationships + if err != nil { + if firstErr == nil { + firstErr = err + } + } + enrichment, err := reader.DiscoverFieldEnrichment(ctx, opts) + result.FieldEnrichment = enrichment + if err != nil && firstErr == nil { + firstErr = err + } + return result, firstErr +} diff --git a/internal/catalog/capability_evidence_test.go b/internal/catalog/capability_evidence_test.go new file mode 100644 index 00000000..54945448 --- /dev/null +++ b/internal/catalog/capability_evidence_test.go @@ -0,0 +1,53 @@ +package catalog + +import ( + "reflect" + "testing" +) + +func TestCapabilityEvidenceDigestsAreOrderIndependentAndScoped(t *testing.T) { + records := []ResourceInventoryObservation{ + {Project: "p", DatasetGeneration: "g", AuthResourcePath: "b", ResourceType: "Patient", DocumentCount: 2}, + {Project: "p", DatasetGeneration: "g", AuthResourcePath: "a", ResourceType: "Condition", DocumentCount: 1}, + } + first, err := ResourceInventoryDigest(records) + if err != nil { + t.Fatal(err) + } + second, err := ResourceInventoryDigest([]ResourceInventoryObservation{records[1], records[0]}) + if err != nil || first != second { + t.Fatalf("digest depends on record order: %q != %q (err=%v)", first, second, err) + } + other, err := ResourceInventoryDigest([]ResourceInventoryObservation{{Project: "p", DatasetGeneration: "g", AuthResourcePath: "other", ResourceType: "Patient", DocumentCount: 2}}) + if err != nil || first == other { + t.Fatalf("digest does not distinguish authorization scope: %q == %q (err=%v)", first, other, err) + } +} + +func TestFieldEnrichmentDigestIncludesExactCanonicalRecord(t *testing.T) { + base := FieldEnrichmentObservation{Project: "p", DatasetGeneration: "g", AuthResourcePath: "scope", ResourceType: "Patient", Path: "id", Kind: "scalar", DocCount: 2, DistinctValues: []string{"a", "b"}} + one, err := FieldEnrichmentDigest([]FieldEnrichmentObservation{base}) + if err != nil { + t.Fatal(err) + } + base.DistinctValues = []string{"a", "c"} + two, err := FieldEnrichmentDigest([]FieldEnrichmentObservation{base}) + if err != nil || one == two { + t.Fatalf("digest omitted exact enrichment values: %q == %q (err=%v)", one, two, err) + } + if got := cloneFieldEnrichment([]FieldEnrichmentObservation{base}); !reflect.DeepEqual(got[0].DistinctValues, []string{"a", "c"}) { + t.Fatalf("field enrichment clone lost values: %#v", got) + } +} + +func TestEvidenceStatusesDistinguishEmptyFailureAndTruncation(t *testing.T) { + if got := newEvidenceStatus(true, true, false, 0); got != EvidenceEmpty { + t.Fatalf("empty status = %q", got) + } + if got := newEvidenceStatus(false, false, false, 0); got != EvidenceUnavailable { + t.Fatalf("failure status = %q", got) + } + if got := newEvidenceStatus(true, false, true, 1); got != EvidenceTruncated { + t.Fatalf("truncated status = %q", got) + } +} diff --git a/internal/catalog/limits.go b/internal/catalog/limits.go new file mode 100644 index 00000000..e58ec00c --- /dev/null +++ b/internal/catalog/limits.go @@ -0,0 +1,65 @@ +package catalog + +// ProfileLimits bounds the write-side memory retained while profiling one +// resource file. Catalog discovery is useful only while it remains a bounded +// summary; retaining every value from a high-cardinality field turns an ingest +// into an in-memory copy of the source dataset. +type ProfileLimits struct { + MaxFields int + MaxDistinctValuesPerField int + MaxDistinctValueBytes int + MaxPivotColumnsPerField int + MaxExtensionValuesPerField int + MaxShapePlans int +} + +const ( + DefaultMaxProfileFields = 4096 + DefaultMaxDistinctValuesPerField = 4096 + DefaultMaxDistinctValueBytes = 4096 + DefaultMaxPivotColumnsPerField = 4096 + DefaultMaxExtensionValuesPerField = 4096 + DefaultMaxShapePlans = 2048 +) + +// DefaultProfileLimits are deliberately finite. Callers that need a +// different operational envelope must make that choice explicitly. +func DefaultProfileLimits() ProfileLimits { + return ProfileLimits{ + MaxFields: DefaultMaxProfileFields, + MaxDistinctValuesPerField: DefaultMaxDistinctValuesPerField, + MaxDistinctValueBytes: DefaultMaxDistinctValueBytes, + MaxPivotColumnsPerField: DefaultMaxPivotColumnsPerField, + MaxExtensionValuesPerField: DefaultMaxExtensionValuesPerField, + MaxShapePlans: DefaultMaxShapePlans, + } +} + +func (l ProfileLimits) normalized() ProfileLimits { + defaults := DefaultProfileLimits() + if l.MaxFields <= 0 { + l.MaxFields = defaults.MaxFields + } + if l.MaxDistinctValuesPerField <= 0 { + l.MaxDistinctValuesPerField = defaults.MaxDistinctValuesPerField + } + if l.MaxDistinctValueBytes <= 0 { + l.MaxDistinctValueBytes = defaults.MaxDistinctValueBytes + } + if l.MaxPivotColumnsPerField <= 0 { + l.MaxPivotColumnsPerField = defaults.MaxPivotColumnsPerField + } + if l.MaxExtensionValuesPerField <= 0 { + l.MaxExtensionValuesPerField = defaults.MaxExtensionValuesPerField + } + if l.MaxShapePlans <= 0 { + l.MaxShapePlans = defaults.MaxShapePlans + } + return l +} + +// NormalizeProfileLimits applies the finite defaults to an operational load +// configuration. +func NormalizeProfileLimits(l ProfileLimits) ProfileLimits { + return l.normalized() +} diff --git a/internal/catalog/rebuild.go b/internal/catalog/rebuild.go index da1753d8..ec71b673 100644 --- a/internal/catalog/rebuild.go +++ b/internal/catalog/rebuild.go @@ -18,5 +18,31 @@ type RelationshipRebuildSummary struct { DatasetGeneration string `json:"dataset_generation,omitempty"` Rows int `json:"rows"` EdgeCount int64 `json:"edge_count"` + InvalidEdgeCount int64 `json:"invalid_edge_count,omitempty"` Seconds float64 `json:"seconds"` } + +// RelationshipAuditOptions identifies the immutable edge namespace to audit. +// The audit is read-only and is intentionally separate from catalog rebuild so +// operators can inspect malformed historical data before choosing a repair. +type RelationshipAuditOptions struct { + Project string + DatasetGeneration string + AuthResourcePaths []string + AuthResourcePathsUnrestricted *bool + CursorBatch int +} + +type InvalidRelationship struct { + FromType string `json:"from_type"` + Label string `json:"label"` + ToType string `json:"to_type"` + EdgeCount int64 `json:"edge_count"` +} + +type RelationshipAuditSummary struct { + Project string `json:"project"` + DatasetGeneration string `json:"dataset_generation,omitempty"` + InvalidEdgeCount int64 `json:"invalid_edge_count"` + InvalidRelations []InvalidRelationship `json:"invalid_relationships,omitempty"` +} diff --git a/internal/catalog/relationships.go b/internal/catalog/relationships.go index 2e72a4cb..de8fca48 100644 --- a/internal/catalog/relationships.go +++ b/internal/catalog/relationships.go @@ -6,6 +6,7 @@ import ( "sort" "github.com/bytedance/sonic" + fhirschema "github.com/calypr/loom/internal/fhir/schema" ) const relationshipCatalogKeyPrefix = "rfc_" @@ -37,13 +38,21 @@ func RelationshipCountsFromRawEdges(docs []json.RawMessage) (map[RelationshipKey if edge.Project == "" || edge.FromType == "" || edge.Label == "" || edge.ToType == "" { return nil, fmt.Errorf("relationship edge %d is missing project/from_type/label/to_type", index) } + fromType, ok := fhirschema.ConcreteResourceType(edge.FromType) + if !ok { + return nil, fmt.Errorf("relationship edge %d has unsupported from_type %q", index, edge.FromType) + } + toType, ok := fhirschema.ConcreteResourceType(edge.ToType) + if !ok { + return nil, fmt.Errorf("relationship edge %d has unsupported to_type %q", index, edge.ToType) + } key := RelationshipKey{ Project: edge.Project, DatasetGeneration: NormalizeDatasetGeneration(edge.DatasetGeneration), AuthResourcePath: edge.AuthResourcePath, - FromType: edge.FromType, + FromType: fromType, Label: edge.Label, - ToType: edge.ToType, + ToType: toType, } counts[key]++ } diff --git a/internal/catalog/relationships_test.go b/internal/catalog/relationships_test.go index f98c9cc4..b6d7ba37 100644 --- a/internal/catalog/relationships_test.go +++ b/internal/catalog/relationships_test.go @@ -25,6 +25,15 @@ func TestRelationshipCountsRequireCompleteCommittedEdgeShape(t *testing.T) { } } +func TestRelationshipCountsRejectNonConcreteResourceEndpoints(t *testing.T) { + for _, endpoint := range []string{"PractitionerQualification", "qualification", "issuer", "Resource", "CustomResource"} { + raw := json.RawMessage(`{"project":"P1","from_type":"Practitioner","label":"link","to_type":"` + endpoint + `"}`) + if _, err := RelationshipCountsFromRawEdges([]json.RawMessage{raw}); err == nil { + t.Fatalf("relationship endpoint %q was accepted", endpoint) + } + } +} + func TestRelationshipCatalogDocumentsHaveStableGenerationSafeKeys(t *testing.T) { counts := map[RelationshipKey]int64{ {Project: "P1", DatasetGeneration: "gen/a", AuthResourcePath: "path", FromType: "Patient", Label: "subject", ToType: "Specimen"}: 3, diff --git a/internal/catalog/types.go b/internal/catalog/types.go index 6a2b4496..12c526ed 100644 --- a/internal/catalog/types.go +++ b/internal/catalog/types.go @@ -1,6 +1,9 @@ package catalog -import "sync" +import ( + "context" + "sync" +) const ( FieldCatalogCollection = "fhir_field_catalog" @@ -19,6 +22,158 @@ const ( TraversalModeBuilder = "builder" ) +// EvidenceStatus describes the meaning of a capability-evidence read. An +// empty Values slice is only usable when Status is EvidenceEmpty (or +// EvidenceAvailable with Complete true); unavailable, incomplete, and +// truncated reads must never be treated as an empty capability set. +type EvidenceStatus string + +const ( + EvidenceAvailable EvidenceStatus = "available" + EvidenceEmpty EvidenceStatus = "empty" + EvidenceUnavailable EvidenceStatus = "unavailable" + EvidenceIncomplete EvidenceStatus = "incomplete" + EvidenceTruncated EvidenceStatus = "truncated" +) + +// CapabilityEvidenceOptions identifies one immutable, authorization-scoped +// evidence namespace. ResourceTypes is optional and is primarily useful for a +// bounded read or a test; an empty value means every generated concrete FHIR +// resource type. +type CapabilityEvidenceOptions struct { + Project string + DatasetGeneration string + AuthResourcePathsUnrestricted *bool + AuthResourcePaths []string + ResourceTypes []string + CursorBatch int +} + +type ResourceInventoryOptions = CapabilityEvidenceOptions +type RelationshipObservationOptions = CapabilityEvidenceOptions +type FieldEnrichmentOptions = CapabilityEvidenceOptions + +// EvidenceDiagnostic records malformed historical evidence without promoting +// it to a capability. Diagnostics are deliberately data-only so callers can +// retain an otherwise usable snapshot and explain excluded records. +type EvidenceDiagnostic struct { + Code string `json:"code"` + Message string `json:"message"` + ResourceType string `json:"resource_type,omitempty"` + StorageFromType string `json:"storage_from_type,omitempty"` + Label string `json:"label,omitempty"` + StorageToType string `json:"storage_to_type,omitempty"` + Count int64 `json:"count,omitempty"` +} + +// ResourceInventoryObservation is the only evidence source for capability +// row nodes. It is intentionally independent of field profiling: a resource +// with no populated field may still be a valid, empty row collection. +type ResourceInventoryObservation struct { + Project string `json:"project"` + DatasetGeneration string `json:"dataset_generation,omitempty"` + AuthResourcePath string `json:"auth_resource_path,omitempty"` + ResourceType string `json:"resource_type"` + DocumentCount int64 `json:"document_count"` +} + +type ResourceInventoryRecord = ResourceInventoryObservation + +type ResourceInventoryResult struct { + Values []ResourceInventoryObservation `json:"values"` + Available bool `json:"available"` + Complete bool `json:"complete"` + Truncated bool `json:"truncated"` + Status EvidenceStatus `json:"status"` + Digest string `json:"digest,omitempty"` + Diagnostics []EvidenceDiagnostic `json:"diagnostics,omitempty"` +} + +// RelationshipObservation retains both projections of one physical edge +// aggregate. StorageFromType/StorageToType are the original _from/_to +// endpoint types (and StorageDirection is always OUTBOUND for fhir_edge). +// FromType/ToType are the Builder-facing inverse where the generated +// traversal registry supports it; BuilderDirection is the physical AQL +// direction needed to follow that Builder edge. +type RelationshipObservation struct { + Project string `json:"project"` + DatasetGeneration string `json:"dataset_generation,omitempty"` + AuthResourcePath string `json:"auth_resource_path,omitempty"` + FromType string `json:"from_type"` + Label string `json:"label"` + ToType string `json:"to_type"` + EdgeCount int64 `json:"edge_count"` + StorageFromType string `json:"storage_from_type"` + StorageToType string `json:"storage_to_type"` + StorageDirection string `json:"storage_direction"` + BuilderFromType string `json:"builder_from_type"` + BuilderToType string `json:"builder_to_type"` + BuilderDirection string `json:"builder_direction"` +} + +type RelationshipObservationResult struct { + Values []RelationshipObservation `json:"values"` + Available bool `json:"available"` + Complete bool `json:"complete"` + Truncated bool `json:"truncated"` + Status EvidenceStatus `json:"status"` + Digest string `json:"digest,omitempty"` + Diagnostics []EvidenceDiagnostic `json:"diagnostics,omitempty"` +} + +// FieldEnrichmentObservation is a capability-facing copy of the bounded +// profiler summary. It is never used to create row nodes. DistinctTruncated +// describes only that field's bounded suggestions; the result-level Truncated +// flag is reserved for an incomplete enrichment artifact and fails closed for +// capability publication. +type FieldEnrichmentObservation struct { + Project string `json:"project"` + DatasetGeneration string `json:"dataset_generation,omitempty"` + AuthResourcePath string `json:"auth_resource_path,omitempty"` + ResourceType string `json:"resource_type"` + Path string `json:"path"` + Kind string `json:"kind"` + DocCount int64 `json:"doc_count"` + SampleCount int `json:"sample_count"` + DistinctValues []string `json:"distinct_values,omitempty"` + DistinctTruncated bool `json:"distinct_truncated"` + ExtensionValues []ExtensionValueObservation `json:"extension_values,omitempty"` + PivotCandidate bool `json:"pivot_candidate"` + PivotKind string `json:"pivot_kind,omitempty"` + PivotColumns []string `json:"pivot_columns,omitempty"` + PivotFamily string `json:"pivot_family,omitempty"` + PivotColumnSelect string `json:"pivot_column_selector,omitempty"` + PivotValueSelect string `json:"pivot_value_selector,omitempty"` + PivotItemSource string `json:"pivot_item_source,omitempty"` + PivotItemResourceType string `json:"pivot_item_resource_type,omitempty"` + PivotValueSelectors []string `json:"pivot_value_selectors,omitempty"` +} + +type FieldEnrichmentResult struct { + Values []FieldEnrichmentObservation `json:"values"` + Available bool `json:"available"` + Complete bool `json:"complete"` + Truncated bool `json:"truncated"` + Status EvidenceStatus `json:"status"` + Digest string `json:"digest,omitempty"` + Diagnostics []EvidenceDiagnostic `json:"diagnostics,omitempty"` +} + +// CapabilityEvidence is the neutral aggregate consumed by a snapshot +// compiler. The three reads remain separately inspectable so optional field +// enrichment cannot make resource inventory or relationship evidence vanish. +type CapabilityEvidence struct { + ResourceInventory ResourceInventoryResult `json:"resource_inventory"` + Relationships RelationshipObservationResult `json:"relationships"` + FieldEnrichment FieldEnrichmentResult `json:"field_enrichment"` +} + +type CapabilityEvidenceReader interface { + DiscoverResourceInventory(context.Context, ResourceInventoryOptions) (ResourceInventoryResult, error) + DiscoverRelationshipObservations(context.Context, RelationshipObservationOptions) (RelationshipObservationResult, error) + DiscoverFieldEnrichment(context.Context, FieldEnrichmentOptions) (FieldEnrichmentResult, error) +} + // Write-side catalog records persisted during load. type FieldCatalogDocument struct { Key string `json:"_key"` @@ -164,6 +319,7 @@ type Profiler struct { datasetGeneration string authResourcePath string resourceType string + limits ProfileLimits shapeCache *ShapePlanCache stats map[string]*fieldCatalogStats } @@ -191,8 +347,9 @@ type fieldCatalogStats struct { // Shared write-side shape planning cache. type ShapePlanCache struct { - mu sync.RWMutex - plans map[string]*shapePlan + mu sync.RWMutex + plans map[string]*shapePlan + maxPlans int } type shapePlan struct { diff --git a/internal/catalog/write_profiler.go b/internal/catalog/write_profiler.go index 43b3a82e..c979b390 100644 --- a/internal/catalog/write_profiler.go +++ b/internal/catalog/write_profiler.go @@ -12,18 +12,33 @@ import ( ) func NewShapePlanCache() *ShapePlanCache { - return &ShapePlanCache{plans: make(map[string]*shapePlan)} + return NewShapePlanCacheWithLimit(DefaultProfileLimits().MaxShapePlans) +} + +func NewShapePlanCacheWithLimit(maxPlans int) *ShapePlanCache { + return &ShapePlanCache{plans: make(map[string]*shapePlan), maxPlans: maxPlans} } // NewProfilerForGeneration constructs a profiler whose catalog documents are // bound to one immutable dataset generation. A blank (or whitespace-only) // generation intentionally selects the legacy namespace for compatibility. func NewProfilerForGeneration(project, datasetGeneration, authResourcePath, resourceType string, cache *ShapePlanCache) *Profiler { + return NewProfilerForGenerationWithLimits(project, datasetGeneration, authResourcePath, resourceType, cache, DefaultProfileLimits()) +} + +// NewProfilerForGenerationWithLimits constructs a profiler with explicit +// bounds for every write-side catalog structure. +func NewProfilerForGenerationWithLimits(project, datasetGeneration, authResourcePath, resourceType string, cache *ShapePlanCache, limits ProfileLimits) *Profiler { + limits = limits.normalized() + if cache == nil { + cache = NewShapePlanCacheWithLimit(limits.MaxShapePlans) + } return &Profiler{ project: project, datasetGeneration: NormalizeDatasetGeneration(datasetGeneration), authResourcePath: authResourcePath, resourceType: resourceType, + limits: limits, shapeCache: cache, stats: make(map[string]*fieldCatalogStats), } @@ -48,20 +63,23 @@ func (p *Profiler) ObservePayload(payload map[string]any, timings map[string]flo continue } stat := p.ensureStat(field) + if stat == nil { + continue + } stat.docCount++ switch field.Kind { case fieldKindScalar: for _, value := range values { if text, ok := scalarStringValue(value); ok { - stat.addDistinct(text) + stat.addDistinctWithLimits(text, p.limits) } } case fieldKindCodeableConcept: for _, value := range values { if cc, ok := value.(map[string]any); ok { for _, col := range codeableConceptColumns(cc) { - stat.addPivotColumn(col) - stat.addDistinct(col) + stat.addPivotColumnWithLimits(col, p.limits) + stat.addDistinctWithLimits(col, p.limits) } } } @@ -124,6 +142,9 @@ func (p *Profiler) Merge(other *Profiler) error { for path, otherStat := range other.stats { stat, ok := p.stats[path] if !ok { + if p.limits.MaxFields > 0 && len(p.stats) >= p.limits.MaxFields { + continue + } stat = &fieldCatalogStats{ path: otherStat.path, kind: otherStat.kind, @@ -146,13 +167,13 @@ func (p *Profiler) Merge(other *Profiler) error { stat.setPivotDefaults(otherStat.pivotFamily, otherStat.pivotColumnSelect, otherStat.pivotValueSelect) stat.setPivotScope(otherStat.pivotItemSource, otherStat.pivotItemResourceType, otherStat.pivotValueSelectors) for _, value := range otherStat.distinctValues { - stat.addDistinct(value) + stat.addDistinctWithLimits(value, p.limits) } for _, value := range otherStat.pivotColumns { - stat.addPivotColumn(value) + stat.addPivotColumnWithLimits(value, p.limits) } for _, observation := range otherStat.extensionValues { - stat.addExtensionValue(observation) + stat.addExtensionValueWithLimits(observation, p.limits) } } return nil @@ -216,6 +237,9 @@ func (p *Profiler) ensureStat(field *fieldPlan) *fieldCatalogStats { if stat, ok := p.stats[field.Path]; ok { return stat } + if p.limits.MaxFields > 0 && len(p.stats) >= p.limits.MaxFields { + return nil + } stat := &fieldCatalogStats{ path: field.Path, kind: field.Kind, @@ -240,30 +264,53 @@ func (p *Profiler) ensureStat(field *fieldPlan) *fieldCatalogStats { } func (s *fieldCatalogStats) addDistinct(value string) { + s.addDistinctWithLimits(value, DefaultProfileLimits()) +} + +func (s *fieldCatalogStats) addDistinctWithLimits(value string, limits ProfileLimits) { value = strings.TrimSpace(value) if value == "" { return } + limits = limits.normalized() if _, ok := s.distinctSet[value]; ok { return } + if len(value) > limits.MaxDistinctValueBytes || len(s.distinctValues) >= limits.MaxDistinctValuesPerField { + s.distinctTruncated = true + return + } s.distinctSet[value] = struct{}{} s.distinctValues = append(s.distinctValues, value) } func (s *fieldCatalogStats) addPivotColumn(value string) { + s.addPivotColumnWithLimits(value, DefaultProfileLimits()) +} + +func (s *fieldCatalogStats) addPivotColumnWithLimits(value string, limits ProfileLimits) { value = strings.TrimSpace(value) if value == "" { return } + limits = limits.normalized() if _, ok := s.pivotColumnSet[value]; ok { return } + if len(value) > limits.MaxDistinctValueBytes || len(s.pivotColumns) >= limits.MaxPivotColumnsPerField { + s.distinctTruncated = true + return + } s.pivotColumnSet[value] = struct{}{} s.pivotColumns = append(s.pivotColumns, value) } func (s *fieldCatalogStats) addExtensionValue(observation ExtensionValueObservation) { + s.addExtensionValueWithLimits(observation, DefaultProfileLimits()) +} + +func (s *fieldCatalogStats) addExtensionValueWithLimits(observation ExtensionValueObservation, limits ProfileLimits) { + limits = limits.normalized() observation.URL = strings.TrimSpace(observation.URL) observation.SourcePath = strings.TrimSpace(observation.SourcePath) observation.ValuePath = strings.TrimSpace(observation.ValuePath) @@ -271,6 +318,16 @@ func (s *fieldCatalogStats) addExtensionValue(observation ExtensionValueObservat if observation.URL == "" || observation.SourcePath == "" || observation.ValueType == "" { return } + if len(observation.URL) > limits.MaxDistinctValueBytes || len(observation.SourcePath) > limits.MaxDistinctValueBytes || len(observation.ValuePath) > limits.MaxDistinctValueBytes { + s.distinctTruncated = true + return + } + for _, ancestor := range observation.URLPath { + if len(ancestor) > limits.MaxDistinctValueBytes { + s.distinctTruncated = true + return + } + } if s.extensionValueSet == nil { s.extensionValueSet = make(map[string]struct{}) } @@ -278,6 +335,10 @@ func (s *fieldCatalogStats) addExtensionValue(observation ExtensionValueObservat if _, ok := s.extensionValueSet[key]; ok { return } + if len(s.extensionValues) >= limits.MaxExtensionValuesPerField { + s.distinctTruncated = true + return + } s.extensionValueSet[key] = struct{}{} s.extensionValues = append(s.extensionValues, observation) } @@ -296,12 +357,15 @@ func walkExtensionValuesWithAncestors(value any, path string, profiler *Profiler isExtension := strings.HasSuffix(path, "extension[]") if url, ok := typed["url"].(string); ok && strings.TrimSpace(url) != "" && isExtension { stat := profiler.ensureExtensionURLStat(path + ".url") + if stat == nil { + return + } for key, raw := range typed { if !strings.HasPrefix(key, "value") || len(key) == len("value") || raw == nil { continue } valuePath, valueType := extensionValueMapping(key, raw) - stat.addExtensionValue(ExtensionValueObservation{URL: url, SourcePath: path, ValuePath: valuePath, ValueType: valueType, URLPath: append([]string(nil), ancestors...)}) + stat.addExtensionValueWithLimits(ExtensionValueObservation{URL: url, SourcePath: path, ValuePath: valuePath, ValueType: valueType, URLPath: append([]string(nil), ancestors...)}, profiler.limits) } } for _, key := range sortedKeys(typed) { @@ -334,6 +398,9 @@ func (p *Profiler) ensureExtensionURLStat(path string) *fieldCatalogStats { if stat, ok := p.stats[path]; ok { return stat } + if p.limits.MaxFields > 0 && len(p.stats) >= p.limits.MaxFields { + return nil + } stat := &fieldCatalogStats{path: path, kind: fieldKindScalar, distinctSet: make(map[string]struct{}), pivotColumnSet: make(map[string]struct{}), extensionValueSet: make(map[string]struct{})} p.stats[path] = stat return stat @@ -413,6 +480,9 @@ func (c *ShapePlanCache) getOrBuild(fingerprint string, payload map[string]any) return plan } plan = buildShapePlan(payload) + if c.maxPlans > 0 && len(c.plans) >= c.maxPlans { + return plan + } c.plans[fingerprint] = plan return plan } @@ -552,6 +622,9 @@ func (p *Profiler) observeObservationCodePivot(payload map[string]any) { } stat, ok := p.stats["code"] if !ok { + if p.limits.MaxFields > 0 && len(p.stats) >= p.limits.MaxFields { + return + } stat = &fieldCatalogStats{ path: "code", kind: fieldKindCodeableConcept, @@ -570,7 +643,7 @@ func (p *Profiler) observeObservationCodePivot(payload map[string]any) { } stat.setPivotDefaults(fhirschema.PivotFamilyObservationCodeValue, columnSelector, valueSelector) for _, col := range codeableConceptColumns(codeValue) { - stat.addPivotColumn(col) + stat.addPivotColumnWithLimits(col, p.limits) } } diff --git a/internal/catalog/write_profiler_test.go b/internal/catalog/write_profiler_test.go index 9c2993bb..a2e575bb 100644 --- a/internal/catalog/write_profiler_test.go +++ b/internal/catalog/write_profiler_test.go @@ -28,6 +28,41 @@ func TestFieldCatalogRetainsAllDynamicKeys(t *testing.T) { } } +func TestFieldCatalogProfilerBoundsHighCardinalityValues(t *testing.T) { + limits := ProfileLimits{ + MaxFields: 8, + MaxDistinctValuesPerField: 2, + MaxDistinctValueBytes: 4, + MaxPivotColumnsPerField: 2, + MaxExtensionValuesPerField: 2, + MaxShapePlans: 1, + } + profiler := NewProfilerForGenerationWithLimits("TEST", "generation-a", "", "Patient", nil, limits) + for _, id := range []string{"a", "b", "c", "too-long"} { + profiler.ObservePayload(map[string]any{"id": id}, map[string]float64{}) + } + + var idField FieldCatalogDocument + for _, document := range profiler.Documents() { + if document.Path == "id" { + idField = document + break + } + } + if len(idField.DistinctValues) != 2 || !idField.DistinctTruncated { + t.Fatalf("bounded id catalog = %#v, want two values and truncation", idField) + } +} + +func TestShapePlanCacheHonorsLimit(t *testing.T) { + cache := NewShapePlanCacheWithLimit(1) + cache.getOrBuild("shape-a", map[string]any{"id": "a"}) + cache.getOrBuild("shape-b", map[string]any{"name": "b"}) + if got := len(cache.plans); got != 1 { + t.Fatalf("shape plan cache size = %d, want 1", got) + } +} + func TestFieldCatalogProfilerCanonicalPaths(t *testing.T) { cache := NewShapePlanCache() profiler := NewProfilerForGeneration("TEST", "", "pathA", "Observation", cache) diff --git a/internal/dataframe/compiler/capability/probe.go b/internal/dataframe/compiler/capability/probe.go new file mode 100644 index 00000000..8922e87c --- /dev/null +++ b/internal/dataframe/compiler/capability/probe.go @@ -0,0 +1,758 @@ +// Package capability contains compiler-backed capability probes. +// +// A probe is deliberately expressed in schema and semantic terms. It does +// not know about catalog rows, Explorer wire types, or a particular storage +// adapter. A successful probe is an executable proof: the request passed the +// generated schema, semantic validation, physical lowering, optimization, +// and canonical AQL renderer. +package capability + +import ( + "context" + "fmt" + "strings" + + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/dataframe/compiler/ir" + "github.com/calypr/loom/internal/dataframe/compiler/lower" + "github.com/calypr/loom/internal/dataframe/compiler/optimize" + "github.com/calypr/loom/internal/dataframe/compiler/render/aql" + "github.com/calypr/loom/internal/dataframe/expression" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataframe/semantic" + "github.com/calypr/loom/internal/dataframe/spec" + fhirschema "github.com/calypr/loom/internal/fhir/schema" +) + +// Scope is the request provenance carried into every successful proof. The +// same values are placed in the physical plan and consequently in rendered +// bind variables; consumers must not treat a query without this provenance as +// an advertised capability. +type Scope struct { + Project string + DatasetGeneration string + AuthResourcePaths []string + AuthScopeMode authscope.ReadScopeMode +} + +// Traversal describes one authoring-direction relationship. The source, +// label, and target are all required so an observed edge cannot be silently +// matched to an ambiguous generated relationship. +type Traversal struct { + FromResourceType string + EdgeLabel string + ToResourceType string + Alias string + MatchMode spec.TraversalMatchMode +} + +// Filter describes an optional candidate filter operation. Values are typed +// semantic values, not query fragments. When Values is empty, ProbeCandidate +// supplies a harmless typed sample solely to exercise the compiler path. +type Filter struct { + Operator spec.FilterOperator + Quantifier spec.ArrayQuantifier + FieldKind spec.FilterValueKind + Values []spec.FilterValue +} + +// Chart describes an optional candidate chart/aggregate operation. +type Chart struct { + Operation recipe.AggregateOperation +} + +// RootRequest asks whether one concrete generated resource can be a row root. +type RootRequest struct { + Scope + ResourceType string +} + +// TraversalRequest asks whether one exact relationship can be lowered and +// rendered from a concrete root. It proves storage direction as well as the +// generated logical relationship. +type TraversalRequest struct { + Scope + RootResourceType string + Traversal +} + +// CandidateRequest asks whether a selector and its requested operation can be +// compiled at an occurrence. Route is optional for a zero-hop candidate and +// is a sequence of exact one-hop traversals for a candidate on a related node. +type CandidateRequest struct { + Scope + RootResourceType string + ResourceType string + FieldRef string + Selector string + Route []Traversal + Projection spec.ProjectionMode + Filter *Filter + Chart *Chart +} + +// CostEstimate is intentionally descriptive rather than a hidden limit. A +// caller may install a policy that rejects an expensive finite request while +// still allowing arbitrary route depth when its own budget permits it. +type CostEstimate struct { + TraversalCount int + CandidateCount int +} + +// CostPolicy is an optional request-scoped safety hook. It is called before +// compilation and receives the context supplied to the probe. +type CostPolicy interface { + Allow(context.Context, CostEstimate) error +} + +type CostPolicyFunc func(context.Context, CostEstimate) error + +func (f CostPolicyFunc) Allow(ctx context.Context, estimate CostEstimate) error { + if f == nil { + return nil + } + return f(ctx, estimate) +} + +// Options controls the explicitly authorized physical rewrite and cost +// policy. The default is the same conservative policy used by normal recipe +// compilation. +type Options struct { + Policy ir.PhysicalOptimizationPolicy + Cost CostPolicy + CostLimit int +} + +func (o Options) normalized() Options { + if !o.Policy.Enabled && o.Policy.MinimumSavings == 0 && o.Policy.RuleOverrides == nil { + o.Policy = ir.DefaultPhysicalOptimizationPolicy() + } + return o +} + +// Rendered is the executable proof and its scope provenance. +type Rendered struct { + Query string + BindVars map[string]any + Project string + DatasetGeneration string + AuthResourcePaths []string + AuthScopeMode authscope.ReadScopeMode +} + +type RootCapability struct { + ResourceType string + CanonicalType string + RowGrain spec.RowGrain + RowRootEligible bool + Rendered Rendered +} + +type TraversalCapability struct { + FromResourceType string + EdgeLabel string + ToResourceType string + SchemaDirection fhirschema.TraversalDirection + StorageDirection ir.PhysicalTraversalDirection + Multiplicity fhirschema.TraversalMultiplicity + Rendered Rendered +} + +type CandidateCapability struct { + ResourceType string + FieldRef string + Selector string + FieldKind fhirschema.FieldKind + Primitive fhirschema.PrimitiveKind + Cardinality spec.Cardinality + Repeated bool + ProjectionModes []spec.ProjectionMode + FilterOperators []spec.FilterOperator + ChartOperations []recipe.AggregateOperation + Filterable bool + Chartable bool + Rendered Rendered +} + +type Result struct { + Root *RootCapability + Traversal *TraversalCapability + Candidate *CandidateCapability + Rendered Rendered +} + +// ProbeRoot compiles and renders a zero-hop concrete row root. +func ProbeRoot(ctx context.Context, request RootRequest, options ...Options) (Result, error) { + if err := contextErr(ctx); err != nil { + return Result{}, err + } + request.ResourceType = strings.TrimSpace(request.ResourceType) + canonical, ok := fhirschema.ConcreteResourceType(request.ResourceType) + if !ok { + return Result{}, fmt.Errorf("resource type %q is not a concrete generated FHIR resource", request.ResourceType) + } + rowGrain, ok := spec.InferRowGrain(canonical) + if !ok { + return Result{}, fmt.Errorf("resource type %q has no supported row grain", canonical) + } + physical, rendered, err := compile(ctx, request.Scope, semantic.SemanticPlan{Version: 1, Project: request.Project, DatasetGeneration: request.DatasetGeneration, AuthResourcePaths: cloneStrings(request.AuthResourcePaths), AuthScopeMode: request.AuthScopeMode, Root: semantic.SemanticNode{Alias: "root", ResourceType: canonical}}, optionsFor(options)) + _ = physical + if err != nil { + return Result{}, err + } + capability := RootCapability{ResourceType: request.ResourceType, CanonicalType: canonical, RowGrain: rowGrain, RowRootEligible: true, Rendered: rendered} + return Result{Root: &capability, Rendered: rendered}, nil +} + +// ProbeTraversal compiles one exact one-hop route and reports the direction +// selected by the storage-route proof in the shared lowerer. +func ProbeTraversal(ctx context.Context, request TraversalRequest, options ...Options) (Result, error) { + if strings.TrimSpace(request.Traversal.FromResourceType) == "" { + request.Traversal.FromResourceType = request.RootResourceType + } + if err := validateTraversalRequest(request.RootResourceType, request.Traversal); err != nil { + return Result{}, err + } + rootType, ok := fhirschema.ConcreteResourceType(request.RootResourceType) + if !ok { + return Result{}, fmt.Errorf("resource type %q is not a concrete generated FHIR resource", request.RootResourceType) + } + toType, _ := fhirschema.ConcreteResourceType(request.ToResourceType) + child := semantic.SemanticNode{Alias: routeAlias(request.Alias, 1), ResourceType: toType, EdgeLabel: request.EdgeLabel, MatchMode: request.MatchMode} + plan := semantic.SemanticPlan{Version: 1, Project: request.Project, DatasetGeneration: request.DatasetGeneration, AuthResourcePaths: cloneStrings(request.AuthResourcePaths), AuthScopeMode: request.AuthScopeMode, Root: semantic.SemanticNode{Alias: "root", ResourceType: rootType, Children: []semantic.SemanticNode{child}}} + physical, rendered, err := compile(ctx, request.Scope, plan, optionsFor(options)) + if err != nil { + return Result{}, err + } + traversal, ok := findTraversal(physical) + if !ok { + return Result{}, fmt.Errorf("route %s -[%s]-> %s did not produce a physical traversal", rootType, request.EdgeLabel, request.ToResourceType) + } + relationship, found, err := fhirschema.ResolveCompilerTraversal(rootType, request.EdgeLabel, toType) + if err != nil { + return Result{}, err + } + if !found { + return Result{}, fmt.Errorf("route %s -[%s]-> %s is not represented by the active generated FHIR schema", rootType, request.EdgeLabel, toType) + } + capability := TraversalCapability{FromResourceType: rootType, EdgeLabel: request.EdgeLabel, ToResourceType: toType, SchemaDirection: relationship.Direction, StorageDirection: traversal.Direction, Multiplicity: relationship.Multiplicity, Rendered: rendered} + return Result{Traversal: &capability, Rendered: rendered}, nil +} + +// ProbeCandidate compiles a candidate projection, filter, or chart operation. +// It also probes every operation supported by the shared compiler so the +// returned metadata can be used directly by a capability builder. +func ProbeCandidate(ctx context.Context, request CandidateRequest, options ...Options) (Result, error) { + optionsValue := optionsFor(options) + prepared, err := prepareCandidate(request) + if err != nil { + return Result{}, err + } + if err := contextErr(ctx); err != nil { + return Result{}, err + } + if optionsValue.Cost != nil { + if err := optionsValue.Cost.Allow(ctx, CostEstimate{TraversalCount: len(request.Route), CandidateCount: 1}); err != nil { + return Result{}, err + } + } + fieldKind := prepared.fieldKind + metadata := CandidateCapability{ResourceType: prepared.resourceType, FieldRef: prepared.fieldRef, Selector: prepared.selector.CanonicalPath(), FieldKind: fieldKind, Primitive: prepared.primitive, Cardinality: prepared.cardinality, Repeated: prepared.repeated} + projectionModes := []spec.ProjectionMode{spec.ProjectionScalar, spec.ProjectionFirst, spec.ProjectionArray, spec.ProjectionDistinctArray} + for _, mode := range projectionModes { + if _, _, err := compileCandidate(ctx, prepared, mode, nil, nil, optionsValue); err == nil { + metadata.ProjectionModes = append(metadata.ProjectionModes, mode) + } + } + if len(metadata.ProjectionModes) == 0 { + return Result{}, fmt.Errorf("candidate %s.%s has no compiler-supported projection mode", prepared.resourceType, prepared.selector.CanonicalPath()) + } + for _, operator := range []spec.FilterOperator{spec.FilterEquals, spec.FilterNotEquals, spec.FilterIn, spec.FilterExists, spec.FilterMissing, spec.FilterContains, spec.FilterGreaterThan, spec.FilterGreaterEq, spec.FilterLessThan, spec.FilterLessEq} { + filter, ok := sampleFilter(prepared, operator) + if !ok { + continue + } + if _, _, err := compileCandidate(ctx, prepared, defaultProjection(prepared.repeated), &filter, nil, optionsValue); err == nil { + metadata.FilterOperators = append(metadata.FilterOperators, operator) + } + } + for _, operation := range []recipe.AggregateOperation{recipe.AggregateCount, recipe.AggregateCountDistinct, recipe.AggregateExists, recipe.AggregateDistinctValues, recipe.AggregateMin, recipe.AggregateMax} { + if _, _, err := compileCandidate(ctx, prepared, defaultProjection(prepared.repeated), nil, &Chart{Operation: operation}, optionsValue); err == nil { + metadata.ChartOperations = append(metadata.ChartOperations, operation) + } + } + metadata.Filterable = len(metadata.FilterOperators) != 0 + metadata.Chartable = len(metadata.ChartOperations) != 0 + mode := request.Projection + if mode == "" { + mode = defaultProjection(prepared.repeated) + } + filter := request.Filter + chart := request.Chart + if filter != nil && filter.FieldKind == "" { + filterCopy := *filter + filterCopy.FieldKind = filterKindForPrimitive(prepared.primitive) + filter = &filterCopy + } + _, rendered, err := compileCandidate(ctx, prepared, mode, filter, chart, optionsValue) + if err != nil { + return Result{}, err + } + metadata.Rendered = rendered + return Result{Candidate: &metadata, Rendered: rendered}, nil +} + +// Request groups probes for snapshot construction. Unsupported entries are +// returned as diagnostics so a caller can retain audit evidence while only +// publishing successful capabilities. +type Request struct { + Scope Scope + RootResourceType string + Roots []string + Traversals []Traversal + Candidates []CandidateRequest +} + +type Diagnostic struct { + Kind string + Message string +} + +type Snapshot struct { + Roots []RootCapability + Traversals []TraversalCapability + Candidates []CandidateCapability + Diagnostics []Diagnostic +} + +func ProbeCapabilities(ctx context.Context, request Request, options ...Options) (Snapshot, error) { + optionsValue := optionsFor(options) + roots := append([]string(nil), request.Roots...) + if len(roots) == 0 && strings.TrimSpace(request.RootResourceType) != "" { + roots = []string{request.RootResourceType} + } + if optionsValue.Cost != nil { + if err := optionsValue.Cost.Allow(ctx, CostEstimate{TraversalCount: len(request.Traversals), CandidateCount: len(request.Candidates)}); err != nil { + return Snapshot{}, err + } + } + snapshot := Snapshot{} + for _, root := range roots { + result, err := ProbeRoot(ctx, RootRequest{Scope: request.Scope, ResourceType: root}, optionsValue) + if err != nil { + snapshot.Diagnostics = append(snapshot.Diagnostics, Diagnostic{Kind: "root", Message: err.Error()}) + continue + } + snapshot.Roots = append(snapshot.Roots, *result.Root) + } + for _, route := range request.Traversals { + result, err := ProbeTraversal(ctx, TraversalRequest{Scope: request.Scope, RootResourceType: request.RootResourceType, Traversal: route}, optionsValue) + if err != nil { + snapshot.Diagnostics = append(snapshot.Diagnostics, Diagnostic{Kind: "traversal", Message: err.Error()}) + continue + } + snapshot.Traversals = append(snapshot.Traversals, *result.Traversal) + } + for _, candidate := range request.Candidates { + if candidate.Project == "" { + candidate.Scope = request.Scope + } + result, err := ProbeCandidate(ctx, candidate, optionsValue) + if err != nil { + snapshot.Diagnostics = append(snapshot.Diagnostics, Diagnostic{Kind: "candidate", Message: err.Error()}) + continue + } + snapshot.Candidates = append(snapshot.Candidates, *result.Candidate) + } + return snapshot, nil +} + +// Probe is the concise entry point for callers constructing a capability +// snapshot. The named ProbeCapabilities form remains useful at call sites +// where the distinction from the individual probes matters. +func Probe(ctx context.Context, request Request, options ...Options) (Snapshot, error) { + return ProbeCapabilities(ctx, request, options...) +} + +// ProbeZeroHop and ProbeOneHop are descriptive aliases for the primitive +// probes, kept small so backend adapters do not need to know the package's +// internal naming choices. +func ProbeZeroHop(ctx context.Context, request RootRequest, options ...Options) (Result, error) { + return ProbeRoot(ctx, request, options...) +} + +func ProbeOneHop(ctx context.Context, request TraversalRequest, options ...Options) (Result, error) { + return ProbeTraversal(ctx, request, options...) +} + +func ProbeSelection(ctx context.Context, request CandidateRequest, options ...Options) (Result, error) { + return ProbeCandidate(ctx, request, options...) +} + +type preparedCandidate struct { + scope Scope + resourceType string + fieldRef string + selector spec.Selector + fieldKind fhirschema.FieldKind + primitive fhirschema.PrimitiveKind + cardinality spec.Cardinality + repeated bool + root semantic.SemanticNode +} + +func prepareCandidate(request CandidateRequest) (preparedCandidate, error) { + rootType := strings.TrimSpace(request.RootResourceType) + if rootType == "" { + rootType = strings.TrimSpace(request.ResourceType) + } + canonicalRoot, ok := fhirschema.ConcreteResourceType(rootType) + if !ok { + return preparedCandidate{}, fmt.Errorf("resource type %q is not a concrete generated FHIR resource", rootType) + } + resourceType, ok := fhirschema.ConcreteResourceType(request.ResourceType) + if !ok { + return preparedCandidate{}, fmt.Errorf("candidate resource type %q is not a concrete generated FHIR resource", request.ResourceType) + } + selector, err := spec.ParseSelector(request.Selector) + if err != nil { + return preparedCandidate{}, fmt.Errorf("candidate selector: %w", err) + } + fieldKind := fhirschema.FieldKindUnknown + if semantics, found := fhirschema.ResolveFieldSemantics(resourceType, selector.CanonicalPath()); found { + fieldKind = semantics.Kind + } else { + return preparedCandidate{}, fmt.Errorf("candidate selector %q is not in the active FHIR schema for %s", request.Selector, resourceType) + } + terminal, found := fhirschema.ResolveTerminalScalarMetadata(resourceType, selector.CanonicalPath()) + if !found { + return preparedCandidate{}, fmt.Errorf("candidate selector %q has no terminal metadata for %s", request.Selector, resourceType) + } + repeated, _, err := spec.SelectorCardinality(resourceType, selector) + if err != nil { + return preparedCandidate{}, fmt.Errorf("candidate selector %q: %w", request.Selector, err) + } + if terminal.Repeated { + repeated = true + } + cardinality := spec.CardinalityOptionalOne + if repeated { + cardinality = spec.CardinalityMany + } + root := semantic.SemanticNode{Alias: "root", ResourceType: canonicalRoot} + current := &root + for index, route := range request.Route { + if strings.TrimSpace(route.FromResourceType) == "" { + route.FromResourceType = current.ResourceType + } + if err := validateTraversalRequest(current.ResourceType, route); err != nil { + return preparedCandidate{}, err + } + toType, _ := fhirschema.ConcreteResourceType(route.ToResourceType) + child := semantic.SemanticNode{Alias: routeAlias(route.Alias, index+1), ResourceType: toType, EdgeLabel: route.EdgeLabel, MatchMode: route.MatchMode} + current.Children = append(current.Children, child) + current = ¤t.Children[len(current.Children)-1] + } + if current.ResourceType != resourceType { + return preparedCandidate{}, fmt.Errorf("candidate resource type %q does not match route terminal %q", resourceType, current.ResourceType) + } + fieldRef := strings.TrimSpace(request.FieldRef) + if fieldRef == "" { + fieldRef = resourceType + "." + selector.CanonicalPath() + } + return preparedCandidate{scope: request.Scope, resourceType: resourceType, fieldRef: fieldRef, selector: selector, fieldKind: fieldKind, primitive: terminal.Primitive, cardinality: cardinality, repeated: repeated, root: root}, nil +} + +func compileCandidate(ctx context.Context, prepared preparedCandidate, mode spec.ProjectionMode, filter *Filter, chart *Chart, options Options) (ir.PhysicalPlan, Rendered, error) { + if err := contextErr(ctx); err != nil { + return ir.PhysicalPlan{}, Rendered{}, err + } + if err := validateCandidateProjection(prepared, mode); err != nil { + return ir.PhysicalPlan{}, Rendered{}, err + } + field := semantic.SemanticField{Name: "candidate", FieldRef: prepared.fieldRef, Selector: prepared.selector, ValueMode: valueMode(mode), ExprType: expression.Type{Kind: expression.KindObject, Cardinality: expression.OptionalOne}} + if prepared.primitive != fhirschema.PrimitiveUnknown { + field.ExprType.Kind = expressionKind(prepared.primitive) + } + if prepared.repeated { + field.ExprType.Cardinality = expression.Many + } + root := prepared.root + target := &root + for len(target.Children) != 0 { + target = &target.Children[len(target.Children)-1] + } + target.Fields = []semantic.SemanticField{field} + if filter != nil { + typed, err := typedFilter(prepared, *filter) + if err != nil { + return ir.PhysicalPlan{}, Rendered{}, err + } + target.Filters = []spec.TypedFilter{typed} + } + if chart != nil { + if chart.Operation == "" { + return ir.PhysicalPlan{}, Rendered{}, fmt.Errorf("chart operation is required") + } + selector := prepared.selector + target.Aggregates = []semantic.SemanticAggregate{{Name: "chart", Operation: string(chart.Operation), FieldRef: prepared.fieldRef, Selector: &selector}} + } + plan := semantic.SemanticPlan{Version: 1, Root: root} + physical, rendered, err := compile(ctx, prepared.scope, plan, options) + return physical, rendered, err +} + +func validateCandidateProjection(prepared preparedCandidate, mode spec.ProjectionMode) error { + if err := spec.ValidateProjection(prepared.cardinality, mode); err != nil { + return err + } + if !prepared.repeated && (mode == spec.ProjectionArray || mode == spec.ProjectionDistinctArray) { + return fmt.Errorf("%s projection cannot represent scalar candidate %s", mode, prepared.selector.CanonicalPath()) + } + return nil +} + +func compile(ctx context.Context, scope Scope, plan semantic.SemanticPlan, options Options) (ir.PhysicalPlan, Rendered, error) { + if err := contextErr(ctx); err != nil { + return ir.PhysicalPlan{}, Rendered{}, err + } + options = options.normalized() + if options.Cost != nil { + if err := options.Cost.Allow(ctx, CostEstimate{TraversalCount: countSemanticTraversals(plan.Root)}); err != nil { + return ir.PhysicalPlan{}, Rendered{}, err + } + } + plan.Project = scope.Project + plan.DatasetGeneration = scope.DatasetGeneration + plan.AuthResourcePaths = cloneStrings(scope.AuthResourcePaths) + plan.AuthScopeMode = scope.AuthScopeMode + physical, err := lower.BuildGenericPhysicalPlanWithPolicy(plan, options.Policy) + if err != nil { + return ir.PhysicalPlan{}, Rendered{}, err + } + optimized, err := optimize.OptimizePhysicalPlanWithPolicy(physical, options.Policy) + if err != nil { + return ir.PhysicalPlan{}, Rendered{}, err + } + if err := contextErr(ctx); err != nil { + return ir.PhysicalPlan{}, Rendered{}, err + } + rendered, err := aql.RenderPhysicalPlan(optimized) + if err != nil { + return ir.PhysicalPlan{}, Rendered{}, err + } + return optimized, Rendered{Query: rendered.Query, BindVars: rendered.BindVars, Project: scope.Project, DatasetGeneration: scope.DatasetGeneration, AuthResourcePaths: cloneStrings(scope.AuthResourcePaths), AuthScopeMode: scope.AuthScopeMode}, nil +} + +func optionsFor(options []Options) Options { + if len(options) == 0 { + return Options{}.normalized() + } + return options[0].normalized() +} + +func validateTraversalRequest(root string, route Traversal) error { + canonicalRoot, ok := fhirschema.ConcreteResourceType(root) + if !ok { + return fmt.Errorf("resource type %q is not a concrete generated FHIR resource", root) + } + from, ok := fhirschema.ConcreteResourceType(route.FromResourceType) + if !ok { + return fmt.Errorf("traversal source resource type %q is not a concrete generated FHIR resource", route.FromResourceType) + } + if from != canonicalRoot { + return fmt.Errorf("traversal source %q does not match current resource %q", from, canonicalRoot) + } + if strings.TrimSpace(route.EdgeLabel) == "" || strings.TrimSpace(route.ToResourceType) == "" { + return fmt.Errorf("traversal source, edge label, and target are required") + } + to, ok := fhirschema.ConcreteResourceType(route.ToResourceType) + if !ok { + return fmt.Errorf("traversal target resource type %q is not a concrete generated FHIR resource", route.ToResourceType) + } + if _, found := fhirschema.LookupTraversal(from, route.EdgeLabel, to); !found { + return fmt.Errorf("traversal %s -[%s]-> %s is not represented by the active generated FHIR schema", from, route.EdgeLabel, to) + } + if err := route.MatchMode.Validate(); err != nil { + return err + } + return nil +} + +func routeAlias(alias string, index int) string { + if strings.TrimSpace(alias) != "" { + return strings.TrimSpace(alias) + } + return fmt.Sprintf("route_%d", index) +} + +func typedFilter(prepared preparedCandidate, filter Filter) (spec.TypedFilter, error) { + kind := filter.FieldKind + if kind == "" { + kind = filterKindForPrimitive(prepared.primitive) + } + if kind == "" { + return spec.TypedFilter{}, fmt.Errorf("candidate %s is not a scalar filter candidate", prepared.selector.CanonicalPath()) + } + quantifier := filter.Quantifier + if prepared.repeated && quantifier == "" { + quantifier = spec.QuantifierAny + } + typed := spec.TypedFilter{FieldRef: prepared.fieldRef, Selector: prepared.selector.CanonicalPath(), FieldKind: kind, Repeated: prepared.repeated, Quantifier: quantifier, Operator: filter.Operator, Values: append([]spec.FilterValue(nil), filter.Values...)} + if len(typed.Values) == 0 && typed.Operator != spec.FilterExists && typed.Operator != spec.FilterMissing { + sample, ok := sampleFilter(prepared, typed.Operator) + if !ok { + return spec.TypedFilter{}, fmt.Errorf("operator %s is not supported for candidate %s", typed.Operator, prepared.selector.CanonicalPath()) + } + typed.Values = sample.Values + } + if err := typed.Validate(); err != nil { + return spec.TypedFilter{}, err + } + if err := spec.ValidateTypedFilterForResource(prepared.resourceType, typed); err != nil { + return spec.TypedFilter{}, err + } + return typed, nil +} + +func sampleFilter(prepared preparedCandidate, operator spec.FilterOperator) (Filter, bool) { + kind := filterKindForPrimitive(prepared.primitive) + if kind == "" || !spec.OperatorSupportsKind(operator, kind) { + return Filter{}, false + } + filter := Filter{Operator: operator, FieldKind: kind} + if prepared.repeated { + filter.Quantifier = spec.QuantifierAny + } + if operator == spec.FilterExists || operator == spec.FilterMissing { + filter.Quantifier = "" + return filter, true + } + value := sampleValue(kind) + if operator == spec.FilterIn { + filter.Values = []spec.FilterValue{value} + } else { + filter.Values = []spec.FilterValue{value} + } + return filter, true +} + +func sampleValue(kind spec.FilterValueKind) spec.FilterValue { + value := spec.FilterValue{Kind: kind} + switch kind { + case spec.FilterString: + v := "probe" + value.String = &v + case spec.FilterCode: + value.Code = &spec.CodeValue{Code: "probe"} + case spec.FilterBoolean: + v := true + value.Boolean = &v + case spec.FilterInteger: + v := int64(1) + value.Integer = &v + case spec.FilterDecimal: + v := 1.0 + value.Decimal = &v + case spec.FilterDate: + v := "2020-01-01" + value.Date = &v + case spec.FilterDateTime: + v := "2020-01-01T00:00:00Z" + value.DateTime = &v + } + return value +} + +func filterKindForPrimitive(primitive fhirschema.PrimitiveKind) spec.FilterValueKind { + switch primitive { + case fhirschema.PrimitiveString: + return spec.FilterString + case fhirschema.PrimitiveBoolean: + return spec.FilterBoolean + case fhirschema.PrimitiveInteger: + return spec.FilterInteger + case fhirschema.PrimitiveDecimal: + return spec.FilterDecimal + case fhirschema.PrimitiveDate: + return spec.FilterDate + case fhirschema.PrimitiveDateTime: + return spec.FilterDateTime + default: + return "" + } +} + +func expressionKind(primitive fhirschema.PrimitiveKind) expression.ValueKind { + switch primitive { + case fhirschema.PrimitiveBoolean: + return expression.KindBoolean + case fhirschema.PrimitiveInteger: + return expression.KindInteger + case fhirschema.PrimitiveDecimal: + return expression.KindDecimal + case fhirschema.PrimitiveDate: + return expression.KindDate + case fhirschema.PrimitiveDateTime: + return expression.KindDateTime + case fhirschema.PrimitiveString: + return expression.KindString + default: + return expression.KindObject + } +} + +func valueMode(mode spec.ProjectionMode) string { + switch mode { + case spec.ProjectionFirst: + return "FIRST" + case spec.ProjectionArray: + return "ALL" + case spec.ProjectionDistinctArray: + return "DISTINCT" + default: + return "AUTO" + } +} + +func defaultProjection(repeated bool) spec.ProjectionMode { + if repeated { + return spec.ProjectionFirst + } + return spec.ProjectionScalar +} + +func findTraversal(plan ir.PhysicalPlan) (ir.PhysicalTraversal, bool) { + var walk func([]ir.PhysicalOperation) (ir.PhysicalTraversal, bool) + walk = func(operations []ir.PhysicalOperation) (ir.PhysicalTraversal, bool) { + for _, operation := range operations { + if operation.Traversal != nil { + return *operation.Traversal, true + } + if operation.Set != nil { + if traversal, ok := walk(operation.Set.Subplan.Operations); ok { + return traversal, true + } + } + } + return ir.PhysicalTraversal{}, false + } + return walk(plan.Operations) +} + +func countSemanticTraversals(node semantic.SemanticNode) int { + total := len(node.Children) + for _, child := range node.Children { + total += countSemanticTraversals(child) + } + return total +} + +func contextErr(ctx context.Context) error { + if ctx == nil { + return nil + } + return ctx.Err() +} + +func cloneStrings(values []string) []string { return append([]string(nil), values...) } diff --git a/internal/dataframe/compiler/capability/probe_test.go b/internal/dataframe/compiler/capability/probe_test.go new file mode 100644 index 00000000..6ea5babc --- /dev/null +++ b/internal/dataframe/compiler/capability/probe_test.go @@ -0,0 +1,138 @@ +package capability + +import ( + "context" + "strings" + "testing" + + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataframe/spec" +) + +func testScope() Scope { + return Scope{Project: "project-1", DatasetGeneration: "generation-7", AuthScopeMode: authscope.ReadScopeRestricted, AuthResourcePaths: []string{"/programs/p1"}} +} + +func TestProbeRootRejectsBackboneAndCustomButAcceptsGenericResource(t *testing.T) { + if _, err := ProbeRoot(context.Background(), RootRequest{Scope: testScope(), ResourceType: "PractitionerQualification"}); err == nil { + t.Fatal("backbone definition was accepted as a row root") + } + if _, err := ProbeRoot(context.Background(), RootRequest{Scope: testScope(), ResourceType: "CustomResource"}); err == nil { + t.Fatal("custom resource was accepted as a row root") + } + result, err := ProbeRoot(context.Background(), RootRequest{Scope: testScope(), ResourceType: "Observation"}) + if err != nil { + t.Fatalf("generic generated resource was rejected: %v", err) + } + if !result.Root.RowRootEligible || result.Root.RowGrain != spec.RowGrainObservation || result.Rendered.Query == "" { + t.Fatalf("unexpected root capability: %#v", result.Root) + } + assertScopedQuery(t, result.Rendered) +} + +func TestProbeTraversalProvesInboundAndOutboundStorageDirection(t *testing.T) { + inbound, err := ProbeTraversal(context.Background(), TraversalRequest{Scope: testScope(), RootResourceType: "Patient", Traversal: Traversal{EdgeLabel: "subject_Patient", ToResourceType: "Specimen"}}) + if err != nil { + t.Fatalf("inbound route: %v", err) + } + if inbound.Traversal.StorageDirection != "INBOUND" || inbound.Traversal.SchemaDirection == "" { + t.Fatalf("unexpected inbound capability: %#v", inbound.Traversal) + } + outbound, err := ProbeTraversal(context.Background(), TraversalRequest{Scope: testScope(), RootResourceType: "Observation", Traversal: Traversal{EdgeLabel: "subject_Patient", ToResourceType: "Patient"}}) + if err != nil { + t.Fatalf("outbound route: %v", err) + } + if outbound.Traversal.StorageDirection != "OUTBOUND" { + t.Fatalf("unexpected outbound capability: %#v", outbound.Traversal) + } + assertScopedQuery(t, outbound.Rendered) +} + +func TestProbeTraversalRejectsInvalidRoute(t *testing.T) { + for _, route := range []Traversal{ + {EdgeLabel: "missing", ToResourceType: "Specimen"}, + {EdgeLabel: "subject_Patient", ToResourceType: "Medication"}, + {FromResourceType: "Condition", EdgeLabel: "subject_Patient", ToResourceType: "Specimen"}, + } { + if _, err := ProbeTraversal(context.Background(), TraversalRequest{Scope: testScope(), RootResourceType: "Patient", Traversal: route}); err == nil { + t.Fatalf("invalid route was accepted: %#v", route) + } + } +} + +func TestProbeCandidateReportsScalarRepeatedObjectAndOperations(t *testing.T) { + scalar, err := ProbeCandidate(context.Background(), CandidateRequest{Scope: testScope(), ResourceType: "Patient", FieldRef: "Patient.gender", Selector: "gender"}) + if err != nil { + t.Fatalf("scalar candidate: %v", err) + } + if scalar.Candidate.Repeated || !scalar.Candidate.Filterable || len(scalar.Candidate.ProjectionModes) == 0 { + t.Fatalf("unexpected scalar candidate: %#v", scalar.Candidate) + } + repeated, err := ProbeCandidate(context.Background(), CandidateRequest{Scope: testScope(), ResourceType: "Observation", FieldRef: "Observation.code.coding[].display", Selector: "code.coding[].display"}) + if err != nil { + t.Fatalf("repeated candidate: %v", err) + } + if !repeated.Candidate.Repeated || !containsProjection(repeated.Candidate.ProjectionModes, spec.ProjectionArray) { + t.Fatalf("unexpected repeated candidate: %#v", repeated.Candidate) + } + object, err := ProbeCandidate(context.Background(), CandidateRequest{Scope: testScope(), ResourceType: "Observation", FieldRef: "Observation.code", Selector: "code"}) + if err != nil { + t.Fatalf("object candidate: %v", err) + } + if object.Candidate.FieldKind != "object" || object.Candidate.Filterable { + t.Fatalf("unexpected object candidate: %#v", object.Candidate) + } + if _, err := ProbeCandidate(context.Background(), CandidateRequest{Scope: testScope(), ResourceType: "Patient", Selector: "gender", Projection: spec.ProjectionArray}); err == nil { + t.Fatal("unsupported scalar array projection was accepted") + } + if _, err := ProbeCandidate(context.Background(), CandidateRequest{Scope: testScope(), ResourceType: "Patient", Selector: "gender", Filter: &Filter{Operator: spec.FilterGreaterThan}}); err == nil { + t.Fatal("unsupported string comparison filter was accepted") + } + if _, err := ProbeCandidate(context.Background(), CandidateRequest{Scope: testScope(), ResourceType: "Patient", Selector: "gender", Chart: &Chart{Operation: recipe.AggregateOperation("NOT_A_CHART")}}); err == nil { + t.Fatal("unsupported chart operation was accepted") + } +} + +func TestProbeCandidateRendersGenerationProjectAndAuthScope(t *testing.T) { + result, err := ProbeCandidate(context.Background(), CandidateRequest{Scope: testScope(), ResourceType: "Patient", Selector: "gender", Filter: &Filter{Operator: spec.FilterEquals}}) + if err != nil { + t.Fatalf("candidate filter: %v", err) + } + assertScopedQuery(t, result.Rendered) +} + +func TestProbeCandidateSupportsRelatedOccurrence(t *testing.T) { + result, err := ProbeCandidate(context.Background(), CandidateRequest{ + Scope: testScope(), + RootResourceType: "Patient", + ResourceType: "Specimen", + Selector: "id", + Route: []Traversal{{FromResourceType: "Patient", EdgeLabel: "subject_Patient", ToResourceType: "Specimen", Alias: "specimen"}}, + }) + if err != nil { + t.Fatalf("related candidate: %v", err) + } + if result.Rendered.BindVars["child_set_1_label"] != "subject_Patient" || result.Candidate.ResourceType != "Specimen" { + t.Fatalf("related candidate lost route or metadata: %#v\n%s", result.Candidate, result.Rendered.Query) + } +} + +func assertScopedQuery(t *testing.T, rendered Rendered) { + t.Helper() + if rendered.Query == "" || !strings.Contains(rendered.Query, "@project") || !strings.Contains(rendered.Query, "@dataset_generation") { + t.Fatalf("query is not scoped: %q", rendered.Query) + } + if rendered.Project != "project-1" || rendered.DatasetGeneration != "generation-7" || len(rendered.AuthResourcePaths) != 1 { + t.Fatalf("scope provenance = %#v", rendered) + } +} + +func containsProjection(values []spec.ProjectionMode, want spec.ProjectionMode) bool { + for _, value := range values { + if value == want { + return true + } + } + return false +} diff --git a/internal/dataframe/compiler/grain_test.go b/internal/dataframe/compiler/grain_test.go index f4be5ffd..7db31aef 100644 --- a/internal/dataframe/compiler/grain_test.go +++ b/internal/dataframe/compiler/grain_test.go @@ -105,6 +105,7 @@ func TestInferRowGrainAndDefaultIdentity(t *testing.T) { for resourceType, want := range map[string]spec.RowGrain{ "Patient": spec.RowGrainPatient, "Specimen": spec.RowGrainSpecimen, + " specimen ": spec.RowGrainSpecimen, "DocumentReference": spec.RowGrainFile, "Condition": spec.RowGrainDiagnosis, "Observation": spec.RowGrainObservation, @@ -122,6 +123,11 @@ func TestInferRowGrainAndDefaultIdentity(t *testing.T) { if grain, ok := spec.InferRowGrain("Organization"); !ok || grain != spec.RowGrainResource { t.Fatalf("Organization generic row grain = %q, %v; want %q, true", grain, ok, spec.RowGrainResource) } + for _, resourceType := range []string{"PractitionerQualification", "qualification", "issuer", "Resource", "CustomResource"} { + if grain, ok := spec.InferRowGrain(resourceType); ok || grain != "" { + t.Fatalf("InferRowGrain(%q) = %q, %v; non-resource type must be rejected", resourceType, grain, ok) + } + } } func TestValidateRootGrainRejectsImplicitCrossGrainOutput(t *testing.T) { diff --git a/internal/dataframe/compiler/semantic_validation_test.go b/internal/dataframe/compiler/semantic_validation_test.go index 569acabe..ffbe9b59 100644 --- a/internal/dataframe/compiler/semantic_validation_test.go +++ b/internal/dataframe/compiler/semantic_validation_test.go @@ -37,7 +37,7 @@ func TestValidateSemanticGraphRejectsUnknownRootAndTraversal(t *testing.T) { assertSemanticValidationError(t, unknownTraversal, "is not represented by the active generated FHIR schema") } -func TestValidateSemanticGraphRejectsSelfCycle(t *testing.T) { +func TestValidateSemanticGraphAcceptsRepeatedSelfReference(t *testing.T) { plan := semantic.SemanticPlan{Root: semantic.SemanticNode{ Alias: "root", ResourceType: "Patient", Children: []semantic.SemanticNode{{ @@ -45,7 +45,9 @@ func TestValidateSemanticGraphRejectsSelfCycle(t *testing.T) { Children: []semantic.SemanticNode{{Alias: "linked_again", ResourceType: "Patient", EdgeLabel: "link_other_Patient"}}, }}, }} - assertSemanticValidationError(t, plan, "cycle detected") + if err := semantic.ValidateSemanticGraph(plan); err != nil { + t.Fatalf("repeated self-reference should remain a valid finite query: %v", err) + } } func TestValidateSemanticGraphAllowsOneHopSelfReference(t *testing.T) { @@ -58,7 +60,7 @@ func TestValidateSemanticGraphAllowsOneHopSelfReference(t *testing.T) { } } -func TestValidateSemanticGraphEnforcesDepthCap(t *testing.T) { +func TestValidateSemanticGraphAcceptsMoreThanFourHops(t *testing.T) { plan := semantic.SemanticPlan{Root: semantic.SemanticNode{ Alias: "root", ResourceType: "Patient", Children: []semantic.SemanticNode{{ @@ -70,14 +72,16 @@ func TestValidateSemanticGraphEnforcesDepthCap(t *testing.T) { Children: []semantic.SemanticNode{{ Alias: "another_specimen", ResourceType: "Specimen", EdgeLabel: "collection_procedure", Children: []semantic.SemanticNode{{ - Alias: "too_deep", ResourceType: "Practitioner", EdgeLabel: "irrelevant_at_depth_guard", + Alias: "another_file", ResourceType: "DocumentReference", EdgeLabel: "subject_Specimen", }}, }}, }}, }}, }}, }} - assertSemanticValidationError(t, plan, "exceeds maximum 4") + if err := semantic.ValidateSemanticGraph(plan); err != nil { + t.Fatalf("finite route longer than four hops should remain valid: %v", err) + } } func TestValidateSemanticGraphRejectsMalformedRoot(t *testing.T) { diff --git a/internal/dataframe/errors/errors.go b/internal/dataframe/errors/errors.go index 5e255e04..3a5ec898 100644 --- a/internal/dataframe/errors/errors.go +++ b/internal/dataframe/errors/errors.go @@ -61,6 +61,9 @@ const ( CodeRecipeContractViolation ErrorCode = "RECIPE_CONTRACT_VIOLATION" CodeFederationIncompatible ErrorCode = "FEDERATION_INCOMPATIBLE" CodeInvalidSelector ErrorCode = "INVALID_SELECTOR" + CodeReceiptStoreUnavailable ErrorCode = "RECEIPT_STORE_UNAVAILABLE" + CodePreviewTimeout ErrorCode = "PREVIEW_TIMEOUT" + CodePreviewResponseTooLarge ErrorCode = "PREVIEW_RESPONSE_TOO_LARGE" ) // UserError is the semantic error contract shared by GraphQL, preview, and @@ -249,7 +252,7 @@ func SanitizePersistedFailure(raw string) (message, code string, retryable bool) } func IsRetryableCode(code ErrorCode) bool { - return code == CodeBackendUnavailable || code == CodePublicationInProgress || code == CodePublicationConflict || code == CodePublicationLeaseLost || code == CodePublicationFailed + return code == CodeBackendUnavailable || code == CodeReceiptStoreUnavailable || code == CodePreviewTimeout || code == CodePublicationInProgress || code == CodePublicationConflict || code == CodePublicationLeaseLost || code == CodePublicationFailed } func defaultMessage(code ErrorCode) string { @@ -350,6 +353,12 @@ func defaultMessage(code ErrorCode) string { return "published sources cannot share a logical schema" case CodeInvalidSelector: return "a complete dataframe selector is required" + case CodeReceiptStoreUnavailable: + return "the compilation receipt store is temporarily unavailable" + case CodePreviewTimeout: + return "the preview took too long to complete" + case CodePreviewResponseTooLarge: + return "the preview response is too large" default: return "internal server error" } diff --git a/internal/dataframe/errors/errors_test.go b/internal/dataframe/errors/errors_test.go index 593cce5e..57837618 100644 --- a/internal/dataframe/errors/errors_test.go +++ b/internal/dataframe/errors/errors_test.go @@ -20,7 +20,10 @@ func TestErrorCodesAreUniqueAndStable(t *testing.T) { CodeRecipeExecutionNotFound, CodeExportLimitExceeded, CodeIngestPreflightFailed, CodeGenerationLoadIncomplete, CodeGenerationActivationUnknown, CodeInvalidGenerationFile, CodeDuplicateGenerationFile, CodePublicationInProgress, CodePublicationConflict, - CodePublicationLeaseLost, CodeOutputEncodingFailed, + CodePublicationLeaseLost, CodePublicationFailed, CodeOutputEncodingFailed, + CodeDynamicSchemaDrift, CodeRecipeContractViolation, CodeFederationIncompatible, + CodeInvalidSelector, CodeReceiptStoreUnavailable, CodePreviewTimeout, + CodePreviewResponseTooLarge, } seen := make(map[ErrorCode]struct{}, len(codes)) for _, code := range codes { @@ -133,7 +136,28 @@ func TestNormalizeRedactsAdapterOwnedUserErrors(t *testing.T) { } func TestErrorClassification(t *testing.T) { - if !IsRetryableCode(CodeBackendUnavailable) || IsRetryableCode(CodeClientCanceled) { + if !IsRetryableCode(CodeBackendUnavailable) || !IsRetryableCode(CodeReceiptStoreUnavailable) || !IsRetryableCode(CodePreviewTimeout) || IsRetryableCode(CodePreviewResponseTooLarge) || IsRetryableCode(CodeClientCanceled) { t.Fatal("unexpected retryable classification") } } + +func TestPreviewErrorDefaults(t *testing.T) { + for _, test := range []struct { + code ErrorCode + message string + }{ + {CodeReceiptStoreUnavailable, "the compilation receipt store is temporarily unavailable"}, + {CodePreviewTimeout, "the preview took too long to complete"}, + {CodePreviewResponseTooLarge, "the preview response is too large"}, + } { + t.Run(string(test.code), func(t *testing.T) { + err := NewError(test.code, "") + if err.Error() != test.message { + t.Fatalf("default message = %q, want %q", err.Error(), test.message) + } + if PublicMessage(err) != test.message { + t.Fatalf("public message = %q, want %q", PublicMessage(err), test.message) + } + }) + } +} diff --git a/internal/dataframe/recipe/engine/engine.go b/internal/dataframe/recipe/engine/engine.go index fcd73bb3..81db9d9c 100644 --- a/internal/dataframe/recipe/engine/engine.go +++ b/internal/dataframe/recipe/engine/engine.go @@ -9,14 +9,17 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" + "errors" "fmt" "sort" "strings" + "time" "github.com/calypr/loom/internal/dataframe/compiler" "github.com/calypr/loom/internal/dataframe/compiler/ir" "github.com/calypr/loom/internal/dataframe/compiler/lower" "github.com/calypr/loom/internal/dataframe/compiler/optimize" + dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" "github.com/calypr/loom/internal/dataframe/recipe" "github.com/calypr/loom/internal/dataframe/recipe/exec" "github.com/calypr/loom/internal/dataframe/semantic" @@ -34,6 +37,35 @@ type VersionedRegistry interface { type QueryRows func(context.Context, string, int, map[string]any, func(map[string]any) error) error +const ( + // DefaultPreviewLimit is used when a preview request omits its limit. + DefaultPreviewLimit = 25 + // MaxPreviewLimit bounds rows accumulated by one output preview. + MaxPreviewLimit = 1000 + previewPlanMode = "physical" + previewPlanProfile = "generic_fhir_graph_recipe" +) + +// PreviewRequest selects one compiled output and bounds its preview rows. +type PreviewRequest struct { + Output string + Limit int +} + +// PreviewSummary is safe execution metadata for one preview output. It does +// not contain AQL, bind variables, or physical plan contents. +type PreviewSummary struct { + Output string + Columns []string + RowCount int + PlanMode string + PlanProfile string + PlanFingerprint string + TraversalCount int + LoweringDuration time.Duration + QueryDuration time.Duration +} + type Config struct { Registry Registry Revisions recipe.RevisionStore @@ -52,9 +84,13 @@ type Engine struct { batchSize int } -// Resolved contains semantic discovery provenance and canonical physical plans -// per output. It deliberately contains no recipe-specific physical model. +// Resolved contains the immutable recipe after schema discovery, semantic +// discovery provenance, and canonical physical plans per output. Bundle is the +// fully resolved recipe that may be passed back through CompileResolvedBundle +// after a receipt or other durable boundary. Compiled remains request-scoped +// runtime state; callers must not persist it. type Resolved struct { + Bundle recipe.Bundle Semantic semantic.ResolvedRecipePlan Compiled lower.CompiledRecipe StoredRecipeDigest string @@ -84,9 +120,9 @@ type OutputStream struct { Name string Columns []string RowIdentity *spec.RowIdentity - Query string - BindVars map[string]any DynamicChecks map[string]map[string]DynamicColumnCheck + query string + bindVars map[string]any stream QueryRows batchSize int } @@ -167,6 +203,22 @@ func (e *Engine) ResolveBundle(ctx context.Context, bundle recipe.Bundle, bindin return e.resolveEntry(ctx, exec.Entry{Bundle: bundle, Digest: digest}, bindings) } +// CompileResolvedBundle validates and compiles a bundle that has already been +// resolved by schema discovery. It never invokes Config.ResolveBundle and +// therefore performs no catalog or schema discovery. Dynamic declarations +// with nil Columns are rejected by the semantic boundary; a non-nil empty +// Columns slice is an explicitly resolved, zero-column family and is valid. +func (e *Engine) CompileResolvedBundle(ctx context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (Resolved, error) { + if strings.TrimSpace(bindings.Project) == "" { + return Resolved{}, fmt.Errorf("recipe project is required") + } + digest, err := bundle.Digest() + if err != nil { + return Resolved{}, fmt.Errorf("digest resolved bundle: %w", err) + } + return e.compileResolvedBundle(ctx, bundle, bindings, digest) +} + func (e *Engine) PreviewBundle(ctx context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (map[string][]map[string]any, error) { resolved, err := e.ResolveBundle(ctx, bundle, bindings) if err != nil { @@ -175,6 +227,16 @@ func (e *Engine) PreviewBundle(ctx context.Context, bundle recipe.Bundle, bindin return e.Preview(ctx, resolved, bindings.PreviewLimit) } +// PreviewResolvedBundle compiles an already schema-resolved bundle without +// catalog discovery, then executes its request-scoped preview. +func (e *Engine) PreviewResolvedBundle(ctx context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (map[string][]map[string]any, error) { + resolved, err := e.CompileResolvedBundle(ctx, bundle, bindings) + if err != nil { + return nil, &ResolutionError{Err: err} + } + return e.Preview(ctx, resolved, bindings.PreviewLimit) +} + func (e *Engine) MaterializeBundle(ctx context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings, publish func(context.Context, Resolved) error) (Resolved, error) { resolved, err := e.ResolveBundle(ctx, bundle, bindings) if err != nil { @@ -188,6 +250,22 @@ func (e *Engine) MaterializeBundle(ctx context.Context, bundle recipe.Bundle, bi return resolved, nil } +// MaterializeResolvedBundle compiles an already schema-resolved bundle +// without catalog discovery and hands the resulting request-scoped plan to +// the publisher. +func (e *Engine) MaterializeResolvedBundle(ctx context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings, publish func(context.Context, Resolved) error) (Resolved, error) { + resolved, err := e.CompileResolvedBundle(ctx, bundle, bindings) + if err != nil { + return Resolved{}, &ResolutionError{Err: err} + } + if publish != nil { + if err := publish(ctx, resolved); err != nil { + return Resolved{}, err + } + } + return resolved, nil +} + func (e *Engine) resolveEntry(ctx context.Context, entry exec.Entry, bindings recipe.RuntimeBindings) (Resolved, error) { if strings.TrimSpace(bindings.Project) == "" { return Resolved{}, fmt.Errorf("recipe project is required") @@ -203,6 +281,23 @@ func (e *Engine) resolveEntry(ctx context.Context, entry exec.Entry, bindings re return Resolved{}, fmt.Errorf("resolve recipe schema: %w", err) } } + return e.compileResolvedBundle(ctx, bundle, bindings, storedRecipeDigest) +} + +// compileResolvedBundle is the shared post-discovery compiler. Keeping this +// helper separate from resolveEntry makes it impossible for receipt-backed +// callers to accidentally rediscover catalog fields during compilation. +func (e *Engine) compileResolvedBundle(ctx context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings, storedRecipeDigest string) (Resolved, error) { + if strings.TrimSpace(bindings.Project) == "" { + return Resolved{}, fmt.Errorf("recipe project is required") + } + if strings.TrimSpace(storedRecipeDigest) == "" { + var err error + storedRecipeDigest, err = bundle.Digest() + if err != nil { + return Resolved{}, fmt.Errorf("digest resolved bundle: %w", err) + } + } semanticPlan, err := semantic.BuildRecipePlan(bundle, bindings) if err != nil { return Resolved{}, err @@ -239,7 +334,7 @@ func (e *Engine) resolveEntry(ctx context.Context, entry exec.Entry, bindings re return Resolved{}, err } resolved.ResolvedSchemaDigest = resolvedSchemaDigest - return Resolved{Semantic: resolved, Compiled: compiled, StoredRecipeDigest: storedRecipeDigest, ResolvedSchemaDigest: resolvedSchemaDigest}, nil + return Resolved{Bundle: bundle, Semantic: resolved, Compiled: compiled, StoredRecipeDigest: storedRecipeDigest, ResolvedSchemaDigest: resolvedSchemaDigest}, nil } func resolvedBundleSchemaDigest(storedDigest string, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (string, error) { @@ -327,18 +422,33 @@ func (e *Engine) streamsWithLimit(_ context.Context, resolved Resolved, limit in if selected != nil && !selected[output.Name] { continue } - query, err := compiler.CompileRecipeOutputWithPolicy(output, resolved.Semantic.SemanticPlan.Bindings, limit, ir.DefaultPhysicalOptimizationPolicy()) + stream, _, err := e.streamForOutput(resolved, output.Name, limit) if err != nil { - return nil, fmt.Errorf("output %q: %w", output.Name, err) + return nil, err } - streams = append(streams, OutputStream{ - Name: output.Name, Columns: append([]string(nil), query.PublicColumns...), RowIdentity: query.RowIdentity.Clone(), Query: query.Query, - BindVars: query.BindVars, DynamicChecks: dynamicChecks(output.DynamicColumns), stream: e.queryRows, batchSize: e.batchSize, - }) + streams = append(streams, stream) } return streams, nil } +func (e *Engine) streamForOutput(resolved Resolved, name string, limit int) (OutputStream, compiler.CompiledQuery, error) { + for _, output := range resolved.Compiled.Outputs { + if output.Name != name { + continue + } + query, err := compiler.CompileRecipeOutputWithPolicy(output, resolved.Semantic.SemanticPlan.Bindings, limit, ir.DefaultPhysicalOptimizationPolicy()) + if err != nil { + return OutputStream{}, compiler.CompiledQuery{}, fmt.Errorf("output %q: %w", output.Name, err) + } + return OutputStream{ + Name: output.Name, Columns: append([]string(nil), query.PublicColumns...), RowIdentity: query.RowIdentity.Clone(), + DynamicChecks: dynamicChecks(output.DynamicColumns), query: query.Query, bindVars: query.BindVars, + stream: e.queryRows, batchSize: e.batchSize, + }, query, nil + } + return OutputStream{}, compiler.CompiledQuery{}, previewAdmissionError(dataframeerrors.CodeInvalidRequest, "requested preview output is not available", map[string]any{"output": name}) +} + func selectedOutputNames(names []string, outputs []lower.CompiledRecipeOutput) map[string]bool { if len(names) == 0 { return nil @@ -356,37 +466,179 @@ func selectedOutputNames(names []string, outputs []lower.CompiledRecipeOutput) m } func (e *Engine) Preview(ctx context.Context, resolved Resolved, limit int) (map[string][]map[string]any, error) { - if limit <= 0 { - limit = 25 - } - streams, err := e.streamsWithLimit(ctx, resolved, limit) + limit, err := normalizePreviewLimit(limit) if err != nil { return nil, err } - result := make(map[string][]map[string]any, len(streams)) - for _, stream := range streams { + selected := resolved.Semantic.SemanticPlan.Bindings.OutputNames + if len(selected) == 0 { + selected = make([]string, 0, len(resolved.Compiled.Outputs)) + for _, output := range resolved.Compiled.Outputs { + selected = append(selected, output.Name) + } + } + for _, name := range selected { + if !hasCompiledOutput(resolved, name) { + return nil, previewAdmissionError(dataframeerrors.CodeInvalidRequest, "requested preview output is not available", map[string]any{"output": name}) + } + } + result := make(map[string][]map[string]any, len(selected)) + for _, name := range selected { rows := make([]map[string]any, 0, limit) - count := 0 - err := stream.stream(ctx, stream.Query, stream.batchSize, stream.BindVars, func(row map[string]any) error { - if count >= limit { - return errPreviewLimit - } - resolvedRow, err := materializePostQueryRowWithChecks(row, stream.DynamicChecks) - if err != nil { - return err - } - rows = append(rows, resolvedRow) - count++ + _, err := e.PreviewOutput(ctx, resolved, PreviewRequest{Output: name, Limit: limit}, func(row map[string]any) error { + rows = append(rows, row) return nil }) - if err != nil && err != errPreviewLimit { - return nil, fmt.Errorf("output %q: %w", stream.Name, err) + if err != nil { + return nil, err } - result[stream.Name] = rows + result[name] = rows } return result, nil } +func hasCompiledOutput(resolved Resolved, name string) bool { + for _, output := range resolved.Compiled.Outputs { + if output.Name == name { + return true + } + } + return false +} + +// PreviewOutput executes exactly one selected output and exposes only the +// public output schema. Physical query text, bind variables, and internal +// projections never cross this boundary. +func (e *Engine) PreviewOutput(ctx context.Context, resolved Resolved, request PreviewRequest, visit func(map[string]any) error) (PreviewSummary, error) { + if err := contextError(ctx); err != nil { + return PreviewSummary{}, err + } + limit, err := normalizePreviewLimit(request.Limit) + if err != nil { + return PreviewSummary{}, err + } + if strings.TrimSpace(request.Output) == "" { + return PreviewSummary{}, previewAdmissionError(dataframeerrors.CodeInvalidRequest, "preview output is required", nil) + } + if visit == nil { + return PreviewSummary{}, previewAdmissionError(dataframeerrors.CodeInvalidRequest, "preview visitor is required", nil) + } + loweringStarted := time.Now() + stream, query, err := e.streamForOutput(resolved, request.Output, limit) + if err != nil { + if _, ok := dataframeerrors.AsUserError(err); ok { + return PreviewSummary{}, err + } + return PreviewSummary{}, dataframeerrors.Wrap(err, dataframeerrors.CodeRecipeContractViolation, "preview plan compilation failed") + } + if err := contextError(ctx); err != nil { + return PreviewSummary{}, err + } + if err := validatePreviewPlan(query, limit); err != nil { + return PreviewSummary{}, err + } + summary := PreviewSummary{Output: stream.Name, Columns: append([]string(nil), stream.Columns...), PlanMode: query.PlanMode, PlanProfile: query.PlanProfile, PlanFingerprint: query.PlanDiagnostics.Fingerprint, TraversalCount: query.TraversalCount, LoweringDuration: time.Since(loweringStarted)} + count := 0 + var visitorErr error + queryStarted := time.Now() + queryErr := stream.stream(ctx, stream.query, stream.batchSize, stream.bindVars, func(row map[string]any) error { + if err := contextError(ctx); err != nil { + return err + } + if count >= limit { + return errPreviewLimit + } + resolvedRow, err := materializePostQueryRowWithChecks(row, stream.DynamicChecks) + if err != nil { + return err + } + public := publicPreviewRow(resolvedRow, stream.Columns) + if err := visit(public); err != nil { + visitorErr = err + return err + } + count++ + return nil + }) + summary.RowCount = count + summary.QueryDuration = time.Since(queryStarted) + if visitorErr != nil { + return summary, normalizePreviewError(visitorErr, false) + } + if queryErr != nil && !errors.Is(queryErr, errPreviewLimit) { + return summary, normalizePreviewError(queryErr, true) + } + if err := contextError(ctx); err != nil { + return summary, err + } + return summary, nil +} + +func normalizePreviewLimit(limit int) (int, error) { + if limit == 0 { + return DefaultPreviewLimit, nil + } + if limit < 1 || limit > MaxPreviewLimit { + return 0, previewAdmissionError(dataframeerrors.CodeInvalidLimit, "preview limit is outside the supported range", map[string]any{"maximum": MaxPreviewLimit}) + } + return limit, nil +} + +func validatePreviewPlan(query compiler.CompiledQuery, limit int) error { + if query.PlanMode != previewPlanMode || query.PlanProfile != previewPlanProfile || strings.TrimSpace(query.PlanDiagnostics.Fingerprint) == "" || query.Limit != limit { + return previewAdmissionError(dataframeerrors.CodePlanTooExpensive, "compiled preview plan is not in the approved preview plan class", nil) + } + return nil +} + +func contextError(ctx context.Context) error { + if ctx == nil { + return nil + } + if err := ctx.Err(); err != nil { + return dataframeerrors.Normalize(err) + } + return nil +} + +func previewAdmissionError(code dataframeerrors.ErrorCode, message string, details map[string]any) error { + options := []dataframeerrors.ErrorOption{dataframeerrors.WithRetryable(false)} + if details != nil { + options = append(options, dataframeerrors.WithDetails(details)) + } + return dataframeerrors.NewError(code, message, options...) +} + +func normalizePreviewError(err error, backend bool) error { + if err == nil { + return nil + } + var drift *DynamicDriftError + if errors.As(err, &drift) { + return dataframeerrors.Wrap(err, dataframeerrors.CodeDynamicSchemaDrift, "dynamic schema drift", dataframeerrors.WithDetails(map[string]any{"dynamic_map": drift.DynamicName, "frozen_key_count": drift.FrozenKeyCount})) + } + if userErr, ok := dataframeerrors.AsUserError(err); ok { + return userErr + } + if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) { + return dataframeerrors.Normalize(err) + } + if backend { + return dataframeerrors.Wrap(err, dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) + } + return dataframeerrors.Normalize(err) +} + +func publicPreviewRow(row map[string]any, columns []string) map[string]any { + public := make(map[string]any, len(columns)) + for _, column := range columns { + if value, ok := row[column]; ok { + public[column] = value + } + } + return public +} + var errPreviewLimit = fmt.Errorf("preview limit reached") func (s OutputStream) Stream(ctx context.Context, visit func(map[string]any) error) (StreamResult, error) { @@ -394,12 +646,12 @@ func (s OutputStream) Stream(ctx context.Context, visit func(map[string]any) err return StreamResult{}, fmt.Errorf("row visitor is required") } count := 0 - err := s.stream(ctx, s.Query, s.batchSize, s.BindVars, func(row map[string]any) error { + err := s.stream(ctx, s.query, s.batchSize, s.bindVars, func(row map[string]any) error { resolved, err := materializePostQueryRowWithChecks(row, s.DynamicChecks) if err != nil { return err } - if err := ensureStableRowIdentity(resolved, s.RowIdentity, s.BindVars); err != nil { + if err := ensureStableRowIdentity(resolved, s.RowIdentity, s.bindVars); err != nil { return err } resolved = publicStreamRow(resolved, s.Columns) diff --git a/internal/dataframe/recipe/engine/engine_test.go b/internal/dataframe/recipe/engine/engine_test.go index 7f95d469..7ad49f68 100644 --- a/internal/dataframe/recipe/engine/engine_test.go +++ b/internal/dataframe/recipe/engine/engine_test.go @@ -3,8 +3,13 @@ package engine import ( "context" "errors" + "fmt" + "strings" "testing" + "github.com/calypr/loom/internal/dataframe/compiler" + "github.com/calypr/loom/internal/dataframe/compiler/ir" + dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" "github.com/calypr/loom/internal/dataframe/recipe" "github.com/calypr/loom/internal/dataframe/recipe/exec" ) @@ -40,3 +45,326 @@ func TestMaterializeMarksResolutionFailures(t *testing.T) { t.Fatalf("error = %v, want ResolutionError", err) } } + +func testResolvedBundle(dynamicColumns []string) recipe.Bundle { + return recipe.Bundle{ + RecipeSchemaVersion: 1, + Name: "resolved", + TranslationVersion: "test", + Outputs: []recipe.Output{{ + Name: "Patient", RootResourceType: "Patient", RowGrain: "patient", + Fields: []recipe.Field{{Name: "id", Expr: recipe.Expression{Select: "root.id"}}}, + DynamicColumns: []recipe.DynamicColumn{{ + Name: "identifier", Source: recipe.Expression{Select: "root.identifier[].value"}, + Columns: dynamicColumns, + }}, + }}, + } +} + +func testEngine(queryRows QueryRows) *Engine { + engine, err := New(Config{ + Registry: invalidRecipeRegistry{}, + ScopeDigest: func(recipe.RuntimeBindings) string { return "test-scope" }, + QueryRows: queryRows, + }) + if err != nil { + panic(err) + } + return engine +} + +func TestPreviewOutputFiltersInternalColumnsAndReturnsSafePlanSummary(t *testing.T) { + e := testEngine(func(_ context.Context, _ string, _ int, _ map[string]any, visit func(map[string]any) error) error { + return visit(map[string]any{ + "id": "p1", + "_key": "internal-key", + "__loom_row_id": "internal-row-id", + "auth_resource_path": "/private/path", + "__loom_dynamic_runtime_keys": map[string]any{"family": []string{"x"}}, + }) + }) + resolved, err := e.CompileResolvedBundle(context.Background(), testResolvedBundle([]string{}), recipe.RuntimeBindings{Project: "P1"}) + if err != nil { + t.Fatal(err) + } + var rows []map[string]any + summary, err := e.PreviewOutput(context.Background(), resolved, PreviewRequest{Output: "Patient", Limit: 1}, func(row map[string]any) error { + rows = append(rows, row) + return nil + }) + if err != nil { + t.Fatal(err) + } + if summary.Output != "Patient" || summary.RowCount != 1 || summary.PlanMode != "physical" || summary.PlanProfile != "generic_fhir_graph_recipe" || summary.PlanFingerprint == "" { + t.Fatalf("unsafe or incomplete preview summary: %#v", summary) + } + if len(rows) != 1 || rows[0]["id"] != "p1" || len(rows[0]) != 1 { + t.Fatalf("preview row was not public-only: %#v", rows) + } +} + +func TestPreviewOutputExecutesOnlyRequestedOutputAndRejectsUnknownBeforeQuery(t *testing.T) { + queries := 0 + e := testEngine(func(_ context.Context, _ string, _ int, _ map[string]any, visit func(map[string]any) error) error { + queries++ + return visit(map[string]any{"id": "p1"}) + }) + bundle := testResolvedBundle([]string{}) + bundle.Outputs = append(bundle.Outputs, recipe.Output{ + Name: "Observation", RootResourceType: "Observation", RowGrain: "observation", + Fields: []recipe.Field{{Name: "id", Expr: recipe.Expression{Select: "root.id"}}}, + }) + resolved, err := e.CompileResolvedBundle(context.Background(), bundle, recipe.RuntimeBindings{Project: "P1"}) + if err != nil { + t.Fatal(err) + } + if _, err := e.PreviewOutput(context.Background(), resolved, PreviewRequest{Output: "Observation", Limit: 1}, func(map[string]any) error { return nil }); err != nil { + t.Fatal(err) + } + if queries != 1 { + t.Fatalf("query count = %d, want 1", queries) + } + _, err = e.PreviewOutput(context.Background(), resolved, PreviewRequest{Output: "Missing", Limit: 1}, func(map[string]any) error { return nil }) + if err == nil || queries != 1 { + t.Fatalf("unknown output err=%v query count=%d, want error before query", err, queries) + } + userErr, ok := dataframeerrors.AsUserError(err) + if !ok || userErr.Code() != string(dataframeerrors.CodeInvalidRequest) { + t.Fatalf("unknown output error = %v, want INVALID_REQUEST", err) + } +} + +func TestPreviewOutputEnforcesLimitAndCancellation(t *testing.T) { + rowsSeen := 0 + e := testEngine(func(_ context.Context, _ string, _ int, _ map[string]any, visit func(map[string]any) error) error { + for index := 0; index < 10; index++ { + rowsSeen++ + if err := visit(map[string]any{"id": fmt.Sprintf("p%d", index)}); err != nil { + return err + } + } + return nil + }) + resolved, err := e.CompileResolvedBundle(context.Background(), testResolvedBundle([]string{}), recipe.RuntimeBindings{Project: "P1"}) + if err != nil { + t.Fatal(err) + } + count := 0 + summary, err := e.PreviewOutput(context.Background(), resolved, PreviewRequest{Output: "Patient", Limit: 2}, func(map[string]any) error { + count++ + return nil + }) + if err != nil || count != 2 || summary.RowCount != 2 || rowsSeen != 3 { + t.Fatalf("limit count=%d summary=%#v rowsSeen=%d err=%v", count, summary, rowsSeen, err) + } + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + _, err = e.PreviewOutput(ctx, resolved, PreviewRequest{Output: "Patient", Limit: 1}, func(map[string]any) error { return nil }) + userErr, ok := dataframeerrors.AsUserError(err) + if !ok || userErr.Code() != string(dataframeerrors.CodeClientCanceled) { + t.Fatalf("canceled preview error = %v, want CLIENT_CANCELED", err) + } + + cancelEngine := testEngine(func(_ context.Context, _ string, _ int, _ map[string]any, visit func(map[string]any) error) error { + if err := visit(map[string]any{"id": "p1"}); err != nil { + return err + } + return visit(map[string]any{"id": "p2"}) + }) + resolved, err = cancelEngine.CompileResolvedBundle(context.Background(), testResolvedBundle([]string{}), recipe.RuntimeBindings{Project: "P1"}) + if err != nil { + t.Fatal(err) + } + ctx, cancel = context.WithCancel(context.Background()) + _, err = cancelEngine.PreviewOutput(ctx, resolved, PreviewRequest{Output: "Patient", Limit: 2}, func(map[string]any) error { + cancel() + return nil + }) + userErr, ok = dataframeerrors.AsUserError(err) + if !ok || userErr.Code() != string(dataframeerrors.CodeClientCanceled) { + t.Fatalf("mid-query canceled preview error = %v, want CLIENT_CANCELED", err) + } +} + +func TestPreviewOutputNormalizesVisitorAndDynamicSchemaErrors(t *testing.T) { + driftEngine := testEngine(func(_ context.Context, _ string, _ int, _ map[string]any, visit func(map[string]any) error) error { + return visit(map[string]any{ + "id": "p1", + "value": "v", + "__loom_dynamic_runtime_keys": map[string]any{"identifier": []string{"unexpected"}}, + }) + }) + resolved, err := driftEngine.CompileResolvedBundle(context.Background(), testResolvedBundle([]string{"value"}), recipe.RuntimeBindings{Project: "P1"}) + if err != nil { + t.Fatal(err) + } + _, err = driftEngine.PreviewOutput(context.Background(), resolved, PreviewRequest{Output: "Patient", Limit: 1}, func(map[string]any) error { return nil }) + userErr, ok := dataframeerrors.AsUserError(err) + if !ok || userErr.Code() != string(dataframeerrors.CodeDynamicSchemaDrift) { + t.Fatalf("dynamic drift error = %v, want DYNAMIC_SCHEMA_DRIFT", err) + } + + visitorErr := errors.New("visitor failed") + visitorEngine := testEngine(func(_ context.Context, _ string, _ int, _ map[string]any, visit func(map[string]any) error) error { + return visit(map[string]any{"id": "p1"}) + }) + resolved, err = visitorEngine.CompileResolvedBundle(context.Background(), testResolvedBundle([]string{}), recipe.RuntimeBindings{Project: "P1"}) + if err != nil { + t.Fatal(err) + } + _, err = visitorEngine.PreviewOutput(context.Background(), resolved, PreviewRequest{Output: "Patient", Limit: 1}, func(map[string]any) error { return visitorErr }) + userErr, ok = dataframeerrors.AsUserError(err) + if !ok || userErr.Code() != string(dataframeerrors.CodeInternalError) || !errors.Is(err, visitorErr) { + t.Fatalf("visitor error = %v, want typed internal error preserving cause", err) + } +} + +func TestValidatePreviewPlanRequiresCanonicalPhysicalClass(t *testing.T) { + valid := compiler.CompiledQuery{PlanMode: previewPlanMode, PlanProfile: previewPlanProfile, Limit: 2, PlanDiagnostics: ir.CompilerPlanDiagnostics{Fingerprint: "fingerprint"}} + if err := validatePreviewPlan(valid, 2); err != nil { + t.Fatal(err) + } + for _, invalid := range []compiler.CompiledQuery{ + {PlanMode: "logical", PlanProfile: previewPlanProfile, Limit: 2, PlanDiagnostics: ir.CompilerPlanDiagnostics{Fingerprint: "fingerprint"}}, + {PlanMode: previewPlanMode, PlanProfile: "other", Limit: 2, PlanDiagnostics: ir.CompilerPlanDiagnostics{Fingerprint: "fingerprint"}}, + {PlanMode: previewPlanMode, PlanProfile: previewPlanProfile, Limit: 2}, + {PlanMode: previewPlanMode, PlanProfile: previewPlanProfile, Limit: 3, PlanDiagnostics: ir.CompilerPlanDiagnostics{Fingerprint: "fingerprint"}}, + } { + if err := validatePreviewPlan(invalid, 2); err == nil { + t.Fatalf("invalid plan %#v was admitted", invalid) + } else if userErr, ok := dataframeerrors.AsUserError(err); !ok || userErr.Code() != string(dataframeerrors.CodePlanTooExpensive) { + t.Fatalf("invalid plan error = %v, want PLAN_TOO_EXPENSIVE", err) + } + } +} + +func TestPreviewLimitsHaveStableDefaultAndMaximum(t *testing.T) { + if got, err := normalizePreviewLimit(0); err != nil || got != DefaultPreviewLimit { + t.Fatalf("default preview limit = %d, err=%v; want %d", got, err, DefaultPreviewLimit) + } + if got, err := normalizePreviewLimit(MaxPreviewLimit); err != nil || got != MaxPreviewLimit { + t.Fatalf("maximum preview limit = %d, err=%v; want %d", got, err, MaxPreviewLimit) + } + for _, limit := range []int{-1, MaxPreviewLimit + 1} { + if _, err := normalizePreviewLimit(limit); err == nil { + t.Fatalf("limit %d was accepted", limit) + } + } +} + +func TestCompileResolvedBundleSkipsCatalogResolverAndRetainsBundle(t *testing.T) { + resolverCalls := 0 + e, err := New(Config{ + Registry: invalidRecipeRegistry{}, + ResolveBundle: func(context.Context, recipe.Bundle, recipe.RuntimeBindings) (recipe.Bundle, error) { + resolverCalls++ + return recipe.Bundle{}, errors.New("catalog resolver must not be called") + }, + ScopeDigest: func(recipe.RuntimeBindings) string { return "test-scope" }, + QueryRows: func(context.Context, string, int, map[string]any, func(map[string]any) error) error { + return nil + }, + }) + if err != nil { + t.Fatal(err) + } + + bundle := testResolvedBundle([]string{"value"}) + resolved, err := e.CompileResolvedBundle(context.Background(), bundle, recipe.RuntimeBindings{Project: "P1"}) + if err != nil { + t.Fatal(err) + } + if resolverCalls != 0 { + t.Fatalf("catalog resolver calls = %d, want 0", resolverCalls) + } + if resolved.Bundle.Name != bundle.Name || len(resolved.Bundle.Outputs) != 1 { + t.Fatalf("resolved bundle was not retained: %#v", resolved.Bundle) + } + if len(resolved.Compiled.Outputs) != 1 { + t.Fatalf("compiled outputs = %d, want 1", len(resolved.Compiled.Outputs)) + } + if _, err := e.PreviewOutput(context.Background(), resolved, PreviewRequest{Output: "Patient", Limit: 1}, func(map[string]any) error { return nil }); err != nil { + t.Fatal(err) + } + if resolverCalls != 0 { + t.Fatalf("catalog resolver calls during PreviewOutput = %d, want 0", resolverCalls) + } +} + +func TestResolveBundleUsesResolverButResolvedPreviewAndMaterializeDoNot(t *testing.T) { + resolverCalls := 0 + e, err := New(Config{ + Registry: invalidRecipeRegistry{}, + ResolveBundle: func(_ context.Context, bundle recipe.Bundle, _ recipe.RuntimeBindings) (recipe.Bundle, error) { + resolverCalls++ + return bundle, nil + }, + ScopeDigest: func(recipe.RuntimeBindings) string { return "test-scope" }, + QueryRows: func(_ context.Context, _ string, _ int, _ map[string]any, visit func(map[string]any) error) error { + return visit(map[string]any{"id": "p1"}) + }, + }) + if err != nil { + t.Fatal(err) + } + bundle := testResolvedBundle([]string{}) + bindings := recipe.RuntimeBindings{Project: "P1", PreviewLimit: 1} + normal, err := e.ResolveBundle(context.Background(), bundle, bindings) + if err != nil { + t.Fatal(err) + } + if resolverCalls != 1 { + t.Fatalf("catalog resolver calls after ResolveBundle = %d, want 1", resolverCalls) + } + direct, err := e.CompileResolvedBundle(context.Background(), bundle, bindings) + if err != nil { + t.Fatal(err) + } + normalStreams, err := e.Streams(context.Background(), normal) + if err != nil { + t.Fatal(err) + } + directStreams, err := e.Streams(context.Background(), direct) + if err != nil { + t.Fatal(err) + } + if len(normalStreams) != len(directStreams) || normalStreams[0].query != directStreams[0].query { + t.Fatalf("resolved output differs from catalog-resolved output") + } + if _, err := e.PreviewResolvedBundle(context.Background(), bundle, bindings); err != nil { + t.Fatal(err) + } + if _, err := e.MaterializeResolvedBundle(context.Background(), bundle, bindings, nil); err != nil { + t.Fatal(err) + } + if resolverCalls != 1 { + t.Fatalf("catalog resolver calls after resolved operations = %d, want 1", resolverCalls) + } +} + +func TestCompileResolvedBundleRejectsUnresolvedDynamicDeclarations(t *testing.T) { + e, err := New(Config{ + Registry: invalidRecipeRegistry{}, + ScopeDigest: func(recipe.RuntimeBindings) string { return "test-scope" }, + QueryRows: func(context.Context, string, int, map[string]any, func(map[string]any) error) error { + return nil + }, + }) + if err != nil { + t.Fatal(err) + } + _, err = e.CompileResolvedBundle(context.Background(), testResolvedBundle(nil), recipe.RuntimeBindings{Project: "P1"}) + if err == nil || !strings.Contains(err.Error(), "unresolved") { + t.Fatalf("error = %v, want unresolved dynamic declaration", err) + } + + resolved, err := e.CompileResolvedBundle(context.Background(), testResolvedBundle([]string{}), recipe.RuntimeBindings{Project: "P1"}) + if err != nil { + t.Fatalf("explicit empty dynamic family rejected: %v", err) + } + if len(resolved.Compiled.Outputs) != 1 { + t.Fatalf("compiled outputs = %d, want 1", len(resolved.Compiled.Outputs)) + } +} diff --git a/internal/dataframe/recipe/engine/identity_test.go b/internal/dataframe/recipe/engine/identity_test.go index 2c5080a0..d22c1260 100644 --- a/internal/dataframe/recipe/engine/identity_test.go +++ b/internal/dataframe/recipe/engine/identity_test.go @@ -45,6 +45,7 @@ func TestOutputStreamStripsCompilerOnlyColumnsAfterIdentity(t *testing.T) { Name: "DocumentReference", Columns: []string{"id"}, RowIdentity: &spec.RowIdentity{Fields: []string{"_key"}}, + bindVars: map[string]any{"project": "P1"}, stream: func(_ context.Context, _ string, _ int, _ map[string]any, visit func(map[string]any) error) error { return visit(map[string]any{ "_key": "internal-key", diff --git a/internal/dataframe/semantic/semantic_validation.go b/internal/dataframe/semantic/semantic_validation.go index 132c47c1..e76ce2db 100644 --- a/internal/dataframe/semantic/semantic_validation.go +++ b/internal/dataframe/semantic/semantic_validation.go @@ -7,11 +7,6 @@ import ( fhirschema "github.com/calypr/loom/internal/fhir/schema" ) -// MaxSemanticTraversalDepth is the maximum number of relationship edges below -// a semantic-plan root. Keeping this small bounds compiler work and graph-query -// fanout until a cost model can safely authorize deeper plans. -const MaxSemanticTraversalDepth = 4 - // ValidateSemanticGraph checks the schema and structural safety of an already // constructed semantic plan. It performs no observed-data or authorization // checks and does not mutate the plan. @@ -35,20 +30,16 @@ func ValidateSemanticGraph(plan SemanticPlan) error { state := semanticValidationState{ aliases: map[string]string{}, } - return state.validateChildren(plan.Root, 0, []string{plan.Root.ResourceType}, map[string]bool{}) + return state.validateChildren(plan.Root, []string{plan.Root.ResourceType}) } type semanticValidationState struct { aliases map[string]string } -func (s *semanticValidationState) validateChildren(parent SemanticNode, depth int, path []string, edgesOnPath map[string]bool) error { +func (s *semanticValidationState) validateChildren(parent SemanticNode, path []string) error { for index, child := range parent.Children { - childDepth := depth + 1 location := fmt.Sprintf("%s.children[%d]", strings.Join(path, " -> "), index) - if childDepth > MaxSemanticTraversalDepth { - return fmt.Errorf("semantic traversal depth %d exceeds maximum %d at %s", childDepth, MaxSemanticTraversalDepth, location) - } alias := strings.TrimSpace(child.Alias) if alias == "" { return fmt.Errorf("semantic traversal alias is required at %s", location) @@ -75,28 +66,13 @@ func (s *semanticValidationState) validateChildren(parent SemanticNode, depth in } edge := fmt.Sprintf("%s -[%s]-> %s", parent.ResourceType, child.EdgeLabel, child.ResourceType) - edgeKey := parent.ResourceType + "\x00" + child.EdgeLabel + "\x00" + child.ResourceType - // A single self-reference (for example, Patient.link.other) is a - // normal, finite FHIR relationship and must remain compilable. A route - // that repeats the same relationship within one requested path is the - // cycle that can accidentally multiply graph work; reject that while the - // depth cap protects paths made of distinct relationships. - if edgesOnPath[edgeKey] { - return fmt.Errorf("semantic traversal cycle detected at %s: %s", location, strings.Join(append(path, edge), " -> ")) - } - nextEdges := cloneTraversalPathSet(edgesOnPath) - nextEdges[edgeKey] = true - if err := s.validateChildren(child, childDepth, append(path, edge), nextEdges); err != nil { + // Semantic plans are finite values: every child is explicitly present in + // the request and therefore has a bounded traversal route. Repeating an + // edge (including a self-reference) is valid and is left to the explicit + // physical cost policy rather than an authoring-time hop or cycle cap. + if err := s.validateChildren(child, append(path, edge)); err != nil { return err } } return nil } - -func cloneTraversalPathSet(in map[string]bool) map[string]bool { - out := make(map[string]bool, len(in)+1) - for key, value := range in { - out[key] = value - } - return out -} diff --git a/internal/dataframe/spec/grain.go b/internal/dataframe/spec/grain.go index 1e981c52..a14075ba 100644 --- a/internal/dataframe/spec/grain.go +++ b/internal/dataframe/spec/grain.go @@ -43,7 +43,11 @@ func (g RowGrain) Validate() error { // RowGrainResource so every valid semantic request still carries a stable row // identity. func InferRowGrain(resourceType string) (RowGrain, bool) { - switch strings.TrimSpace(resourceType) { + canonical, ok := fhirschema.CanonicalResourceType(resourceType) + if !ok { + return "", false + } + switch canonical { case "Patient": return RowGrainPatient, true case "Specimen": @@ -57,10 +61,7 @@ func InferRowGrain(resourceType string) (RowGrain, bool) { case "ResearchSubject": return RowGrainStudyEnrollment, true default: - if fhirschema.HasResource(resourceType) { - return RowGrainResource, true - } - return "", false + return RowGrainResource, true } } @@ -98,15 +99,16 @@ func ValidateRootGrain(resourceType string, grain RowGrain) error { if err := grain.Validate(); err != nil { return err } - if !fhirschema.HasResource(resourceType) { + canonical, ok := fhirschema.ConcreteResourceType(resourceType) + if !ok { return fmt.Errorf("root resource type %q is not represented by the active generated FHIR schema", resourceType) } expected, ok := RootResourceForGrain(grain) if !ok { return fmt.Errorf("unsupported row grain %q", grain) } - if expected != "" && resourceType != expected { - return fmt.Errorf("row grain %q requires root resource type %q, got %q", grain, expected, resourceType) + if expected != "" && canonical != expected { + return fmt.Errorf("row grain %q requires root resource type %q, got %q", grain, expected, canonical) } return nil } diff --git a/internal/explorer/arango/capability_snapshot_store.go b/internal/explorer/arango/capability_snapshot_store.go new file mode 100644 index 00000000..80c720ca --- /dev/null +++ b/internal/explorer/arango/capability_snapshot_store.go @@ -0,0 +1,202 @@ +package arango + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + "github.com/calypr/loom/internal/explorer/capability" + "github.com/calypr/loom/internal/explorer/capabilitystore" + store "github.com/calypr/loom/internal/store/arango" +) + +// CapabilitySnapshotCollection is intentionally separate from the legacy +// Explorer collections. Registration in the server bootstrap should include +// this persistent, non-truncating collection. +const CapabilitySnapshotCollection = "loom_explorer_capability_snapshots" + +// CapabilitySnapshotCollectionSpec is exported so the server's shared +// bootstrap registry can append it without coupling this adapter to the +// legacy collection list. +func CapabilitySnapshotCollectionSpec() store.CollectionSpec { + return store.CollectionSpec{ + Name: CapabilitySnapshotCollection, + Indexes: [][]string{ + {"identity.project", "identity.generation", "identity.authorizationScopeDigest", "identity.protocolVersion", "identity.compilerVersion"}, + {"identity.project", "identity.generation", "identity.authorizationScopeDigest", "status"}, + }, + } +} + +// CapabilitySnapshotStore persists the complete canonical snapshot under its +// content address. Insert-ignore is deliberate: retries never execute an +// UPDATE, so an immutable document's payload and revision remain untouched. +type CapabilitySnapshotStore struct{ client client } + +func NewCapabilitySnapshotStore(c client) (*CapabilitySnapshotStore, error) { + if c == nil { + return nil, fmt.Errorf("Explorer capability snapshot Arango client is required") + } + return &CapabilitySnapshotStore{client: c}, nil +} + +// NewSnapshotStore is a concise compatibility constructor. +func NewSnapshotStore(c client) (*CapabilitySnapshotStore, error) { + return NewCapabilitySnapshotStore(c) +} + +func (s *CapabilitySnapshotStore) Put(ctx context.Context, snapshot capability.Snapshot) (*capability.Snapshot, error) { + if err := capabilitystore.ValidateSnapshot(snapshot); err != nil { + return nil, err + } + doc, err := canonicalSnapshotDocument(snapshot, capabilitySnapshotKey(snapshot.Token)) + if err != nil { + return nil, err + } + var out *capability.Snapshot + err = s.client.QueryRows(ctx, capabilitySnapshotPutAQL, 1, map[string]any{ + "@c": CapabilitySnapshotCollection, + "key": capabilitySnapshotKey(snapshot.Token), + "doc": doc, + }, func(row map[string]any) error { + value, decodeErr := decode[capability.Snapshot](row) + if decodeErr != nil { + return decodeErr + } + if value.Token != snapshot.Token { + return fmt.Errorf("%w: %s", capabilitystore.ErrTokenCollision, snapshot.Token) + } + if string(value.CanonicalPayload()) != string(snapshot.CanonicalPayload()) { + return fmt.Errorf("%w: %s", capabilitystore.ErrTokenCollision, snapshot.Token) + } + value = value.Clone() + out = &value + return nil + }) + if err != nil { + return nil, err + } + if out == nil { + existing, getErr := s.GetByToken(ctx, snapshot.Token) + if getErr != nil { + return nil, getErr + } + if string(existing.CanonicalPayload()) != string(snapshot.CanonicalPayload()) { + return nil, fmt.Errorf("%w: %s", capabilitystore.ErrTokenCollision, snapshot.Token) + } + return existing, nil + } + return out, nil +} + +func (s *CapabilitySnapshotStore) GetByToken(ctx context.Context, token string) (*capability.Snapshot, error) { + var out *capability.Snapshot + err := s.client.QueryRows(ctx, capabilitySnapshotGetByTokenAQL, 1, map[string]any{ + "@c": CapabilitySnapshotCollection, + "key": capabilitySnapshotKey(token), + "token": token, + }, func(row map[string]any) error { + value, err := decode[capability.Snapshot](row) + if err == nil { + err = capabilitystore.ValidateSnapshot(value) + } + if err == nil { + value = value.Clone() + out = &value + } + return err + }) + if err != nil { + return nil, err + } + if out == nil { + return nil, capabilitystore.ErrNotFound + } + return out, nil +} + +func (s *CapabilitySnapshotStore) GetByIdentity(ctx context.Context, identity capability.SnapshotIdentity) (*capability.Snapshot, error) { + var out *capability.Snapshot + err := s.client.QueryRows(ctx, capabilitySnapshotGetByIdentityAQL, 1, map[string]any{ + "@c": CapabilitySnapshotCollection, + "project": identity.Project, + "generation": identity.Generation, + "authorizationScopeDigest": identity.AuthorizationScopeDigest, + "schemaDigest": identity.SchemaDigest, + "resourceInventoryDigest": identity.ResourceInventoryDigest, + "relationshipDigest": identity.RelationshipDigest, + "fieldDigest": identity.FieldDigest, + "protocolVersion": identity.ProtocolVersion, + "compilerVersion": identity.CompilerVersion, + "traversalPolicyVersion": identity.TraversalPolicyVersion, + "projectionPolicyVersion": identity.ProjectionPolicyVersion, + "statuses": []string{string(capability.StatusReady), string(capability.StatusBuilding), string(capability.StatusFailed)}, + }, func(row map[string]any) error { + value, err := decode[capability.Snapshot](row) + if err == nil { + err = capabilitystore.ValidateSnapshot(value) + } + if err == nil { + value = value.Clone() + out = &value + } + return err + }) + if err != nil { + return nil, err + } + if out == nil { + return nil, capabilitystore.ErrNotFound + } + return out, nil +} + +func capabilitySnapshotKey(token string) string { + return "capability_snapshot_" + strings.NewReplacer(":", "_", "/", "_").Replace(token) +} + +func canonicalSnapshotDocument(snapshot capability.Snapshot, key string) (map[string]any, error) { + // CanonicalPayload is the exact payload covered by Token. Add Token back to + // that normalized object so Arango stores a canonical *full* snapshot. + var doc map[string]any + if err := json.Unmarshal(snapshot.CanonicalPayload(), &doc); err != nil { + return nil, err + } + doc["token"] = snapshot.Token + doc["_key"] = key + return doc, nil +} + +const capabilitySnapshotPutAQL = ` +INSERT @doc INTO @@c + OPTIONS { overwriteMode: "ignore" } + RETURN NEW +` + +const capabilitySnapshotGetByTokenAQL = ` +FOR d IN @@c + FILTER d._key == @key AND d.token == @token + RETURN d +` + +const capabilitySnapshotGetByIdentityAQL = ` +FOR d IN @@c + FILTER d.identity.project == @project + AND d.identity.generation == @generation + AND d.identity.authorizationScopeDigest == @authorizationScopeDigest + AND d.identity.schemaDigest == @schemaDigest + AND d.identity.resourceInventoryDigest == @resourceInventoryDigest + AND d.identity.relationshipDigest == @relationshipDigest + AND d.identity.fieldDigest == @fieldDigest + AND d.identity.protocolVersion == @protocolVersion + AND d.identity.compilerVersion == @compilerVersion + AND d.identity.traversalPolicyVersion == @traversalPolicyVersion + AND d.identity.projectionPolicyVersion == @projectionPolicyVersion + AND d.status IN @statuses +SORT d.status == "READY" DESC, d.token +LIMIT 1 +RETURN d +` + +var _ capabilitystore.Repository = (*CapabilitySnapshotStore)(nil) diff --git a/internal/explorer/arango/capability_snapshot_store_test.go b/internal/explorer/arango/capability_snapshot_store_test.go new file mode 100644 index 00000000..3ccd75d0 --- /dev/null +++ b/internal/explorer/arango/capability_snapshot_store_test.go @@ -0,0 +1,91 @@ +package arango + +import ( + "context" + "strings" + "testing" + + "github.com/calypr/loom/internal/explorer/capability" + storepkg "github.com/calypr/loom/internal/store/arango" +) + +type capabilitySnapshotClient struct { + calls []queryCall + row map[string]any +} + +func (c *capabilitySnapshotClient) WithTransaction(ctx context.Context, _ storepkg.TransactionCollections, fn storepkg.TransactionFunc) error { + return fn(ctx, c) +} + +func (c *capabilitySnapshotClient) QueryRows(_ context.Context, query string, _ int, binds map[string]any, visit storepkg.RowVisitor) error { + c.calls = append(c.calls, queryCall{query: query, binds: binds}) + if c.row != nil { + return visit(c.row) + } + return nil +} + +func TestCapabilitySnapshotStoreBindsImmutableIdentity(t *testing.T) { + client := &capabilitySnapshotClient{} + adapter, err := NewCapabilitySnapshotStore(client) + if err != nil { + t.Fatal(err) + } + snapshot := testCapabilitySnapshot() + client.row, err = canonicalSnapshotDocument(snapshot, capabilitySnapshotKey(snapshot.Token)) + if err != nil { + t.Fatal(err) + } + if _, err := adapter.Put(context.Background(), snapshot); err != nil { + t.Fatal(err) + } + if len(client.calls) != 1 { + t.Fatalf("calls=%d", len(client.calls)) + } + call := client.calls[0] + if !strings.Contains(call.query, "INSERT @doc") || !strings.Contains(call.query, `overwriteMode: "ignore"`) || strings.Contains(call.query, "UPDATE") { + t.Fatalf("Put query is not immutable insert-if-absent:\n%s", call.query) + } + doc := call.binds["doc"].(map[string]any) + if doc["token"] != snapshot.Token || doc["identity"] == nil || doc["status"] != string(snapshot.Status) { + t.Fatalf("canonical full document=%#v", doc) + } + + client.row, err = canonicalSnapshotDocument(snapshot, capabilitySnapshotKey(snapshot.Token)) + if err != nil { + t.Fatal(err) + } + if _, err := adapter.GetByIdentity(context.Background(), snapshot.Identity); err != nil { + t.Fatal(err) + } + identityCall := client.calls[len(client.calls)-1] + for _, required := range []string{ + "d.identity.project == @project", "d.identity.generation == @generation", + "d.identity.authorizationScopeDigest == @authorizationScopeDigest", + "d.identity.protocolVersion == @protocolVersion", "d.identity.compilerVersion == @compilerVersion", + "d.status IN @statuses", + } { + if !strings.Contains(identityCall.query, required) { + t.Fatalf("identity query missing %q:\n%s", required, identityCall.query) + } + } + if got := identityCall.binds["project"]; got != snapshot.Identity.Project { + t.Fatalf("project bind=%v", got) + } + if got := identityCall.binds["generation"]; got != snapshot.Identity.Generation { + t.Fatalf("generation bind=%v", got) + } +} + +func testCapabilitySnapshot() capability.Snapshot { + return capability.NewSnapshot( + capability.SnapshotIdentity{ + Project: "project-a", Generation: "generation-a", AuthorizationScopeDigest: "scope-a", + SchemaDigest: "schema-a", ResourceInventoryDigest: "inventory-a", RelationshipDigest: "relationship-a", FieldDigest: "field-a", + ProtocolVersion: "protocol-a", CompilerVersion: "compiler-a", TraversalPolicyVersion: "traversal-a", ProjectionPolicyVersion: "projection-a", + }, + capability.Policy{}, capability.StatusFailed, false, false, nil, nil, nil, + []capability.Diagnostic{{Code: "failed", Message: "diagnostic"}}, + ) +} diff --git a/internal/explorer/arango/collections.go b/internal/explorer/arango/collections.go index e30a9b85..afc6ead1 100644 --- a/internal/explorer/arango/collections.go +++ b/internal/explorer/arango/collections.go @@ -4,9 +4,10 @@ package arango import store "github.com/calypr/loom/internal/store/arango" const ( - ExplorersCollection = "loom_explorers" - RevisionsCollection = "loom_explorer_revisions" - RepositoryConfigsCollection = "loom_repository_explorer_configs" + ExplorersCollection = "loom_explorers" + RevisionsCollection = "loom_explorer_revisions" + CompilationReceiptsCollection = "loom_explorer_compilation_receipts" + RepositoryConfigsCollection = "loom_repository_explorer_configs" ) // CollectionSpecs is deliberately non-truncating: both draft history pointers @@ -15,7 +16,13 @@ func CollectionSpecs() []store.CollectionSpec { return []store.CollectionSpec{ {Name: ExplorersCollection, Indexes: [][]string{{"project", "explorerId"}}}, {Name: RevisionsCollection, Indexes: [][]string{{"project", "explorerId", "createdAt"}, {"project", "status"}, {"project", "explorerId", "sourceCommit", "definitionDigest", "sourceGeneration"}}}, + {Name: CompilationReceiptsCollection, Indexes: [][]string{ + {"project", "explorerId", "intentDigest"}, + {"project", "explorerId", "createdAt"}, + {"project", "explorerId", "compilationKey", "receiptFormatVersion", "compilerContractVersion"}, + }}, {Name: RepositoryConfigsCollection, Indexes: [][]string{{"project"}}}, + CapabilitySnapshotCollectionSpec(), } } func BootstrapSpec() store.BootstrapSpec { return store.BootstrapSpec{Collections: CollectionSpecs()} } diff --git a/internal/explorer/arango/collections_test.go b/internal/explorer/arango/collections_test.go index 03d0a6fd..1a61979b 100644 --- a/internal/explorer/arango/collections_test.go +++ b/internal/explorer/arango/collections_test.go @@ -4,7 +4,7 @@ import "testing" func TestCollectionSpecsArePersistentAndIndexed(t *testing.T) { s := CollectionSpecs() - if len(s) != 3 { + if len(s) != 5 { t.Fatalf("specs=%#v", s) } for _, spec := range s { diff --git a/internal/explorer/arango/receipt_store_test.go b/internal/explorer/arango/receipt_store_test.go new file mode 100644 index 00000000..f7b66e97 --- /dev/null +++ b/internal/explorer/arango/receipt_store_test.go @@ -0,0 +1,100 @@ +package arango + +import ( + "context" + "encoding/json" + "strings" + "testing" + + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/explorer" + storepkg "github.com/calypr/loom/internal/store/arango" +) + +type receiptClient struct { + calls []queryCall + doc map[string]any +} + +func (c *receiptClient) WithTransaction(ctx context.Context, _ storepkg.TransactionCollections, fn storepkg.TransactionFunc) error { + return fn(ctx, c) +} + +func (c *receiptClient) QueryRows(_ context.Context, query string, _ int, binds map[string]any, visit storepkg.RowVisitor) error { + c.calls = append(c.calls, queryCall{query: query, binds: binds}) + if strings.HasPrefix(strings.TrimSpace(query), "INSERT") { + if c.doc == nil { + c.doc = binds["doc"].(map[string]any) + } + return visit(c.doc) + } + if strings.Contains(query, "oldestCreatedAt") { + return visit(map[string]any{"count": 1, "approxBytes": 128, "oldestCreatedAt": "2026-01-01T00:00:00Z", "unreferencedCount": 1}) + } + if c.doc != nil { + return visit(c.doc) + } + return nil +} + +func TestReceiptArangoStoreUsesImmutableTenantScopedQueries(t *testing.T) { + client := &receiptClient{} + adapter, err := New(client) + if err != nil { + t.Fatal(err) + } + bundle := testReceiptBundle() + receipt := explorer.CompilationReceipt{ + ReceiptFormatVersion: explorer.CurrentReceiptFormatVersion, + CompilerContractVersion: explorer.CurrentCompilerContractVersion, + Project: "project-a", ExplorerID: "explorer-a", IntentDigest: "intent", SnapshotToken: "snapshot", + AuthorizationScopeDigest: "scope", CapabilitySchemaDigest: "schema", + SourceGeneration: "generation", RecipeDigest: "recipe", ResolvedSchemaDigest: "resolved-schema", + Bundle: bundle, PublicOutputContract: json.RawMessage(`{"outputId":"output","columns":[]}`), + } + receipt.ResolvedRecipeDigest, _ = bundle.Digest() + receipt.OutputContractDigest, _ = explorer.CompilationArtifactDigest(receipt.PublicOutputContract) + receipt.CompilationKey, _ = explorer.CompilationKey(receipt) + receipt.ID, err = explorer.ReceiptID(receipt) + if err != nil { + t.Fatal(err) + } + if _, err := adapter.InsertCompilationReceipt(context.Background(), receipt); err != nil { + t.Fatal(err) + } + if strings.Contains(client.calls[0].query, "UPSERT") || strings.Contains(client.calls[0].query, "UPDATE") || !strings.Contains(client.calls[0].query, "overwriteMode: \"ignore\"") { + t.Fatalf("receipt insert is not immutable: %s", client.calls[0].query) + } + if _, err := adapter.GetCompilationReceiptForExplorer(context.Background(), "project-a", "explorer-a", receipt.ID); err != nil { + t.Fatal(err) + } + call := client.calls[len(client.calls)-1] + if !strings.Contains(call.query, "d.project == @project") || !strings.Contains(call.query, "d.explorerId == @explorerId") { + t.Fatalf("lookup is not tenant scoped: %s", call.query) + } + if _, err := adapter.GetCompilationReceiptByCompilationKey(context.Background(), "project-a", "explorer-a", receipt.CompilationKey); err != nil { + t.Fatal(err) + } + if !strings.Contains(client.calls[len(client.calls)-1].query, "d.compilationKey == @compilationKey") { + t.Fatalf("compilation key query missing: %s", client.calls[len(client.calls)-1].query) + } +} + +func TestReceiptArangoStats(t *testing.T) { + client := &receiptClient{} + adapter, err := New(client) + if err != nil { + t.Fatal(err) + } + stats, err := adapter.CompilationReceiptStats(context.Background(), "project-a") + if err != nil { + t.Fatal(err) + } + if stats.Count != 1 || stats.ApproxBytes != 128 || stats.UnreferencedCount != 1 { + t.Fatalf("stats=%+v", stats) + } +} + +func testReceiptBundle() recipe.Bundle { + return recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "receipt-test", TranslationVersion: "test", Outputs: []recipe.Output{{Name: "output", RootResourceType: "Patient", RowGrain: "resource"}}} +} diff --git a/internal/explorer/arango/store.go b/internal/explorer/arango/store.go index 178e7f24..ce7680c5 100644 --- a/internal/explorer/arango/store.go +++ b/internal/explorer/arango/store.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "strings" "time" publicationarango "github.com/calypr/loom/internal/dataframe/publication/arango" @@ -168,6 +169,200 @@ func (s *Store) SaveDraft(ctx context.Context, e explorer.Explorer, expected int return out, nil } +func (s *Store) InsertCompilationReceipt(ctx context.Context, receipt explorer.CompilationReceipt) (*explorer.CompilationReceipt, error) { + if err := validateReceipt(receipt); err != nil { + return nil, err + } + doc, err := document(receipt, receipt.ID) + if err != nil { + return nil, err + } + // INSERT with overwriteMode=ignore makes the key immutable under retries + // and concurrent requests. The read below is authoritative and compares + // the content-addressed identity, detecting a corrupted key collision. + err = s.client.QueryRows(ctx, `INSERT @doc INTO @@c OPTIONS { overwriteMode: "ignore" } RETURN NEW`, 1, map[string]any{"@c": CompilationReceiptsCollection, "doc": doc}, func(map[string]any) error { return nil }) + if err != nil { + return nil, err + } + if receipt.Project != "" && receipt.ExplorerID != "" { + return s.GetCompilationReceiptForExplorer(ctx, receipt.Project, receipt.ExplorerID, receipt.ID) + } + return s.GetCompilationReceipt(ctx, receipt.ID) +} + +func (s *Store) GetCompilationReceipt(ctx context.Context, id string) (*explorer.CompilationReceipt, error) { + return s.readCompilationReceipt(ctx, `FOR d IN @@c FILTER d._key == @key RETURN d`, map[string]any{"@c": CompilationReceiptsCollection, "key": id}) +} + +func (s *Store) GetCompilationReceiptForExplorer(ctx context.Context, project, explorerID, id string) (*explorer.CompilationReceipt, error) { + return s.readCompilationReceipt(ctx, `FOR d IN @@c FILTER d._key == @key AND d.project == @project AND d.explorerId == @explorerId RETURN d`, map[string]any{"@c": CompilationReceiptsCollection, "key": id, "project": project, "explorerId": explorerID}) +} + +func (s *Store) GetCompilationReceiptByCompilationKey(ctx context.Context, project, explorerID, compilationKey string) (*explorer.CompilationReceipt, error) { + return s.readCompilationReceipt(ctx, `FOR d IN @@c FILTER d.project == @project AND d.explorerId == @explorerId AND d.compilationKey == @compilationKey SORT d._key LIMIT 1 RETURN d`, map[string]any{"@c": CompilationReceiptsCollection, "project": project, "explorerId": explorerID, "compilationKey": compilationKey}) +} + +func (s *Store) readCompilationReceipt(ctx context.Context, query string, binds map[string]any) (*explorer.CompilationReceipt, error) { + var out *explorer.CompilationReceipt + err := s.client.QueryRows(ctx, query, 1, binds, func(row map[string]any) error { + value, decodeErr := decode[explorer.CompilationReceipt](row) + if decodeErr != nil { + return decodeErr + } + if err := validateReceipt(value); err != nil { + return err + } + out = &value + return nil + }) + if err != nil { + return nil, err + } + if out == nil { + return nil, explorer.ErrNotFound + } + return out, nil +} + +func validateReceipt(receipt explorer.CompilationReceipt) error { + if strings.TrimSpace(receipt.ID) == "" { + return explorer.ErrCorruptReceipt + } + if receipt.ReceiptFormatVersion != 0 || receipt.CompilerContractVersion != "" || receipt.CompilationKey != "" { + if err := receipt.Validate(); err != nil { + return err + } + } + if strings.HasPrefix(receipt.ID, "receipt_") && len(receipt.ID) == len("receipt_")+sha256.Size*2 { + if _, err := hex.DecodeString(strings.TrimPrefix(receipt.ID, "receipt_")); err != nil { + return explorer.ErrCorruptReceipt + } + if err := receipt.ValidateID(); err != nil { + return explorer.ErrCorruptReceipt + } + } + return nil +} + +func sameReceipt(a, b explorer.CompilationReceipt) bool { + left, leftErr := explorer.ReceiptID(a) + right, rightErr := explorer.ReceiptID(b) + return leftErr == nil && rightErr == nil && left == right +} + +func (s *Store) CompilationReceiptStats(ctx context.Context, project string) (explorer.ReceiptStoreStats, error) { + var row struct { + Count int `json:"count"` + ApproxBytes int64 `json:"approxBytes"` + OldestCreatedAt string `json:"oldestCreatedAt"` + UnreferencedCount int `json:"unreferencedCount"` + } + err := s.client.QueryRows(ctx, `LET referenced = (FOR r IN @@revisions FILTER r.compilationReceiptId != null AND (@project == "" OR r.project == @project) RETURN r.compilationReceiptId) LET receipts = (FOR d IN @@receipts FILTER @project == "" OR d.project == @project RETURN d) RETURN {count: LENGTH(receipts), approxBytes: SUM(FOR d IN receipts RETURN LENGTH(TO_STRING(d))), oldestCreatedAt: MIN(FOR d IN receipts RETURN d.createdAt), unreferencedCount: LENGTH(FOR d IN receipts FILTER d._key NOT IN referenced RETURN 1)}`, 1, map[string]any{"@receipts": CompilationReceiptsCollection, "@revisions": RevisionsCollection, "project": project}, func(value map[string]any) error { + decoded, err := decode[struct { + Count int `json:"count"` + ApproxBytes int64 `json:"approxBytes"` + OldestCreatedAt string `json:"oldestCreatedAt"` + UnreferencedCount int `json:"unreferencedCount"` + }](value) + if err != nil { + return err + } + row.Count, row.ApproxBytes, row.OldestCreatedAt, row.UnreferencedCount = decoded.Count, decoded.ApproxBytes, decoded.OldestCreatedAt, decoded.UnreferencedCount + return nil + }) + if err != nil { + return explorer.ReceiptStoreStats{}, err + } + stats := explorer.ReceiptStoreStats{Count: row.Count, ApproxBytes: row.ApproxBytes, UnreferencedCount: row.UnreferencedCount} + if row.OldestCreatedAt != "" { + parsed, parseErr := time.Parse(time.RFC3339Nano, row.OldestCreatedAt) + if parseErr != nil { + parsed, parseErr = time.Parse(time.RFC3339, row.OldestCreatedAt) + } + if parseErr != nil { + return explorer.ReceiptStoreStats{}, fmt.Errorf("invalid receipt oldestCreatedAt: %w", parseErr) + } + stats.OldestCreatedAt = parsed + } + return stats, nil +} + +func (s *Store) PublishAuthoring(ctx context.Context, receipt explorer.CompilationReceipt, revision explorer.Revision) (*explorer.Revision, error) { + if err := validateReceipt(receipt); err != nil { + return nil, err + } + receiptDoc, err := document(receipt, receipt.ID) + if err != nil { + return nil, err + } + revisionDoc, err := document(revision, revision.ID) + if err != nil { + return nil, err + } + management := explorer.ManagementInteractive + if revision.ExplorerID == "default" { + management = explorer.ManagementRepository + } + var out *explorer.Revision + err = s.client.WithTransaction(ctx, store.TransactionCollections{Write: []string{ExplorersCollection, RevisionsCollection, CompilationReceiptsCollection}}, func(txCtx context.Context, tx store.Transaction) error { + if err := tx.QueryRows(txCtx, `INSERT @doc INTO @@c OPTIONS { overwriteMode: "ignore" } RETURN NEW`, 1, map[string]any{"@c": CompilationReceiptsCollection, "doc": receiptDoc}, func(map[string]any) error { return nil }); err != nil { + return err + } + var stored *explorer.CompilationReceipt + if err := tx.QueryRows(txCtx, `FOR d IN @@c FILTER d._key == @key AND d.project == @project AND d.explorerId == @explorerId RETURN d`, 1, map[string]any{"@c": CompilationReceiptsCollection, "key": receipt.ID, "project": receipt.Project, "explorerId": receipt.ExplorerID}, func(row map[string]any) error { + value, err := decode[explorer.CompilationReceipt](row) + if err != nil { + return err + } + if err := validateReceipt(value); err != nil { + return err + } + stored = &value + return nil + }); err != nil { + return err + } + if stored == nil { + return explorer.ErrNotFound + } + if !sameReceipt(*stored, receipt) { + return explorer.ErrCorruptReceipt + } + if err := tx.QueryRows(txCtx, `UPSERT { _key: @key } INSERT @doc UPDATE {} IN @@c RETURN NEW`, 1, map[string]any{"@c": RevisionsCollection, "key": revision.ID, "doc": revisionDoc}, func(map[string]any) error { return nil }); err != nil { + return err + } + row, found, err := readActivationRow(txCtx, tx, activationReadAQL, map[string]any{"@explorers": ExplorersCollection, "@revisions": RevisionsCollection, "explorerKey": explorerKey(revision.Project, revision.ExplorerID), "revisionKey": revision.ID, "project": revision.Project, "explorerId": revision.ExplorerID, "management": management}) + if err != nil { + return err + } + if !found { + return explorer.ErrDraftConflict + } + state, err := activationStateFromRow(row) + if err != nil { + return err + } + if err := activateRevisionAndOwner(txCtx, tx, state, time.Now().UTC()); err != nil { + return err + } + return tx.QueryRows(txCtx, `FOR d IN @@c FILTER d._key == @key RETURN d`, 1, map[string]any{"@c": RevisionsCollection, "key": revision.ID}, func(row map[string]any) error { value, err := decode[explorer.Revision](row); out = &value; return err }) + }) + return out, err +} + +func (s *Store) PurgeDraftAuthoring(ctx context.Context) error { + return s.client.WithTransaction(ctx, store.TransactionCollections{Write: []string{ExplorersCollection, CompilationReceiptsCollection}, Read: []string{RevisionsCollection}}, func(txCtx context.Context, tx store.Transaction) error { + // UNSET returns the complete cleaned document. Use REPLACE here: UPDATE + // merges that result back into the original document, which leaves every + // retired draft field in place and makes the cutover appear to succeed + // while preserving the legacy state. + if err := tx.QueryRows(txCtx, `FOR d IN @@explorers REPLACE d WITH UNSET(d, "draftConfig", "draftVersion", "draftDigest", "draftAuthoringBundle", "draftIntentDigest", "draftReceiptId", "draftIdentityMappings", "draftDefinition", "authoringBundle", "intentDigest", "receiptPointer", "identityMappings", "version", "digest") IN @@explorers RETURN {purged: true}`, 100000, map[string]any{"@explorers": ExplorersCollection}, func(map[string]any) error { return nil }); err != nil { + return err + } + return tx.QueryRows(txCtx, `LET referenced = (FOR r IN @@revisions FILTER r.compilationReceiptId != null RETURN DISTINCT r.compilationReceiptId) FOR receipt IN @@receipts FILTER receipt._key NOT IN referenced REMOVE receipt IN @@receipts RETURN {purged: true}`, 100000, map[string]any{"@revisions": RevisionsCollection, "@receipts": CompilationReceiptsCollection}, func(map[string]any) error { return nil }) + }) +} + func (s *Store) InsertRevision(ctx context.Context, revision explorer.Revision) (*explorer.Revision, error) { if revision.ID == "" { return nil, fmt.Errorf("revision ID is required") diff --git a/internal/explorer/authoring_v1.go b/internal/explorer/authoring_v1.go new file mode 100644 index 00000000..627286d7 --- /dev/null +++ b/internal/explorer/authoring_v1.go @@ -0,0 +1,470 @@ +package explorer + +// This file is the versioned Explorer authoring wire contract. It is kept in +// the Explorer domain package so HTTP, ETL, and repository bootstrap callers +// share one decoder and one canonical digest implementation. + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "sort" + "strings" +) + +const ( + ExplorerAuthoringV1APIVersion = "loom.calypr.org/explorer-authoring/v1" + ExplorerAuthoringV1Kind = "ExplorerAuthoringBundle" + ExplorerBuilderV1Kind = "ExplorerBuilderDocument" +) + +// ExplorerAuthoringBundleV1 is the portable authoring artifact. Intent is +// the only durable browser-facing representation. The compiled recipe is +// held by CompilationReceipt and never appears in this document. +type ExplorerAuthoringBundleV1 struct { + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + Title string `json:"title,omitempty"` + // Document is accepted as a compatibility input for the original V1 + // single-output packet. Canonical output always uses Documents so one + // Explorer can retain all of its output-backed tabs. + Document ExplorerBuilderDocumentV1 `json:"document"` + Documents []ExplorerBuilderDocumentV1 `json:"documents,omitempty"` + Tabs []ExplorerTabV1 `json:"tabs,omitempty"` + IntentDigest string `json:"intentDigest,omitempty"` +} + +// MarshalJSON emits only the canonical plural Builder shape. Document remains +// a decode-only compatibility field so legacy packets can be migrated without +// leaking the singular form back into current Builder responses. +func (b ExplorerAuthoringBundleV1) MarshalJSON() ([]byte, error) { + documents := b.AuthoringDocuments() + if documents == nil { + documents = []ExplorerBuilderDocumentV1{} + } + tabs := b.Tabs + if tabs == nil { + tabs = []ExplorerTabV1{} + } + return json.Marshal(struct { + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + Title string `json:"title,omitempty"` + Documents []ExplorerBuilderDocumentV1 `json:"documents"` + Tabs []ExplorerTabV1 `json:"tabs"` + IntentDigest string `json:"intentDigest,omitempty"` + }{b.APIVersion, b.Kind, b.Project, b.ExplorerID, b.Title, documents, tabs, b.IntentDigest}) +} + +// ExplorerBuilderDocumentV1 contains authoring intent only. In particular, +// it has no recipe expression, select, alias, generated public column, or +// physical/storage identity. +type ExplorerBuilderDocumentV1 struct { + Kind string `json:"kind"` + Output ExplorerOutputIdentityV1 `json:"output"` + BaseNodeID string `json:"baseNodeId"` + RowNodeID string `json:"rowNodeId"` + RouteEdgeIDs []string `json:"routeEdgeIds,omitempty"` + RouteOccurrences []ExplorerRouteOccurrenceV1 `json:"routeOccurrences,omitempty"` + CandidateIDs []string `json:"candidateIds,omitempty"` + CandidateOccurrences []ExplorerCandidateOccurrenceV1 `json:"candidateOccurrences,omitempty"` + Presentation map[string]ExplorerPresentationBindingV1 `json:"presentation,omitempty"` +} + +type ExplorerOutputIdentityV1 struct { + ID string `json:"id"` + Title string `json:"title,omitempty"` +} + +// ExplorerTabV1 describes the visible tab/view layer without exposing recipe +// fields or generated columns. Output-backed tabs may be ordered independently +// of the recipe output order, and outputs not referenced by a tab remain valid +// materialization outputs without becoming visible tabs. +type ExplorerTabV1 struct { + ID string `json:"id"` + Title string `json:"title"` + OutputID string `json:"outputId"` + Order int `json:"order"` + Visible *bool `json:"visible,omitempty"` +} + +// Route occurrences identify a node occurrence in a route, rather than only +// a resource type. That distinction is required when a route repeats a +// resource type. +type ExplorerRouteOccurrenceV1 struct { + ID string `json:"id"` + Index int `json:"index"` + NodeID string `json:"nodeId"` + IncomingEdgeID string `json:"incomingEdgeId,omitempty"` +} + +// Candidate occurrences make candidate resolution unambiguous for repeated +// resource types and for candidates that are valid at more than one node. +type ExplorerCandidateOccurrenceV1 struct { + CandidateID string `json:"candidateId"` + OccurrenceID string `json:"occurrenceId"` + // ProjectionMode is populated by the V2 adapter. Legacy stored V1 + // documents omit it and use the compiler-proven candidate default. + ProjectionMode string `json:"projectionMode,omitempty"` +} + +// Presentation is keyed by the server-owned emission ID. No presentation +// object can name a recipe field or generated public column. +type ExplorerPresentationBindingV1 struct { + Label string `json:"label,omitempty"` + Visible *bool `json:"visible,omitempty"` + Order *int `json:"order,omitempty"` + Table *ExplorerTableBindingV1 `json:"table,omitempty"` + Filter *ExplorerFilterBindingV1 `json:"filter,omitempty"` + Chart *ExplorerChartBindingV1 `json:"chart,omitempty"` +} + +type ExplorerTableBindingV1 struct { + Pinned bool `json:"pinned,omitempty"` +} + +type ExplorerFilterBindingV1 struct { + Label string `json:"label,omitempty"` +} + +type ExplorerChartBindingV1 struct { + Type string `json:"type"` + Title string `json:"title,omitempty"` +} + +type AuthoringDiagnostic struct { + Severity string `json:"severity"` + Stage string `json:"stage"` + Code string `json:"code"` + JSONPath string `json:"jsonPath"` + Message string `json:"message"` + Details map[string]any `json:"details,omitempty"` + RequestID string `json:"requestId,omitempty"` +} + +type AuthoringError struct { + Status int + Diagnostic AuthoringDiagnostic + Cause error +} + +func (e *AuthoringError) Error() string { + if e == nil { + return "Explorer authoring error" + } + return e.Diagnostic.Code + ": " + e.Diagnostic.Message +} +func (e *AuthoringError) Unwrap() error { + if e == nil { + return nil + } + return e.Cause +} + +func malformedAuthoring(stage, path, code, message string, cause error) error { + return &AuthoringError{Status: 400, Cause: cause, Diagnostic: AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: code, JSONPath: path, Message: message}} +} +func semanticAuthoring(stage, path, code, message string, details map[string]any) error { + return &AuthoringError{Status: 422, Diagnostic: AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: code, JSONPath: path, Message: message, Details: details}} +} +func conflictAuthoring(stage, code, message string, details map[string]any) error { + return &AuthoringError{Status: 409, Diagnostic: AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: code, Message: message, Details: details}} +} + +// DecodeAuthoringBundleV1 rejects unknown fields, duplicate fields, trailing +// JSON, and all recipe-shaped fields. It is intentionally separate from the +// recipe decoder: accepting a recipe here would recreate the old browser +// compiler protocol. +func DecodeAuthoringBundleV1(raw []byte) (ExplorerAuthoringBundleV1, error) { + return decodeAuthoringBundleV1(raw, false) +} + +// DecodeAuthoringBundleV1ForMigration accepts the same strict wire shape as +// DecodeAuthoringBundleV1, but defers intentDigest verification until the +// server has resolved legacy intent against the current catalog. Stored +// bundles from before candidateOccurrences was canonical may have a digest +// for that legacy shape and must still be repairable by the authoring server. +func DecodeAuthoringBundleV1ForMigration(raw []byte) (ExplorerAuthoringBundleV1, error) { + return decodeAuthoringBundleV1(raw, true) +} + +func decodeAuthoringBundleV1(raw []byte, ignoreIntentDigest bool) (ExplorerAuthoringBundleV1, error) { + if err := rejectDuplicateJSONKeys(raw); err != nil { + return ExplorerAuthoringBundleV1{}, malformedAuthoring("decode", "$", "MALFORMED_AUTHORING_REQUEST", err.Error(), err) + } + var bundle ExplorerAuthoringBundleV1 + dec := json.NewDecoder(bytes.NewReader(raw)) + dec.DisallowUnknownFields() + if err := dec.Decode(&bundle); err != nil { + return ExplorerAuthoringBundleV1{}, malformedAuthoring("decode", "$", "MALFORMED_AUTHORING_REQUEST", err.Error(), err) + } + var trailing any + if err := dec.Decode(&trailing); err != io.EOF { + if err == nil { + err = fmt.Errorf("multiple JSON values") + } + return ExplorerAuthoringBundleV1{}, malformedAuthoring("decode", "$", "MALFORMED_AUTHORING_REQUEST", err.Error(), err) + } + if ignoreIntentDigest { + bundle.IntentDigest = "" + } + validationErr := bundle.Validate() + if validationErr != nil { + return ExplorerAuthoringBundleV1{}, validationErr + } + return bundle, nil +} + +// RejectDuplicateJSONKeys is shared by the versioned HTTP envelope decoder so +// every authoring entry point has the same strict wire behavior. +func RejectDuplicateJSONKeys(raw []byte) error { return rejectDuplicateJSONKeys(raw) } + +func (b ExplorerAuthoringBundleV1) Validate() error { + if b.APIVersion != ExplorerAuthoringV1APIVersion || b.Kind != ExplorerAuthoringV1Kind { + return malformedAuthoring("protocol", "$.apiVersion", "UNSUPPORTED_AUTHORING_PROTOCOL", "unsupported Explorer authoring protocol or kind", nil) + } + if strings.TrimSpace(b.Project) == "" || strings.TrimSpace(b.ExplorerID) == "" { + return malformedAuthoring("protocol", "$.project", "MISSING_AUTHORING_IDENTITY", "project and explorerId are required", nil) + } + documents := b.AuthoringDocuments() + // An empty document list is the canonical unpublished Explorer model. + // Preview/publish reject it as non-executable, while Builder reads and + // canonical local editing may carry it safely. + if len(b.Documents) > 0 && b.Document.Kind != "" { + return malformedAuthoring("protocol", "$.document", "DUPLICATE_AUTHORING_DOCUMENTS", "use documents or document, not both", nil) + } + seenOutputs := map[string]bool{} + for i, document := range documents { + if err := document.validateAt(fmt.Sprintf("$.documents[%d]", i)); err != nil { + return err + } + if seenOutputs[document.Output.ID] { + return semanticAuthoring("intent", fmt.Sprintf("$.documents[%d].output.id", i), "DUPLICATE_OUTPUT_ID", "output IDs must be unique within an Explorer", nil) + } + seenOutputs[document.Output.ID] = true + } + seenTabs := map[string]bool{} + seenOrders := map[int]bool{} + for i, tab := range b.Tabs { + path := fmt.Sprintf("$.tabs[%d]", i) + if !idPattern.MatchString(tab.ID) || strings.TrimSpace(tab.Title) == "" || !idPattern.MatchString(tab.OutputID) { + return malformedAuthoring("protocol", path, "INVALID_EXPLORER_TAB", "tab id, title, and outputId are required and must be stable identifiers", nil) + } + if seenTabs[tab.ID] { + return semanticAuthoring("intent", path+".id", "DUPLICATE_TAB_ID", "tab IDs must be unique", nil) + } + if seenOrders[tab.Order] { + return semanticAuthoring("intent", path+".order", "DUPLICATE_TAB_ORDER", "tab order values must be unique", nil) + } + if !seenOutputs[tab.OutputID] { + return semanticAuthoring("intent", path+".outputId", "TAB_OUTPUT_MISSING", "tab must reference an output document in the same bundle", nil) + } + seenTabs[tab.ID], seenOrders[tab.Order] = true, true + } + if b.IntentDigest != "" { + digest, err := b.DocumentDigest() + if err != nil { + return err + } + if b.IntentDigest != digest { + return conflictAuthoring("digest", "INTENT_DIGEST_MISMATCH", "intentDigest does not match the canonical document", map[string]any{"expected": digest, "received": b.IntentDigest}) + } + } + return nil +} + +func (d ExplorerBuilderDocumentV1) Validate() error { + return d.validateAt("$.document") +} + +func (d ExplorerBuilderDocumentV1) validateAt(path string) error { + if d.Kind != ExplorerBuilderV1Kind { + return malformedAuthoring("protocol", path+".kind", "UNSUPPORTED_DOCUMENT_VERSION", "unsupported builder document kind", nil) + } + if strings.TrimSpace(d.Output.ID) == "" { + return malformedAuthoring("protocol", path+".output.id", "MISSING_OUTPUT_ID", "output.id is required", nil) + } + if strings.TrimSpace(d.BaseNodeID) == "" || strings.TrimSpace(d.RowNodeID) == "" { + return malformedAuthoring("protocol", path+".baseNodeId", "MISSING_ROUTE_NODE", "baseNodeId and rowNodeId are required", nil) + } + for i, edge := range d.RouteEdgeIDs { + if strings.TrimSpace(edge) == "" { + return malformedAuthoring("protocol", fmt.Sprintf("%s.routeEdgeIds[%d]", path, i), "EMPTY_ROUTE_EDGE_ID", "route edge IDs must not be empty", nil) + } + } + occurrences := map[string]bool{} + for i, occurrence := range d.RouteOccurrences { + if strings.TrimSpace(occurrence.ID) == "" || strings.TrimSpace(occurrence.NodeID) == "" { + return malformedAuthoring("protocol", fmt.Sprintf("%s.routeOccurrences[%d]", path, i), "INVALID_ROUTE_OCCURRENCE", "route occurrence id and nodeId are required", nil) + } + if occurrences[occurrence.ID] { + return semanticAuthoring("intent", fmt.Sprintf("%s.routeOccurrences[%d].id", path, i), "DUPLICATE_ROUTE_OCCURRENCE", "route occurrence IDs must be unique", nil) + } + occurrences[occurrence.ID] = true + } + candidates := map[string]bool{} + for i, candidate := range d.CandidateIDs { + if strings.TrimSpace(candidate) == "" { + return malformedAuthoring("protocol", fmt.Sprintf("%s.candidateIds[%d]", path, i), "EMPTY_CANDIDATE_ID", "candidate IDs must not be empty", nil) + } + if candidates[candidate] { + return semanticAuthoring("intent", fmt.Sprintf("%s.candidateIds[%d]", path, i), "DUPLICATE_CANDIDATE_ID", "candidate IDs must be unique", nil) + } + candidates[candidate] = true + } + for i, candidate := range d.CandidateOccurrences { + if !candidates[candidate.CandidateID] { + return semanticAuthoring("intent", fmt.Sprintf("%s.candidateOccurrences[%d].candidateId", path, i), "CANDIDATE_REFERENCE_MISSING", "candidate occurrence must reference candidateIds", nil) + } + if !occurrences[candidate.OccurrenceID] && candidate.OccurrenceID != "base" { + return semanticAuthoring("intent", fmt.Sprintf("%s.candidateOccurrences[%d].occurrenceId", path, i), "STALE_ROUTE_OCCURRENCE", "candidate occurrence references an unknown route occurrence", nil) + } + } + for emissionID := range d.Presentation { + if strings.TrimSpace(emissionID) == "" { + return malformedAuthoring("protocol", path+".presentation", "EMPTY_EMISSION_ID", "presentation keys must be emission IDs", nil) + } + } + return nil +} + +func (b ExplorerAuthoringBundleV1) CanonicalDocumentJSON() ([]byte, error) { + validationCopy := b + validationCopy.IntentDigest = "" + if err := validationCopy.Validate(); err != nil { + return nil, err + } + return json.Marshal(struct { + Documents []ExplorerBuilderDocumentV1 `json:"documents"` + Tabs []ExplorerTabV1 `json:"tabs,omitempty"` + }{Documents: b.AuthoringDocuments(), Tabs: b.Tabs}) +} +func (b ExplorerAuthoringBundleV1) DocumentDigest() (string, error) { + raw, err := b.CanonicalDocumentJSON() + if err != nil { + return "", err + } + sum := sha256.Sum256(raw) + return "sha256:" + hex.EncodeToString(sum[:]), nil +} +func (b ExplorerAuthoringBundleV1) CanonicalJSON() ([]byte, error) { + if err := b.Validate(); err != nil { + return nil, err + } + digest, err := b.DocumentDigest() + if err != nil { + return nil, err + } + return json.Marshal(struct { + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + Title string `json:"title,omitempty"` + Documents []ExplorerBuilderDocumentV1 `json:"documents"` + Tabs []ExplorerTabV1 `json:"tabs,omitempty"` + IntentDigest string `json:"intentDigest"` + }{b.APIVersion, b.Kind, b.Project, b.ExplorerID, b.Title, b.AuthoringDocuments(), b.Tabs, digest}) +} + +// AuthoringDocuments returns the normalized multi-output view of the bundle. +// The singular Document field is retained only so older V1 callers can be +// read and recompiled while all canonical artifacts use Documents. +func (b ExplorerAuthoringBundleV1) AuthoringDocuments() []ExplorerBuilderDocumentV1 { + if len(b.Documents) > 0 { + return append([]ExplorerBuilderDocumentV1(nil), b.Documents...) + } + if b.Document.Kind != "" || b.Document.Output.ID != "" || b.Document.BaseNodeID != "" { + return []ExplorerBuilderDocumentV1{b.Document} + } + return nil +} + +// AuthoringTabs returns explicit tab order when supplied. A single legacy V1 +// document keeps the historical default view; a multi-output bundle defaults +// to one tab per output when the caller omits tabs. +func (b ExplorerAuthoringBundleV1) AuthoringTabs() []ExplorerTabV1 { + if len(b.Tabs) > 0 { + return append([]ExplorerTabV1(nil), b.Tabs...) + } + documents := b.AuthoringDocuments() + tabs := make([]ExplorerTabV1, 0, len(documents)) + for i, document := range documents { + id := document.Output.ID + if len(documents) == 1 { + id = "default" + } + title := document.Output.Title + if strings.TrimSpace(title) == "" { + title = document.Output.ID + } + tabs = append(tabs, ExplorerTabV1{ID: id, Title: title, OutputID: document.Output.ID, Order: i}) + } + return tabs +} + +func rejectDuplicateJSONKeys(raw []byte) error { + dec := json.NewDecoder(bytes.NewReader(raw)) + var walk func(string) error + walk = func(path string) error { + tok, err := dec.Token() + if err != nil { + return err + } + if delim, ok := tok.(json.Delim); ok { + switch delim { + case '{': + seen := map[string]bool{} + for dec.More() { + keyToken, err := dec.Token() + if err != nil { + return err + } + key := keyToken.(string) + if seen[key] { + return fmt.Errorf("duplicate JSON object key %q at %s", key, path) + } + seen[key] = true + if err := walk(path + "." + key); err != nil { + return err + } + } + _, err = dec.Token() + return err + case '[': + i := 0 + for dec.More() { + if err := walk(fmt.Sprintf("%s[%d]", path, i)); err != nil { + return err + } + i++ + } + _, err = dec.Token() + return err + } + } + return nil + } + if err := walk("$"); err != nil { + return err + } + return nil +} + +// PresentationEmissionIDs returns sorted keys for deterministic diagnostics +// and test assertions without changing the wire representation. +func (d ExplorerBuilderDocumentV1) PresentationEmissionIDs() []string { + ids := make([]string, 0, len(d.Presentation)) + for id := range d.Presentation { + ids = append(ids, id) + } + sort.Strings(ids) + return ids +} diff --git a/internal/explorer/authoring_v1_test.go b/internal/explorer/authoring_v1_test.go new file mode 100644 index 00000000..0ddf4201 --- /dev/null +++ b/internal/explorer/authoring_v1_test.go @@ -0,0 +1,214 @@ +package explorer + +import ( + "context" + "encoding/json" + "strings" + "sync" + "testing" +) + +func TestAuthoringBundleV1StrictDecodeAndCanonicalDigest(t *testing.T) { + raw := []byte(`{"apiVersion":"loom.calypr.org/explorer-authoring/v1","kind":"ExplorerAuthoringBundle","project":"p","explorerId":"e","document":{"kind":"ExplorerBuilderDocument","output":{"id":"out"},"baseNodeId":"n_base","rowNodeId":"n_base","candidateIds":["s_id"],"presentation":{}}}`) + bundle, err := DecodeAuthoringBundleV1(raw) + if err != nil { + t.Fatal(err) + } + digest, err := bundle.DocumentDigest() + if err != nil { + t.Fatal(err) + } + canonical, err := bundle.CanonicalJSON() + if err != nil { + t.Fatal(err) + } + if !strings.Contains(string(canonical), digest) { + t.Fatalf("canonical bundle does not carry digest: %s", canonical) + } + if _, err := DecodeAuthoringBundleV1([]byte(strings.Replace(string(raw), `"candidateIds":["s_id"]`, `"candidateIds":["s_id"],"recipe":{"direction":"OUTBOUND"}`, 1))); err == nil { + t.Fatal("accepted recipe-shaped authoring field") + } + if _, err := DecodeAuthoringBundleV1([]byte(strings.Replace(string(raw), `"candidateIds":["s_id"]`, `"candidateIds":["s_id"],"children":[]`, 1))); err == nil { + t.Fatal("accepted children field") + } + if _, err := DecodeAuthoringBundleV1([]byte(strings.Replace(string(raw), `"candidateIds":["s_id"]`, `"candidateIds":["s_id"],"candidateIds":["s_id"]`, 1))); err == nil { + t.Fatal("accepted duplicate field") + } +} + +func TestAuthoringBundleV1RejectsDigestMismatch(t *testing.T) { + raw := []byte(`{"apiVersion":"loom.calypr.org/explorer-authoring/v1","kind":"ExplorerAuthoringBundle","project":"p","explorerId":"e","intentDigest":"sha256:bad","document":{"kind":"ExplorerBuilderDocument","output":{"id":"out"},"baseNodeId":"n_base","rowNodeId":"n_base"}}`) + if _, err := DecodeAuthoringBundleV1(raw); err == nil || !strings.Contains(err.Error(), "INTENT_DIGEST_MISMATCH") { + t.Fatalf("error=%v", err) + } +} + +func TestReceiptIDIsContentAddressed(t *testing.T) { + r := CompilationReceipt{Project: "p", ExplorerID: "e", IntentDigest: "sha256:a", SnapshotToken: "sha256:s", SourceGeneration: "g"} + first, err := ReceiptID(r) + if err != nil { + t.Fatal(err) + } + second, err := ReceiptID(r) + if err != nil { + t.Fatal(err) + } + if first == "" || first != second || !strings.HasPrefix(first, "receipt_") { + t.Fatalf("receipt IDs=%q,%q", first, second) + } +} + +func TestReceiptIDNormalizesJSONRepresentation(t *testing.T) { + base := CompilationReceipt{ + Project: "p", + ExplorerID: "e", + IntentDigest: "sha256:a", + SnapshotToken: "sha256:s", + SourceGeneration: "g", + CompiledConfig: json.RawMessage(`{"views":[{"columns":{"z":2,"a":1}}],"apiVersion":"loom.calypr.org/explorer-config/v2"}`), + } + reordered := base + reordered.CompiledConfig = json.RawMessage(`{"apiVersion":"loom.calypr.org/explorer-config/v2","views":[{"columns":{"a":1,"z":2}}]}`) + + first, err := ReceiptID(base) + if err != nil { + t.Fatal(err) + } + second, err := ReceiptID(reordered) + if err != nil { + t.Fatal(err) + } + if first != second { + t.Fatalf("JSON representation changed receipt ID: %q != %q", first, second) + } +} + +func TestReceiptIDSurvivesDocumentRoundTrip(t *testing.T) { + receipt := CompilationReceipt{ + Project: "p", + ExplorerID: "e", + IntentDigest: "sha256:a", + SnapshotToken: "sha256:s", + SourceGeneration: "g", + CompiledConfig: json.RawMessage(`{"views":[{"columns":{"z":2,"a":1}}],"apiVersion":"loom.calypr.org/explorer-config/v2"}`), + } + original, err := ReceiptID(receipt) + if err != nil { + t.Fatal(err) + } + + // This mirrors the Arango store's document conversion: marshal the typed + // receipt into a generic JSON document, then decode it again. + raw, err := json.Marshal(receipt) + if err != nil { + t.Fatal(err) + } + var document map[string]any + if err := json.Unmarshal(raw, &document); err != nil { + t.Fatal(err) + } + raw, err = json.Marshal(document) + if err != nil { + t.Fatal(err) + } + var roundTripped CompilationReceipt + if err := json.Unmarshal(raw, &roundTripped); err != nil { + t.Fatal(err) + } + + loaded, err := ReceiptID(roundTripped) + if err != nil { + t.Fatal(err) + } + if original != loaded { + t.Fatalf("Arango-like round trip changed receipt ID: %q != %q", original, loaded) + } +} + +func TestReceiptIDChangesWhenContentChanges(t *testing.T) { + receipt := CompilationReceipt{ + Project: "p", + ExplorerID: "e", + IntentDigest: "sha256:a", + SnapshotToken: "sha256:s", + SourceGeneration: "g", + CompiledConfig: json.RawMessage(`{"apiVersion":"loom.calypr.org/explorer-config/v2","views":[]}`), + } + original, err := ReceiptID(receipt) + if err != nil { + t.Fatal(err) + } + receipt.CompiledConfig = json.RawMessage(`{"apiVersion":"loom.calypr.org/explorer-config/v2","views":[{"id":"new"}]}`) + changed, err := ReceiptID(receipt) + if err != nil { + t.Fatal(err) + } + if original == changed { + t.Fatal("receipt ID did not change after content changed") + } +} + +func TestMemoryStorePurgesOrphanAuthoringReceipts(t *testing.T) { + store := NewMemoryStore() + service, err := NewService(store) + if err != nil { + t.Fatal(err) + } + ctx := context.Background() + for _, id := range []string{"receipt_kept", "receipt_orphan"} { + if _, err := service.StoreCompilationReceipt(ctx, CompilationReceipt{ID: id, Project: "p", ExplorerID: "e"}); err != nil { + t.Fatal(err) + } + } + if _, err := store.InsertRevision(ctx, Revision{ID: "r1", Project: "p", ExplorerID: "e", CompilationReceiptID: "receipt_kept"}); err != nil { + t.Fatal(err) + } + if err := service.PurgeDraftAuthoring(ctx); err != nil { + t.Fatal(err) + } + if _, err := service.CompilationReceipt(ctx, "receipt_kept"); err != nil { + t.Fatalf("referenced receipt removed: %v", err) + } + if _, err := service.CompilationReceipt(ctx, "receipt_orphan"); err != ErrNotFound { + t.Fatalf("orphan receipt error=%v", err) + } +} + +func TestMemoryStoreAuthoringActivationIsLastWriterWins(t *testing.T) { + store := NewMemoryStore() + ctx := context.Background() + if _, err := store.CreateInteractive(ctx, Explorer{Project: "p", ExplorerID: "e", ManagementMode: ManagementInteractive}); err != nil { + t.Fatal(err) + } + for _, revision := range []Revision{ + {ID: "r1", Project: "p", ExplorerID: "e", Status: RevisionReady}, + {ID: "r2", Project: "p", ExplorerID: "e", Status: RevisionReady}, + } { + if _, err := store.InsertRevision(ctx, revision); err != nil { + t.Fatal(err) + } + } + start := make(chan struct{}) + errs := make(chan error, 2) + var wait sync.WaitGroup + for _, revisionID := range []string{"r1", "r2"} { + wait.Add(1) + go func(id string) { + defer wait.Done() + <-start + errs <- store.ActivateInteractive(ctx, "p", "e", id) + }(revisionID) + } + close(start) + wait.Wait() + close(errs) + for err := range errs { + if err != nil { + t.Fatal(err) + } + } + owner, err := store.Get(ctx, "p", "e") + if err != nil || (owner.ActiveRevisionID != "r1" && owner.ActiveRevisionID != "r2") { + t.Fatalf("last-writer-wins activation owner=%#v err=%v", owner, err) + } +} diff --git a/internal/explorer/authoringv2/migration.go b/internal/explorer/authoringv2/migration.go new file mode 100644 index 00000000..ca6d59e0 --- /dev/null +++ b/internal/explorer/authoringv2/migration.go @@ -0,0 +1,80 @@ +package authoringv2 + +import ( + "fmt" + + "github.com/calypr/loom/internal/explorer" +) + +// MigrateV1Document is the only V1-to-V2 direction. It imports authoring +// intent, never a compiled recipe or a server-resolved binding. V1's row node +// is intentionally ignored: V2 derives its tail from routeSteps. +func MigrateV1Document(input explorer.ExplorerBuilderDocumentV1) (Document, error) { + if err := input.Validate(); err != nil { + return Document{}, fmt.Errorf("migrate V1 document: %w", err) + } + title := input.Output.Title + if title == "" { + title = input.Output.ID + } + out := Document{ + APIVersion: APIVersion, + Kind: APIVersionKind(), + Output: Output{ID: input.Output.ID, Title: title}, + RootNodeID: input.BaseNodeID, + RouteSteps: make([]RouteStep, 0, len(input.RouteEdgeIDs)), + Selections: make([]Selection, 0, len(input.CandidateIDs)), + Presentation: make(map[string]Presentation, len(input.Presentation)), + } + for index, edgeID := range input.RouteEdgeIDs { + occurrenceIndex := index + if len(input.RouteOccurrences) == len(input.RouteEdgeIDs)+1 { + occurrenceIndex++ + } + occurrenceID := "" + if occurrenceIndex < len(input.RouteOccurrences) { + occurrenceID = input.RouteOccurrences[occurrenceIndex].ID + } + out.RouteSteps = append(out.RouteSteps, RouteStep{EdgeID: edgeID, OccurrenceID: occurrenceID}) + } + if len(input.CandidateOccurrences) > 0 { + for _, occurrence := range input.CandidateOccurrences { + mode := occurrence.ProjectionMode + if mode == "" { + mode = "SCALAR" + } + out.Selections = append(out.Selections, Selection{CandidateID: occurrence.CandidateID, OccurrenceID: occurrence.OccurrenceID, ProjectionMode: mode}) + } + } else { + for _, candidateID := range input.CandidateIDs { + out.Selections = append(out.Selections, Selection{CandidateID: candidateID, OccurrenceID: RootOccurrenceID, ProjectionMode: "SCALAR"}) + } + } + for key, binding := range input.Presentation { + out.Presentation[key] = Presentation{Label: binding.Label, Visible: binding.Visible, Order: binding.Order} + } + if err := out.Validate(); err != nil { + return Document{}, fmt.Errorf("migrated V1 document is not valid V2 intent: %w", err) + } + return out, nil +} + +// MigrateV1Bundle imports every V1 output document in order. Catalog +// resolution is deliberately a later operation, so migration cannot invent +// stale IDs or accidentally create a compilation cycle. +func MigrateV1Bundle(input explorer.ExplorerAuthoringBundleV1) ([]Document, error) { + documents := input.AuthoringDocuments() + out := make([]Document, 0, len(documents)) + for i, document := range documents { + migrated, err := MigrateV1Document(document) + if err != nil { + return nil, fmt.Errorf("migrate V1 document %d: %w", i, err) + } + out = append(out, migrated) + } + return out, nil +} + +// APIVersionKind exists to keep migration call sites readable while making +// the protocol kind a single constant in the wire package. +func APIVersionKind() string { return Kind } diff --git a/internal/explorer/authoringv2/migration_test.go b/internal/explorer/authoringv2/migration_test.go new file mode 100644 index 00000000..fae0d494 --- /dev/null +++ b/internal/explorer/authoringv2/migration_test.go @@ -0,0 +1,45 @@ +package authoringv2 + +import ( + "strings" + "testing" + + "github.com/calypr/loom/internal/explorer" +) + +func TestMigrateV1DropsRowAndExecutionFields(t *testing.T) { + visible := true + order := 2 + input := explorer.ExplorerBuilderDocumentV1{ + Kind: explorer.ExplorerBuilderV1Kind, + Output: explorer.ExplorerOutputIdentityV1{ID: "out", Title: "Output"}, + BaseNodeID: "patient", RowNodeID: "legacy-row", + RouteEdgeIDs: []string{"patient-encounter"}, + RouteOccurrences: []explorer.ExplorerRouteOccurrenceV1{{ID: "encounter-occurrence", NodeID: "encounter", IncomingEdgeID: "patient-encounter"}}, + CandidateIDs: []string{"encounter-id"}, + CandidateOccurrences: []explorer.ExplorerCandidateOccurrenceV1{{CandidateID: "encounter-id", OccurrenceID: "encounter-occurrence"}}, + Presentation: map[string]explorer.ExplorerPresentationBindingV1{"encounter-id": {Label: "Encounter", Visible: &visible, Order: &order}}, + } + migrated, err := MigrateV1Document(input) + if err != nil { + t.Fatal(err) + } + if migrated.RootNodeID != "patient" || len(migrated.RouteSteps) != 1 || migrated.RouteSteps[0].OccurrenceID != "encounter-occurrence" { + t.Fatalf("unexpected migrated route: %#v", migrated) + } + if migrated.Selections[0].ProjectionMode != "SCALAR" || migrated.Selections[0].CandidateID != "encounter-id" { + t.Fatalf("unexpected migrated selection: %#v", migrated.Selections) + } + if migrated.Output.ID != "out" || migrated.Output.Title != "Output" { + t.Fatalf("output was not migrated: %#v", migrated.Output) + } + raw, err := migrated.CanonicalJSON() + if err != nil { + t.Fatal(err) + } + for _, forbidden := range []string{"rowNodeId", "legacy-row", "selector", "aql", "physicalCollection"} { + if strings.Contains(string(raw), forbidden) { + t.Fatalf("forbidden V1/backend field leaked: %q", forbidden) + } + } +} diff --git a/internal/explorer/authoringv2/types.go b/internal/explorer/authoringv2/types.go new file mode 100644 index 00000000..57e34989 --- /dev/null +++ b/internal/explorer/authoringv2/types.go @@ -0,0 +1,678 @@ +// Package authoringv2 contains the hard-cut Explorer Builder authoring +// protocol. It is deliberately separate from the V1 HTTP and persistence +// contracts: this package describes user intent and catalog facts only. +package authoringv2 + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "sort" + "strings" +) + +const ( + APIVersion = "loom.calypr.org/explorer-authoring/v2" + Kind = "ExplorerBuilderDocument" + StateKind = "ExplorerBuilderState" + CatalogKind = "ExplorerBuilderCatalog" + AuthoringV2APIVersion = APIVersion + ExplorerBuilderV2Kind = Kind + ExplorerBuilderStateV2Kind = StateKind + ExplorerBuilderCatalogV2Kind = CatalogKind + RootOccurrenceID = "base" +) + +// Versioned aliases keep call sites explicit while retaining concise domain +// names inside this package. +type AuthoringDocumentV2 = Document +type ExplorerBuilderDocumentV2 = Document +type BuilderStateV2 = BuilderState +type ExplorerBuilderStateV2 = BuilderState +type CatalogProjectionV2 = CatalogSnapshot +type ExplorerBuilderCatalogV2 = CatalogSnapshot +type RoutePolicyV2 = RoutePolicy +type RouteStepV2 = RouteStep +type SelectionV2 = Selection +type OutputV2 = Output +type PresentationV2 = Presentation +type CatalogNodeV2 = CatalogNode +type CatalogEdgeV2 = CatalogEdge +type CatalogCandidateV2 = CatalogCandidate + +// Document is the complete durable Builder intent. A route is a finite edge +// path from RootNodeID. Its root occurrence is always "base" and its tail is +// computed from the path; neither is a second authored node identity. +type Document struct { + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Output Output `json:"output"` + RootNodeID string `json:"rootNodeId"` + RouteSteps []RouteStep `json:"routeSteps"` + Selections []Selection `json:"selections"` + Presentation map[string]Presentation `json:"presentation"` +} + +type Output struct { + ID string `json:"id"` + Title string `json:"title"` +} + +type RouteStep struct { + EdgeID string `json:"edgeId"` + OccurrenceID string `json:"occurrenceId,omitempty"` +} + +type Selection struct { + CandidateID string `json:"candidateId"` + OccurrenceID string `json:"occurrenceId,omitempty"` + ProjectionMode string `json:"projectionMode"` +} + +// Presentation contains display intent only. In particular, it has no +// selector, expression, physical collection, or generated-column fields. +type Presentation struct { + Label string `json:"label,omitempty"` + Visible *bool `json:"visible,omitempty"` + Order *int `json:"order,omitempty"` +} + +// CatalogSnapshot is an immutable, authorization-scoped projection. The +// token identifies the exact snapshot used to validate a document. +type CatalogSnapshot struct { + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + SourceGeneration string `json:"sourceGeneration"` + AuthorizationScopeDigest string `json:"authorizationScopeDigest"` + ResolvedSchemaDigest string `json:"resolvedSchemaDigest,omitempty"` + SnapshotToken string `json:"snapshotToken"` + Complete bool `json:"complete"` + Truncated bool `json:"truncated"` + Diagnostics []CatalogDiagnostic `json:"diagnostics"` + Nodes []CatalogNode `json:"nodes"` + Edges []CatalogEdge `json:"edges"` + Candidates []CatalogCandidate `json:"candidates"` + RoutePolicy RoutePolicy `json:"routePolicy"` +} + +type CatalogDiagnostic struct { + Severity string `json:"severity"` + Code string `json:"code"` + Message string `json:"message"` +} + +type CatalogNode struct { + ID string `json:"nodeId"` + ResourceType string `json:"resourceType"` + RowRootEligible bool `json:"rowRootEligible"` + RowGrain string `json:"rowGrain,omitempty"` + Populated bool `json:"populated"` + DocumentCount *int64 `json:"documentCount,omitempty"` +} + +type CatalogEdge struct { + ID string `json:"edgeId"` + FromNodeID string `json:"fromNodeId"` + ToNodeID string `json:"toNodeId"` + Label string `json:"label"` +} + +type CatalogCandidate struct { + ID string `json:"candidateId"` + NodeID string `json:"nodeId"` + Label string `json:"label"` + LogicalType string `json:"logicalType"` + Filterable bool `json:"filterable"` + Chartable bool `json:"chartable"` + ProjectionModes []string `json:"projectionModes"` + DefaultProjectionMode string `json:"defaultProjectionMode"` + FilterOperators []string `json:"filterOperators"` + ChartOperations []string `json:"chartOperations"` + Cardinality string `json:"cardinality,omitempty"` + Populated bool `json:"populated"` + Count *int64 `json:"count,omitempty"` + SuggestionsAvailable bool `json:"suggestionsAvailable"` + SuggestionsComplete bool `json:"suggestionsComplete"` + SuggestionsTruncated bool `json:"suggestionsTruncated"` + SuggestionCount int `json:"suggestionCount"` +} + +// RoutePolicy has no default hop ceiling: nil MaxHops means every finite +// route is valid. Repeated edges and self-loops are explicit capabilities. +type RoutePolicy struct { + MaxHops *int `json:"maxHops,omitempty"` + Unbounded bool `json:"unbounded"` + AllowRepeatedEdges bool `json:"allowRepeatedEdges"` + AllowSelfLoops bool `json:"allowSelfLoops"` +} + +// BuilderState joins one document to the one catalog snapshot that proves it. +type BuilderState struct { + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Document *Document `json:"document,omitempty"` + Catalog CatalogSnapshot `json:"catalog"` +} + +// RouteOccurrence is derived, never wire-authored. The first occurrence has +// ID "base". Unnamed route steps receive stable step-N IDs; TailOccurrence +// returns the final derived occurrence (base for an empty route). +type RouteOccurrence struct { + ID string + NodeID string + IncomingEdgeID string +} + +func (d Document) Occurrences(c CatalogSnapshot) ([]RouteOccurrence, error) { + if err := d.Validate(); err != nil { + return nil, err + } + edges := c.edgeIndex() + current := d.RootNodeID + occ := []RouteOccurrence{{ID: RootOccurrenceID, NodeID: current}} + for i, step := range d.RouteSteps { + e := edges[step.EdgeID] + if e == nil { + return nil, fmt.Errorf("route step %d references unknown edge %q", i, step.EdgeID) + } + if e.FromNodeID != current { + return nil, fmt.Errorf("route step %d is disconnected: edge starts at %q, expected %q", i, e.FromNodeID, current) + } + id := step.OccurrenceID + if id == "" { + id = DerivedOccurrenceID(i) + } + occ = append(occ, RouteOccurrence{ID: id, NodeID: e.ToNodeID, IncomingEdgeID: e.ID}) + current = e.ToNodeID + } + return occ, nil +} + +func (d Document) TailOccurrence(c CatalogSnapshot) (RouteOccurrence, error) { + occ, err := d.Occurrences(c) + if err != nil { + return RouteOccurrence{}, err + } + return occ[len(occ)-1], nil +} + +func (d Document) TailOccurrenceID(c CatalogSnapshot) (string, error) { + tail, err := d.TailOccurrence(c) + if err != nil { + return "", err + } + return tail.ID, nil +} + +func DerivedOccurrenceID(stepIndex int) string { + return fmt.Sprintf("step-%d", stepIndex+1) +} + +func (d Document) Validate() error { + if d.APIVersion != APIVersion || d.Kind != Kind { + return fmt.Errorf("unsupported V2 document protocol or kind") + } + if emptyID(d.Output.ID) || strings.TrimSpace(d.Output.Title) == "" { + return fmt.Errorf("output id and title are required") + } + if emptyID(d.RootNodeID) { + return fmt.Errorf("rootNodeId is required") + } + seenOccurrences := map[string]bool{RootOccurrenceID: true} + for i, step := range d.RouteSteps { + if emptyID(step.EdgeID) { + return fmt.Errorf("routeSteps[%d].edgeId is required", i) + } + if step.OccurrenceID != "" { + if step.OccurrenceID == RootOccurrenceID { + return fmt.Errorf("routeSteps[%d] cannot author the derived base occurrence", i) + } + if emptyID(step.OccurrenceID) { + return fmt.Errorf("routeSteps[%d].occurrenceId is invalid", i) + } + if seenOccurrences[step.OccurrenceID] { + return fmt.Errorf("duplicate route occurrence id %q", step.OccurrenceID) + } + seenOccurrences[step.OccurrenceID] = true + } + } + seenSelections := map[string]bool{} + for i, selection := range d.Selections { + if emptyID(selection.CandidateID) { + return fmt.Errorf("selections[%d].candidateId is required", i) + } + if strings.TrimSpace(selection.ProjectionMode) == "" { + return fmt.Errorf("selections[%d].projectionMode is required", i) + } + if selection.OccurrenceID == "base" && selection.OccurrenceID != "" { /* base is valid */ + } + if selection.OccurrenceID != "" && emptyID(selection.OccurrenceID) { + return fmt.Errorf("selections[%d].occurrenceId is invalid", i) + } + key := selection.CandidateID + "\x00" + selection.OccurrenceID + if seenSelections[key] { + return fmt.Errorf("duplicate selection %q", selection.CandidateID) + } + seenSelections[key] = true + } + for key, p := range d.Presentation { + if emptyID(key) { + return fmt.Errorf("presentation keys must be non-empty IDs") + } + if p.Order != nil && *p.Order < 0 { + return fmt.Errorf("presentation[%q].order must not be negative", key) + } + } + return nil +} + +func (c CatalogSnapshot) Validate() error { + if c.APIVersion != APIVersion || c.Kind != CatalogKind { + return fmt.Errorf("unsupported V2 catalog protocol or kind") + } + if strings.TrimSpace(c.SnapshotToken) == "" { + return fmt.Errorf("catalog snapshotToken is required") + } + if strings.TrimSpace(c.Project) == "" || strings.TrimSpace(c.ExplorerID) == "" || strings.TrimSpace(c.SourceGeneration) == "" || strings.TrimSpace(c.AuthorizationScopeDigest) == "" { + return fmt.Errorf("catalog project, explorerId, sourceGeneration, and authorizationScopeDigest are required") + } + if !c.Complete || c.Truncated { + return fmt.Errorf("catalog snapshot is incomplete or truncated") + } + if c.RoutePolicy.MaxHops != nil && *c.RoutePolicy.MaxHops < 0 { + return fmt.Errorf("routePolicy.maxHops must not be negative") + } + if c.RoutePolicy.MaxHops == nil && !c.RoutePolicy.Unbounded { + return fmt.Errorf("routePolicy must explicitly declare an unbounded route when maxHops is absent") + } + if c.RoutePolicy.MaxHops != nil && c.RoutePolicy.Unbounded { + return fmt.Errorf("routePolicy cannot be both bounded and unbounded") + } + nodes := map[string]CatalogNode{} + for i, n := range c.Nodes { + if emptyID(n.ID) || strings.TrimSpace(n.ResourceType) == "" { + return fmt.Errorf("nodes[%d] is invalid", i) + } + if _, ok := nodes[n.ID]; ok { + return fmt.Errorf("duplicate catalog node %q", n.ID) + } + nodes[n.ID] = n + } + edges := map[string]CatalogEdge{} + for i, e := range c.Edges { + if emptyID(e.ID) || nodes[e.FromNodeID].ID == "" || nodes[e.ToNodeID].ID == "" { + return fmt.Errorf("edges[%d] has stale node reference", i) + } + if _, ok := edges[e.ID]; ok { + return fmt.Errorf("duplicate catalog edge %q", e.ID) + } + if e.FromNodeID == e.ToNodeID && !c.RoutePolicy.AllowSelfLoops { + return fmt.Errorf("self-loop edge %q is not allowed by route policy", e.ID) + } + edges[e.ID] = e + } + candidates := map[string]CatalogCandidate{} + for i, candidate := range c.Candidates { + if emptyID(candidate.ID) || nodes[candidate.NodeID].ID == "" { + return fmt.Errorf("candidates[%d] has stale node reference", i) + } + if _, ok := candidates[candidate.ID]; ok { + return fmt.Errorf("duplicate catalog candidate %q", candidate.ID) + } + if len(candidate.ProjectionModes) == 0 || candidate.DefaultProjectionMode == "" { + return fmt.Errorf("candidate %q must advertise projection modes and a default", candidate.ID) + } + if candidate.DefaultProjectionMode != "" { + foundMode := false + for _, mode := range candidate.ProjectionModes { + if strings.TrimSpace(mode) == "" { + return fmt.Errorf("candidates[%d] contains an empty projection mode", i) + } + if mode == candidate.DefaultProjectionMode { + foundMode = true + } + } + if len(candidate.ProjectionModes) > 0 && !foundMode { + return fmt.Errorf("candidate %q default projection mode is not listed", candidate.ID) + } + } + if candidate.Count != nil && *candidate.Count < 0 { + return fmt.Errorf("candidate %q count must not be negative", candidate.ID) + } + if candidate.SuggestionCount < 0 { + return fmt.Errorf("candidate %q suggestionCount must not be negative", candidate.ID) + } + if candidate.SuggestionsComplete && candidate.SuggestionsTruncated { + return fmt.Errorf("candidate %q suggestions cannot be complete and truncated", candidate.ID) + } + candidates[candidate.ID] = candidate + } + return nil +} + +func (s BuilderState) Validate() error { + if s.APIVersion != APIVersion || s.Kind != StateKind { + return fmt.Errorf("unsupported V2 builder state protocol or kind") + } + if err := s.Catalog.Validate(); err != nil { + return err + } + if s.Document == nil { + return nil + } + if err := s.Document.Validate(); err != nil { + return err + } + edges, candidates, nodes := s.Catalog.edgeIndex(), s.Catalog.candidateIndex(), s.Catalog.nodeIndex() + if nodes[s.Document.RootNodeID].ID == "" { + return fmt.Errorf("document rootNodeId %q is stale", s.Document.RootNodeID) + } + seenEdges := map[string]bool{} + current := s.Document.RootNodeID + for i, step := range s.Document.RouteSteps { + e, ok := edges[step.EdgeID] + if !ok { + return fmt.Errorf("routeSteps[%d] references stale edge %q", i, step.EdgeID) + } + if e.FromNodeID != current { + return fmt.Errorf("routeSteps[%d] is disconnected: edge starts at %q, expected %q", i, e.FromNodeID, current) + } + if seenEdges[e.ID] && !s.Catalog.RoutePolicy.AllowRepeatedEdges { + return fmt.Errorf("repeated edge %q is not allowed by route policy", e.ID) + } + seenEdges[e.ID] = true + current = e.ToNodeID + } + if s.Catalog.RoutePolicy.MaxHops != nil && len(s.Document.RouteSteps) > *s.Catalog.RoutePolicy.MaxHops { + return fmt.Errorf("route exceeds routePolicy.maxHops") + } + occ, err := s.Document.Occurrences(s.Catalog) + if err != nil { + return err + } + occByID := map[string]RouteOccurrence{} + for _, item := range occ { + occByID[item.ID] = item + } + for i, selection := range s.Document.Selections { + candidate, ok := candidates[selection.CandidateID] + if !ok { + return fmt.Errorf("selections[%d] references stale candidate %q", i, selection.CandidateID) + } + id := selection.OccurrenceID + if id == "" { + id = occ[len(occ)-1].ID + } + item, ok := occByID[id] + if !ok { + return fmt.Errorf("selections[%d] references stale occurrence %q", i, id) + } + if candidate.NodeID != item.NodeID { + return fmt.Errorf("selection %q belongs to node %q, not occurrence %q node %q", selection.CandidateID, candidate.NodeID, id, item.NodeID) + } + projectionAllowed := false + for _, mode := range candidate.ProjectionModes { + if selection.ProjectionMode == mode { + projectionAllowed = true + break + } + } + if !projectionAllowed { + return fmt.Errorf("selection %q projection mode %q is not advertised", selection.CandidateID, selection.ProjectionMode) + } + } + return nil +} + +func (c CatalogSnapshot) nodeIndex() map[string]CatalogNode { + out := map[string]CatalogNode{} + for _, n := range c.Nodes { + out[n.ID] = n + } + return out +} +func (c CatalogSnapshot) edgeIndex() map[string]*CatalogEdge { + out := map[string]*CatalogEdge{} + for i := range c.Edges { + out[c.Edges[i].ID] = &c.Edges[i] + } + return out +} +func (c CatalogSnapshot) candidateIndex() map[string]CatalogCandidate { + out := map[string]CatalogCandidate{} + for _, n := range c.Candidates { + out[n.ID] = n + } + return out +} + +func emptyID(value string) bool { + return strings.TrimSpace(value) == "" || value != strings.TrimSpace(value) +} + +// CanonicalJSON and Digest provide content-addressed, deterministic wire +// representations. Catalog collections and unordered selections are sorted; +// routeSteps retain their authored path order. +func (d Document) CanonicalJSON() ([]byte, error) { + if err := d.Validate(); err != nil { + return nil, err + } + n := d + n.RouteSteps = append([]RouteStep(nil), d.RouteSteps...) + n.Selections = append([]Selection(nil), d.Selections...) + sort.SliceStable(n.Selections, func(i, j int) bool { + left := n.Selections[i].CandidateID + "\x00" + n.Selections[i].OccurrenceID + right := n.Selections[j].CandidateID + "\x00" + n.Selections[j].OccurrenceID + return left < right + }) + if n.RouteSteps == nil { + n.RouteSteps = []RouteStep{} + } + if n.Selections == nil { + n.Selections = []Selection{} + } + if n.Presentation == nil { + n.Presentation = map[string]Presentation{} + } + return json.Marshal(n) +} + +func (d Document) Digest() (string, error) { + raw, err := d.CanonicalJSON() + if err != nil { + return "", err + } + sum := sha256.Sum256(raw) + return "sha256:" + hex.EncodeToString(sum[:]), nil +} + +func (c CatalogSnapshot) CanonicalJSON() ([]byte, error) { + if err := c.Validate(); err != nil { + return nil, err + } + n := c + n.Nodes = append([]CatalogNode(nil), c.Nodes...) + n.Edges = append([]CatalogEdge(nil), c.Edges...) + n.Candidates = append([]CatalogCandidate(nil), c.Candidates...) + n.Diagnostics = append([]CatalogDiagnostic(nil), c.Diagnostics...) + for i := range n.Candidates { + n.Candidates[i].ProjectionModes = append([]string(nil), n.Candidates[i].ProjectionModes...) + n.Candidates[i].FilterOperators = append([]string(nil), n.Candidates[i].FilterOperators...) + n.Candidates[i].ChartOperations = append([]string(nil), n.Candidates[i].ChartOperations...) + sort.Strings(n.Candidates[i].ProjectionModes) + sort.Strings(n.Candidates[i].FilterOperators) + sort.Strings(n.Candidates[i].ChartOperations) + } + sort.Slice(n.Nodes, func(i, j int) bool { return n.Nodes[i].ID < n.Nodes[j].ID }) + sort.Slice(n.Edges, func(i, j int) bool { return n.Edges[i].ID < n.Edges[j].ID }) + sort.Slice(n.Candidates, func(i, j int) bool { return n.Candidates[i].ID < n.Candidates[j].ID }) + sort.Slice(n.Diagnostics, func(i, j int) bool { + if n.Diagnostics[i].Code != n.Diagnostics[j].Code { + return n.Diagnostics[i].Code < n.Diagnostics[j].Code + } + return n.Diagnostics[i].Message < n.Diagnostics[j].Message + }) + return json.Marshal(n) +} + +func (c CatalogSnapshot) Digest() (string, error) { + raw, err := c.CanonicalJSON() + if err != nil { + return "", err + } + sum := sha256.Sum256(raw) + return "sha256:" + hex.EncodeToString(sum[:]), nil +} + +func (s BuilderState) CanonicalJSON() ([]byte, error) { + if err := s.Validate(); err != nil { + return nil, err + } + var document []byte + var err error + if s.Document == nil { + document = []byte("null") + } else { + document, err = s.Document.CanonicalJSON() + if err != nil { + return nil, err + } + } + catalog, err := s.Catalog.CanonicalJSON() + if err != nil { + return nil, err + } + return json.Marshal(struct { + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Document json.RawMessage `json:"document"` + Catalog json.RawMessage `json:"catalog"` + }{s.APIVersion, s.Kind, document, catalog}) +} + +func (s BuilderState) Digest() (string, error) { + raw, err := s.CanonicalJSON() + if err != nil { + return "", err + } + sum := sha256.Sum256(raw) + return "sha256:" + hex.EncodeToString(sum[:]), nil +} + +func DecodeDocument(raw []byte) (Document, error) { + var out Document + if err := strictDecode(raw, &out); err != nil { + return out, err + } + if err := out.Validate(); err != nil { + return out, err + } + return out, nil +} + +func DecodeExplorerBuilderDocumentV2(raw []byte) (ExplorerBuilderDocumentV2, error) { + return DecodeDocument(raw) +} +func DecodeCatalog(raw []byte) (CatalogSnapshot, error) { + var out CatalogSnapshot + if err := strictDecode(raw, &out); err != nil { + return out, err + } + if err := out.Validate(); err != nil { + return out, err + } + return out, nil +} + +func DecodeExplorerBuilderCatalogV2(raw []byte) (ExplorerBuilderCatalogV2, error) { + return DecodeCatalog(raw) +} +func DecodeBuilderState(raw []byte) (BuilderState, error) { + var out BuilderState + if err := strictDecode(raw, &out); err != nil { + return out, err + } + if err := out.Validate(); err != nil { + return out, err + } + return out, nil +} + +func DecodeExplorerBuilderStateV2(raw []byte) (ExplorerBuilderStateV2, error) { + return DecodeBuilderState(raw) +} + +func strictDecode(raw []byte, target any) error { + if err := rejectDuplicateKeys(raw); err != nil { + return fmt.Errorf("strict decode: %w", err) + } + dec := json.NewDecoder(bytes.NewReader(raw)) + dec.DisallowUnknownFields() + if err := dec.Decode(target); err != nil { + return fmt.Errorf("strict decode: %w", err) + } + var trailing any + if err := dec.Decode(&trailing); err != io.EOF { + if err == nil { + return fmt.Errorf("strict decode: trailing JSON value") + } + return fmt.Errorf("strict decode: %w", err) + } + return nil +} + +func rejectDuplicateKeys(raw []byte) error { + dec := json.NewDecoder(bytes.NewReader(raw)) + var walk func() error + walk = func() error { + tok, err := dec.Token() + if err != nil { + return err + } + delim, ok := tok.(json.Delim) + if !ok { + return nil + } + switch delim { + case '{': + seen := map[string]bool{} + for dec.More() { + key, err := dec.Token() + if err != nil { + return err + } + name, ok := key.(string) + if !ok { + return fmt.Errorf("object key is not a string") + } + if seen[name] { + return fmt.Errorf("duplicate JSON key %q", name) + } + seen[name] = true + if err := walk(); err != nil { + return err + } + } + _, err = dec.Token() + return err + case '[': + for dec.More() { + if err := walk(); err != nil { + return err + } + } + _, err = dec.Token() + return err + } + return nil + } + if err := walk(); err != nil { + return err + } + return nil +} diff --git a/internal/explorer/authoringv2/types_test.go b/internal/explorer/authoringv2/types_test.go new file mode 100644 index 00000000..b5ef3f31 --- /dev/null +++ b/internal/explorer/authoringv2/types_test.go @@ -0,0 +1,132 @@ +package authoringv2 + +import ( + "strings" + "testing" +) + +func testCatalog() CatalogSnapshot { + nodes := []CatalogNode{ + {ID: "patient", ResourceType: "Patient"}, + {ID: "encounter", ResourceType: "Encounter"}, + } + edges := []CatalogEdge{ + {ID: "patient-encounter", FromNodeID: "patient", ToNodeID: "encounter", Label: "encounters"}, + {ID: "encounter-self", FromNodeID: "encounter", ToNodeID: "encounter", Label: "revisits"}, + } + return CatalogSnapshot{ + APIVersion: APIVersion, Kind: CatalogKind, Project: "p", ExplorerID: "e", + SourceGeneration: "g", AuthorizationScopeDigest: "scope", SnapshotToken: "sha256:snapshot", + Complete: true, Nodes: nodes, Edges: edges, + Candidates: []CatalogCandidate{ + {ID: "patient-id", NodeID: "patient", Label: "ID", LogicalType: "string", ProjectionModes: []string{"SCALAR"}, DefaultProjectionMode: "SCALAR"}, + {ID: "encounter-id", NodeID: "encounter", Label: "ID", LogicalType: "string", ProjectionModes: []string{"SCALAR"}, DefaultProjectionMode: "SCALAR"}, + }, + RoutePolicy: RoutePolicy{Unbounded: true, AllowRepeatedEdges: true, AllowSelfLoops: true}, + } +} + +func testDocument() Document { + return Document{ + APIVersion: APIVersion, Kind: Kind, Output: Output{ID: "out", Title: "Patients"}, RootNodeID: "patient", + RouteSteps: []RouteStep{{EdgeID: "patient-encounter", OccurrenceID: "first"}, {EdgeID: "encounter-self", OccurrenceID: "second"}, {EdgeID: "encounter-self", OccurrenceID: "third"}}, + Selections: []Selection{{CandidateID: "patient-id", OccurrenceID: "base", ProjectionMode: "SCALAR"}, {CandidateID: "encounter-id", OccurrenceID: "third", ProjectionMode: "SCALAR"}}, + Presentation: map[string]Presentation{"patient-id": {Label: "Patient ID"}}, + } +} + +func TestBuilderStateSupportsRepeatedOccurrencesSelfLoopsAndLongFiniteRoutes(t *testing.T) { + catalog := testCatalog() + document := testDocument() + for i := 4; i < 12; i++ { + document.RouteSteps = append(document.RouteSteps, RouteStep{EdgeID: "encounter-self", OccurrenceID: "step-explicit-" + string(rune('a'+i))}) + } + state := BuilderState{APIVersion: APIVersion, Kind: StateKind, Document: &document, Catalog: catalog} + if err := state.Validate(); err != nil { + t.Fatal(err) + } + tail, err := document.TailOccurrence(catalog) + if err != nil || tail.ID != "step-explicit-l" { + t.Fatalf("tail=%#v err=%v", tail, err) + } +} + +func TestBuilderStateRejectsStaleAndDuplicateStructure(t *testing.T) { + catalog := testCatalog() + document := testDocument() + document.RouteSteps = append(document.RouteSteps, RouteStep{EdgeID: "missing"}) + state := BuilderState{APIVersion: APIVersion, Kind: StateKind, Document: &document, Catalog: catalog} + if err := state.Validate(); err == nil || !strings.Contains(err.Error(), "stale edge") { + t.Fatalf("stale edge error=%v", err) + } + document = testDocument() + document.Selections = append(document.Selections, document.Selections[0]) + if err := document.Validate(); err == nil || !strings.Contains(err.Error(), "duplicate selection") { + t.Fatalf("duplicate selection error=%v", err) + } + catalog.Edges = append(catalog.Edges, catalog.Edges[0]) + if err := catalog.Validate(); err == nil || !strings.Contains(err.Error(), "duplicate catalog edge") { + t.Fatalf("duplicate edge error=%v", err) + } +} + +func TestStrictV2DecodeRejectsUnknownDuplicateAndTrailingFields(t *testing.T) { + raw := `{"apiVersion":"` + APIVersion + `","kind":"ExplorerBuilderDocument","output":{"id":"out","title":"Title"},"rootNodeId":"patient","routeSteps":[],"selections":[],"presentation":{},"aql":"for x in c return x"}` + if _, err := DecodeDocument([]byte(raw)); err == nil || !strings.Contains(err.Error(), "unknown field") { + t.Fatalf("unknown field error=%v", err) + } + raw = strings.Replace(raw, `,"aql":"for x in c return x"`, `,"presentation":{},"presentation":{}`, 1) + if _, err := DecodeDocument([]byte(raw)); err == nil || !strings.Contains(err.Error(), "duplicate JSON key") { + t.Fatalf("duplicate field error=%v", err) + } + valid := `{"apiVersion":"` + APIVersion + `","kind":"ExplorerBuilderDocument","output":{"id":"out","title":"Title"},"rootNodeId":"patient","routeSteps":[],"selections":[],"presentation":{}} {}` + if _, err := DecodeDocument([]byte(valid)); err == nil || !strings.Contains(err.Error(), "trailing JSON") { + t.Fatalf("trailing value error=%v", err) + } +} + +func TestCanonicalizationAndDigestAreStableAcrossUnorderedCollections(t *testing.T) { + first := testDocument() + second := testDocument() + first.Selections = []Selection{first.Selections[1], first.Selections[0]} + second.Presentation = map[string]Presentation{"patient-id": {Label: "Patient ID"}} + first.Presentation = map[string]Presentation{"patient-id": {Label: "Patient ID"}} + a, err := first.CanonicalJSON() + if err != nil { + t.Fatal(err) + } + b, err := second.CanonicalJSON() + if err != nil { + t.Fatal(err) + } + if string(a) != string(b) { + t.Fatalf("canonical JSON differs:\n%s\n%s", a, b) + } + da, err := first.Digest() + if err != nil { + t.Fatal(err) + } + db, err := second.Digest() + if err != nil { + t.Fatal(err) + } + if da != db || !strings.HasPrefix(da, "sha256:") { + t.Fatalf("digests=%q,%q", da, db) + } +} + +func TestEmptyBuilderStateAndBackendLeakage(t *testing.T) { + state := BuilderState{APIVersion: APIVersion, Kind: StateKind, Catalog: testCatalog()} + if err := state.Validate(); err != nil { + t.Fatal(err) + } + raw, err := state.CanonicalJSON() + if err != nil { + t.Fatal(err) + } + for _, forbidden := range []string{"rowNodeId", "selector", "aql", "physicalCollection", "backend"} { + if strings.Contains(string(raw), forbidden) { + t.Fatalf("backend field leaked: %q in %s", forbidden, raw) + } + } +} diff --git a/internal/explorer/bootstrap/bootstrap.go b/internal/explorer/bootstrap/bootstrap.go new file mode 100644 index 00000000..039c9b64 --- /dev/null +++ b/internal/explorer/bootstrap/bootstrap.go @@ -0,0 +1,353 @@ +// Package bootstrap contains the offline/admin-only conversion from the +// legacy repository default recipe/config to the V1 intent contract. Nothing +// in this package has a runtime store dependency. +package bootstrap + +import ( + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "sort" + "strings" + + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/explorer" +) + +type Mapping struct { + LegacyPath string `json:"legacyPath"` + LegacyFieldName string `json:"legacyFieldName,omitempty"` + OutputID string `json:"outputId"` + CandidateID string `json:"candidateId"` + OccurrenceID string `json:"occurrenceId"` + EmissionID string `json:"emissionId"` +} + +type Report struct { + Equivalent bool `json:"equivalent"` + LegacyRecipeDigest string `json:"legacyRecipeDigest"` + AuthoringDocumentDigest string `json:"authoringDocumentDigest"` + Mappings []Mapping `json:"mappings"` + Unmapped []string `json:"unmapped,omitempty"` + Ambiguous []string `json:"ambiguous,omitempty"` +} + +type ConversionError struct{ Report Report } + +func (e *ConversionError) Error() string { return "legacy default conversion is not exact" } + +// ConvertDefault converts every legacy recipe output into one V1 builder +// document and converts each legacy view into an ordered V1 tab. Recipe +// operations that cannot be represented by V1 intent are rejected; no field is +// guessed or silently dropped. +func ConvertDefault(rawConfig []byte, catalog explorer.Catalog, project string) (explorer.ExplorerAuthoringBundleV1, Report, error) { + cfg, legacy, err := explorer.DecodeDefaultConfigV2(rawConfig, project) + if err != nil { + return explorer.ExplorerAuthoringBundleV1{}, Report{}, fmt.Errorf("decode legacy default: %w", err) + } + report := Report{} + report.LegacyRecipeDigest, _ = legacy.Digest() + nodeIDs, err := uniqueNodeIDs(catalog) + if err != nil { + report.Ambiguous = append(report.Ambiguous, "catalog.nodes") + return explorer.ExplorerAuthoringBundleV1{}, report, &ConversionError{Report: report} + } + documents := make([]explorer.ExplorerBuilderDocumentV1, 0, len(legacy.Outputs)) + documentByLegacyOutput := make(map[string]int, len(legacy.Outputs)) + allMappings := make([]Mapping, 0) + for outputIndex, output := range legacy.Outputs { + document, mappings, conversionErr := convertOutput(cfg, output, outputIndex, catalog, nodeIDs, &report) + if conversionErr != nil { + return explorer.ExplorerAuthoringBundleV1{}, report, conversionErr + } + documentByLegacyOutput[output.Name] = len(documents) + documents = append(documents, document) + allMappings = append(allMappings, mappings...) + } + if err := mapPresentation(cfg, documentByLegacyOutput, documents, allMappings, &report); err != nil { + return explorer.ExplorerAuthoringBundleV1{}, report, err + } + tabs := make([]explorer.ExplorerTabV1, 0, len(cfg.Views)) + for index, view := range cfg.Views { + documentIndex, ok := documentByLegacyOutput[view.Output] + if !ok { + report.Unmapped = append(report.Unmapped, fmt.Sprintf("views[%d].output", index)) + return explorer.ExplorerAuthoringBundleV1{}, report, &ConversionError{Report: report} + } + tabs = append(tabs, explorer.ExplorerTabV1{ID: explorer.StableExplorerID(view.ID), Title: view.Title, OutputID: documents[documentIndex].Output.ID, Order: index}) + } + for i := range documents { + sort.Strings(documents[i].CandidateIDs) + } + bundle := explorer.ExplorerAuthoringBundleV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, Project: project, ExplorerID: "default", Title: cfg.Explorer.Title, Tabs: tabs} + if len(documents) == 1 { + // Keep the in-memory compatibility field populated for callers that have + // not yet moved to the canonical multi-document representation. + bundle.Document = documents[0] + } else { + bundle.Documents = documents + } + bundle.IntentDigest, err = bundle.DocumentDigest() + if err != nil { + return explorer.ExplorerAuthoringBundleV1{}, report, err + } + report.AuthoringDocumentDigest = bundle.IntentDigest + report.Equivalent = len(report.Unmapped) == 0 && len(report.Ambiguous) == 0 + if !report.Equivalent { + return explorer.ExplorerAuthoringBundleV1{}, report, &ConversionError{Report: report} + } + return bundle, report, nil +} + +func convertOutput(cfg explorer.ConfigV2, output recipe.Output, outputIndex int, catalog explorer.Catalog, nodeIDs map[string]string, report *Report) (explorer.ExplorerBuilderDocumentV1, []Mapping, error) { + baseNode, ok := nodeIDs[output.RootResourceType] + if !ok { + report.Unmapped = append(report.Unmapped, fmt.Sprintf("outputs[%d].rootResourceType", outputIndex)) + return explorer.ExplorerBuilderDocumentV1{}, nil, &ConversionError{Report: *report} + } + document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: explorer.StableExplorerID(output.Name), Title: titleForOutput(cfg, output.Name)}, BaseNodeID: baseNode, RowNodeID: baseNode, Presentation: map[string]explorer.ExplorerPresentationBindingV1{}} + currentNode := baseNode + mappingsBefore := len(report.Mappings) + var walkTraversals func([]recipe.Traversal, string, string, int) error + walkTraversals = func(traversals []recipe.Traversal, parentNode, parentOccurrence string, depth int) error { + if len(traversals) > 1 { + report.Ambiguous = append(report.Ambiguous, fmt.Sprintf("traversal[%d]", depth)) + return &ConversionError{Report: *report} + } + for index, traversal := range traversals { + if len(traversal.Traversals) > 1 { + report.Ambiguous = append(report.Ambiguous, fmt.Sprintf("traversal[%d].traversals", depth)) + return &ConversionError{Report: *report} + } + childNode, edgeID, err := exactEdge(catalog, parentNode, traversal.Name, traversal.ToResourceType) + if err != nil { + report.Ambiguous = append(report.Ambiguous, fmt.Sprintf("traversal[%d]", depth)) + return &ConversionError{Report: *report} + } + occurrenceID := fmt.Sprintf("route_%d", len(document.RouteEdgeIDs)) + document.RouteEdgeIDs = append(document.RouteEdgeIDs, edgeID) + document.RouteOccurrences = append(document.RouteOccurrences, explorer.ExplorerRouteOccurrenceV1{ID: occurrenceID, Index: len(document.RouteEdgeIDs) - 1, NodeID: childNode, IncomingEdgeID: edgeID}) + if err := mapFields(traversal.Fields, childNode, occurrenceID, traversalPath(parentOccurrence, index), catalog, &document, report); err != nil { + return err + } + if err := walkTraversals(traversal.Traversals, childNode, occurrenceID, depth+1); err != nil { + return err + } + currentNode = childNode + } + return nil + } + if err := mapFields(output.Fields, baseNode, "base", fmt.Sprintf("outputs[%d]", outputIndex), catalog, &document, report); err != nil { + return explorer.ExplorerBuilderDocumentV1{}, nil, err + } + if err := walkTraversals(output.Traversals, baseNode, "root", 0); err != nil { + return explorer.ExplorerBuilderDocumentV1{}, nil, err + } + document.RowNodeID = currentNode + for i := mappingsBefore; i < len(report.Mappings); i++ { + report.Mappings[i].OutputID = document.Output.ID + } + return document, append([]Mapping(nil), report.Mappings[mappingsBefore:]...), nil +} + +func uniqueNodeIDs(catalog explorer.Catalog) (map[string]string, error) { + out := map[string]string{} + for _, node := range catalog.Nodes { + if old, ok := out[node.ResourceType]; ok && old != node.ID { + return nil, fmt.Errorf("resource type %q has multiple node IDs", node.ResourceType) + } + out[node.ResourceType] = node.ID + } + return out, nil +} +func exactEdge(catalog explorer.Catalog, parentNode, label, childType string) (string, string, error) { + var child, edge string + for _, candidate := range catalog.Edges { + fromMatches := candidate.FromNodeID == parentNode + toMatches := candidate.ToNodeID == parentNode + other := "" + if fromMatches { + other = candidate.ToNodeID + } + if toMatches { + other = candidate.FromNodeID + } + if (fromMatches || toMatches) && candidate.Label == label { + node, ok := catalogNodeByID(catalog, other) + if !ok || node.ResourceType != childType { + continue + } + if child != "" { + return "", "", fmt.Errorf("ambiguous edge") + } + child, edge = other, candidate.ID + } + } + if edge == "" { + return "", "", fmt.Errorf("unmapped edge") + } + return child, edge, nil +} +func catalogNodeByID(catalog explorer.Catalog, id string) (explorer.CatalogNode, bool) { + for _, node := range catalog.Nodes { + if node.ID == id { + return node, true + } + } + return explorer.CatalogNode{}, false +} + +func mapFields(fields []recipe.Field, nodeID, occurrenceID, path string, catalog explorer.Catalog, document *explorer.ExplorerBuilderDocumentV1, report *Report) error { + for index, field := range fields { + if field.Expr.Select == "" || field.Expr.Call != "" || field.Expr.Literal != nil || field.Expr.Document != nil { + report.Unmapped = append(report.Unmapped, fmt.Sprintf("%s.fields[%d].expr", path, index)) + return &ConversionError{Report: *report} + } + selectPath := strings.TrimSpace(field.Expr.Select) + if dot := strings.IndexByte(selectPath, '.'); dot > 0 { + prefix := selectPath[:dot] + if prefix == "root" || strings.HasPrefix(prefix, "route_") { + selectPath = selectPath[dot+1:] + } + } + matches := []explorer.CatalogSelection{} + for _, selection := range catalog.Selections { + if selection.NodeID != nodeID { + continue + } + if field.FieldRef != "" && selection.FieldRef == field.FieldRef { + matches = append(matches, selection) + continue + } + if field.FieldRef == "" && selection.Select == selectPath { + matches = append(matches, selection) + } + } + if len(matches) != 1 { + if len(matches) == 0 { + report.Unmapped = append(report.Unmapped, fmt.Sprintf("%s.fields[%d]", path, index)) + } else { + report.Ambiguous = append(report.Ambiguous, fmt.Sprintf("%s.fields[%d]", path, index)) + } + return &ConversionError{Report: *report} + } + candidate := matches[0].ID + found := false + for _, old := range document.CandidateIDs { + if old == candidate { + found = true + } + } + if !found { + document.CandidateIDs = append(document.CandidateIDs, candidate) + } + if occurrenceID != "base" { + for _, ref := range document.CandidateOccurrences { + if ref.CandidateID == candidate && ref.OccurrenceID == occurrenceID { + report.Ambiguous = append(report.Ambiguous, fmt.Sprintf("%s.fields[%d]", path, index)) + return &ConversionError{Report: *report} + } + } + document.CandidateOccurrences = append(document.CandidateOccurrences, explorer.ExplorerCandidateOccurrenceV1{CandidateID: candidate, OccurrenceID: occurrenceID}) + } + emissionID := explorer.OpaqueID("em_", document.Output.ID+"\x00"+occurrenceID+"\x00"+candidate) + report.Mappings = append(report.Mappings, Mapping{LegacyPath: fmt.Sprintf("%s.fields[%d]", path, index), LegacyFieldName: field.Name, CandidateID: candidate, OccurrenceID: occurrenceID, EmissionID: emissionID}) + } + return nil +} + +func mapPresentation(cfg explorer.ConfigV2, documentByLegacyOutput map[string]int, documents []explorer.ExplorerBuilderDocumentV1, mappings []Mapping, report *Report) error { + for viewIndex, view := range cfg.Views { + documentIndex, ok := documentByLegacyOutput[view.Output] + if !ok { + report.Unmapped = append(report.Unmapped, fmt.Sprintf("views[%d].output", viewIndex)) + return &ConversionError{Report: *report} + } + document := &documents[documentIndex] + for index, column := range view.Table.Columns { + mapping, ok, ambiguous := findMappingByFieldName(mappings, document.Output.ID, column.Column) + if ambiguous { + report.Ambiguous = append(report.Ambiguous, fmt.Sprintf("views[%s].table.columns[%d]", view.ID, index)) + return &ConversionError{Report: *report} + } + if !ok { + report.Unmapped = append(report.Unmapped, fmt.Sprintf("views[%s].table.columns[%d]", view.ID, index)) + return &ConversionError{Report: *report} + } + binding := document.Presentation[mapping.EmissionID] + binding.Label = firstNonEmpty(column.Label, column.Column) + visible := column.Visible + binding.Visible = &visible + document.Presentation[mapping.EmissionID] = binding + } + for _, filter := range view.Filters { + mapping, ok, ambiguous := findMappingByFieldName(mappings, document.Output.ID, filter.Column) + if ambiguous { + report.Ambiguous = append(report.Ambiguous, "views.filters") + return &ConversionError{Report: *report} + } + if !ok { + report.Unmapped = append(report.Unmapped, "views.filters") + return &ConversionError{Report: *report} + } + binding := document.Presentation[mapping.EmissionID] + if filter.Label != "" { + binding.Filter = &explorer.ExplorerFilterBindingV1{Label: filter.Label} + } + document.Presentation[mapping.EmissionID] = binding + } + for _, chart := range view.Charts { + mapping, ok, ambiguous := findMappingByFieldName(mappings, document.Output.ID, chart.Column) + if ambiguous { + report.Ambiguous = append(report.Ambiguous, "views.charts") + return &ConversionError{Report: *report} + } + if !ok { + report.Unmapped = append(report.Unmapped, "views.charts") + return &ConversionError{Report: *report} + } + binding := document.Presentation[mapping.EmissionID] + binding.Chart = &explorer.ExplorerChartBindingV1{Type: chart.Type, Title: chart.Title} + document.Presentation[mapping.EmissionID] = binding + } + } + return nil +} + +func findMappingByFieldName(mappings []Mapping, outputID, name string) (Mapping, bool, bool) { + var found Mapping + count := 0 + for _, mapping := range mappings { + if mapping.OutputID == outputID && mapping.LegacyFieldName == name { + found = mapping + count++ + } + } + return found, count == 1, count > 1 +} +func titleForOutput(cfg explorer.ConfigV2, output string) string { + for _, view := range cfg.Views { + if view.Output == output { + return view.Title + } + } + return output +} +func firstNonEmpty(values ...string) string { + for _, value := range values { + if strings.TrimSpace(value) != "" { + return value + } + } + return "Explorer" +} +func traversalPath(parent string, index int) string { + return fmt.Sprintf("%s.traversals[%d]", parent, index) +} + +func (r Report) CanonicalJSON() ([]byte, error) { return json.Marshal(r) } +func Digest(raw []byte) string { + sum := sha256.Sum256(raw) + return "sha256:" + hex.EncodeToString(sum[:]) +} diff --git a/internal/explorer/bootstrap/bootstrap_test.go b/internal/explorer/bootstrap/bootstrap_test.go new file mode 100644 index 00000000..6f2260e0 --- /dev/null +++ b/internal/explorer/bootstrap/bootstrap_test.go @@ -0,0 +1,61 @@ +package bootstrap + +import ( + "strings" + "testing" + + "github.com/calypr/loom/internal/explorer" +) + +func TestConvertDefaultIsExactAndProducesIntentOnlyBundle(t *testing.T) { + raw := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Default","management":"repository"},"recipe":{"recipeSchemaVersion":1,"name":"legacy","translationVersion":"v1","outputs":[{"name":"patient","rootResourceType":"Patient","rowGrain":"patient","fields":[{"name":"id","fieldRef":"Patient.id","expr":{"select":"root.id"}}]}]},"views":[{"id":"patient","title":"Patients","output":"patient","table":{"columns":[{"column":"id","label":"Patient ID","visible":true}]}}]}`) + catalog := explorer.Catalog{Nodes: []explorer.CatalogNode{{ID: "n_patient", ResourceType: "Patient"}}, Selections: map[string]explorer.CatalogSelection{"s_patient_id": {ID: "s_patient_id", NodeID: "n_patient", FieldRef: "Patient.id", Select: "id"}}} + bundle, report, err := ConvertDefault(raw, catalog, "project-a") + if err != nil { + t.Fatal(err) + } + if !report.Equivalent || len(report.Mappings) != 1 || len(bundle.Document.CandidateIDs) != 1 { + t.Fatalf("report=%#v bundle=%#v", report, bundle) + } + canonical, err := bundle.CanonicalJSON() + if err != nil { + t.Fatal(err) + } + if strings.Contains(string(canonical), "select") || strings.Contains(string(canonical), "expr") || strings.Contains(string(canonical), "recipe") { + t.Fatalf("legacy recipe leaked into bundle: %s", canonical) + } +} + +func TestConvertDefaultPreservesMultipleOutputsAndTabs(t *testing.T) { + raw := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Default","management":"repository"},"recipe":{"recipeSchemaVersion":1,"name":"legacy","translationVersion":"v1","outputs":[{"name":"patient","rootResourceType":"Patient","rowGrain":"patient","fields":[{"name":"id","fieldRef":"Patient.id","expr":{"select":"root.id"}}]},{"name":"specimen","rootResourceType":"Specimen","rowGrain":"specimen","fields":[{"name":"id","fieldRef":"Specimen.id","expr":{"select":"root.id"}}]}]},"views":[{"id":"patient","title":"Patients","output":"patient","table":{"columns":[{"column":"id","label":"Patient ID","visible":true}]}},{"id":"specimen","title":"Specimens","output":"specimen","table":{"columns":[{"column":"id","label":"Specimen ID","visible":true}]}}]}`) + catalog := explorer.Catalog{ + Nodes: []explorer.CatalogNode{{ID: "n_patient", ResourceType: "Patient"}, {ID: "n_specimen", ResourceType: "Specimen"}}, + Selections: map[string]explorer.CatalogSelection{ + "s_patient_id": {ID: "s_patient_id", NodeID: "n_patient", FieldRef: "Patient.id", Select: "id"}, + "s_specimen_id": {ID: "s_specimen_id", NodeID: "n_specimen", FieldRef: "Specimen.id", Select: "id"}, + }, + } + bundle, report, err := ConvertDefault(raw, catalog, "project-a") + if err != nil { + t.Fatal(err) + } + if !report.Equivalent || len(bundle.Documents) != 2 || len(bundle.Tabs) != 2 || len(report.Mappings) != 2 { + t.Fatalf("report=%#v bundle=%#v", report, bundle) + } + canonical, err := bundle.CanonicalJSON() + if err != nil { + t.Fatal(err) + } + if strings.Contains(string(canonical), "select") || strings.Contains(string(canonical), "expr") || !strings.Contains(string(canonical), `"documents"`) || !strings.Contains(string(canonical), `"tabs"`) { + t.Fatalf("multi-output conversion leaked recipe or lost tabs: %s", canonical) + } +} + +func TestConvertDefaultFailsOnUnmappedField(t *testing.T) { + raw := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Default","management":"repository"},"recipe":{"recipeSchemaVersion":1,"name":"legacy","translationVersion":"v1","outputs":[{"name":"patient","rootResourceType":"Patient","rowGrain":"patient","fields":[{"name":"missing","expr":{"select":"root.missing"}}]}]}}`) + catalog := explorer.Catalog{Nodes: []explorer.CatalogNode{{ID: "n_patient", ResourceType: "Patient"}}, Selections: map[string]explorer.CatalogSelection{}} + _, report, err := ConvertDefault(raw, catalog, "project-a") + if err == nil || len(report.Unmapped) == 0 { + t.Fatalf("err=%v report=%#v", err, report) + } +} diff --git a/internal/explorer/canonical_json.go b/internal/explorer/canonical_json.go new file mode 100644 index 00000000..44afb283 --- /dev/null +++ b/internal/explorer/canonical_json.go @@ -0,0 +1,35 @@ +package explorer + +import ( + "bytes" + "encoding/json" + "fmt" + "io" +) + +// canonicalJSONBytes returns compact JSON with deterministic object-key +// ordering. It normalizes raw JSON fields before they participate in a +// content address, so persistence stores that materialize objects and then +// reconstruct them cannot change the digest merely by changing key order. +func canonicalJSONBytes(raw []byte) ([]byte, error) { + decoder := json.NewDecoder(bytes.NewReader(raw)) + decoder.UseNumber() + + var value any + if err := decoder.Decode(&value); err != nil { + return nil, fmt.Errorf("decode JSON: %w", err) + } + var trailing any + if err := decoder.Decode(&trailing); err != io.EOF { + if err == nil { + return nil, fmt.Errorf("multiple JSON values") + } + return nil, fmt.Errorf("decode trailing JSON: %w", err) + } + + canonical, err := json.Marshal(value) + if err != nil { + return nil, fmt.Errorf("encode canonical JSON: %w", err) + } + return canonical, nil +} diff --git a/internal/explorer/capability/builder.go b/internal/explorer/capability/builder.go new file mode 100644 index 00000000..5d113234 --- /dev/null +++ b/internal/explorer/capability/builder.go @@ -0,0 +1,444 @@ +package capability + +import ( + "context" + "crypto/sha256" + "encoding/json" + "fmt" + "regexp" + "sort" + "strings" +) + +// The observation interfaces intentionally speak only in evidence. They do +// not expose generated schema or database handles, so an observer can never +// turn an accidental profiler row into an executable capability on its own. +type ResourceObservation struct { + ResourceType string + Populated bool + DocumentCount int64 +} + +type RelationshipObservation struct { + SourceResourceType string + TargetResourceType string + Label string + StorageDirection string + ObservedEdgeCount int64 + AllowsRepeatedTarget bool +} + +type FieldObservation struct { + ResourceType string + Path string + Label string + LogicalType string + Cardinality string + Observed bool + ObservedDocumentCount int64 + Populated bool + SuggestedValues []string + SuggestionsComplete bool + SuggestionsTruncated bool +} + +type ResourceInventory interface { + ListResources(context.Context) ([]ResourceObservation, error) +} +type RelationshipEvidence interface { + ListRelationships(context.Context) ([]RelationshipObservation, error) +} +type FieldEvidence interface { + ListFields(context.Context) ([]FieldObservation, error) +} + +// Observer is a convenience for adapters that naturally collect all three +// evidence classes together. Builder accepts the individual interfaces too. +type Observer interface { + ResourceInventory + RelationshipEvidence + FieldEvidence +} + +type NodeProof struct { + Allowed bool + RowRootEligible bool + RowGrain string + SupportedOperations []Operation + Reason string +} + +type EdgeProof struct { + Allowed bool + Reason string +} + +type CandidateProof struct { + Allowed bool + LogicalType string + Cardinality string + ProjectionModes []ProjectionMode + FilterOperators []FilterOperator + ChartAggregations []ChartAggregation + SupportedOperations []Operation + Reason string +} + +// CompilerProbe is the compiler's proof boundary. A Builder advertises an +// operation only after the corresponding probe succeeds. In particular, a +// field is not trusted merely because the observation source reported it. +type CompilerProbe interface { + ProbeNode(context.Context, Node) (NodeProof, error) + ProbeEdge(context.Context, Edge) (EdgeProof, error) + ProbeCandidate(context.Context, Candidate) (CandidateProof, error) +} + +// Function adapters keep tests and small integrations free of boilerplate. +type ProbeFuncs struct { + Node func(context.Context, Node) (NodeProof, error) + Edge func(context.Context, Edge) (EdgeProof, error) + Candidate func(context.Context, Candidate) (CandidateProof, error) +} + +func (p ProbeFuncs) ProbeNode(ctx context.Context, n Node) (NodeProof, error) { + if p.Node == nil { + return NodeProof{}, fmt.Errorf("node probe is not configured") + } + return p.Node(ctx, n) +} +func (p ProbeFuncs) ProbeEdge(ctx context.Context, e Edge) (EdgeProof, error) { + if p.Edge == nil { + return EdgeProof{}, fmt.Errorf("edge probe is not configured") + } + return p.Edge(ctx, e) +} +func (p ProbeFuncs) ProbeCandidate(ctx context.Context, c Candidate) (CandidateProof, error) { + if p.Candidate == nil { + return CandidateProof{}, fmt.Errorf("candidate probe is not configured") + } + return p.Candidate(ctx, c) +} + +type SliceObserver struct { + Resources []ResourceObservation + Relationships []RelationshipObservation + Fields []FieldObservation +} + +func (s SliceObserver) ListResources(context.Context) ([]ResourceObservation, error) { + return append([]ResourceObservation(nil), s.Resources...), nil +} +func (s SliceObserver) ListRelationships(context.Context) ([]RelationshipObservation, error) { + return append([]RelationshipObservation(nil), s.Relationships...), nil +} +func (s SliceObserver) ListFields(context.Context) ([]FieldObservation, error) { + return append([]FieldObservation(nil), s.Fields...), nil +} + +type Builder struct { + Identity SnapshotIdentity + Policy Policy + Complete bool + Truncated bool + + Resources ResourceInventory + Relationships RelationshipEvidence + Fields FieldEvidence + Compiler CompilerProbe +} + +type CapabilityBuilder = Builder + +const DefaultSuggestionLimit = 32 + +func NewBuilder(identity SnapshotIdentity, resources ResourceInventory, relationships RelationshipEvidence, fields FieldEvidence, compiler CompilerProbe) Builder { + return Builder{Identity: identity, Resources: resources, Relationships: relationships, Fields: fields, Compiler: compiler, Complete: true, Policy: Policy{Route: RoutePolicy{AllowsRepeatedEdges: true, AllowsSelfLoops: true}, Projection: ProjectionPolicy{SuggestionLimit: DefaultSuggestionLimit}}} +} + +// Build is pure: all values returned by an adapter are copied before they are +// sorted or used, and no adapter or compiler state is modified. +func (b Builder) Build(ctx context.Context) (Snapshot, error) { + identity := b.Identity + identity.Project = strings.TrimSpace(identity.Project) + identity.Generation = strings.TrimSpace(identity.Generation) + if identity.Project == "" || identity.Generation == "" { + return b.failed(identity, "INVALID_SNAPSHOT_IDENTITY", "project and generation are required"), fmt.Errorf("project and generation are required") + } + if b.Complete == false && !b.Truncated { + // Explicitly incomplete discovery is a BUILDING snapshot, not an empty + // READY graph. The caller may publish it after a later complete build. + } + diags := []Diagnostic{} + if b.Resources == nil || b.Relationships == nil || b.Fields == nil || b.Compiler == nil { + return b.failedWith(identity, diags, "MISSING_CAPABILITY_DEPENDENCY", "resource, relationship, field, and compiler interfaces are required"), fmt.Errorf("capability dependencies are incomplete") + } + resources, err := b.Resources.ListResources(ctx) + if err != nil { + return b.failedWith(identity, diags, "RESOURCE_INVENTORY_FAILED", err.Error()), err + } + relationships, err := b.Relationships.ListRelationships(ctx) + if err != nil { + return b.failedWith(identity, diags, "RELATIONSHIP_EVIDENCE_FAILED", err.Error()), err + } + // Field enrichment is intentionally mandatory and fetched even when no + // relationship evidence exists. An omitted enrichment source must fail + // closed rather than silently yielding a field-less usable catalog. + fields, err := b.Fields.ListFields(ctx) + if err != nil { + return b.failedWith(identity, diags, "FIELD_ENRICHMENT_FAILED", err.Error()), err + } + + policy := b.Policy + if policy.Projection.Version == "" { + policy.Projection.Version = identity.ProjectionPolicyVersion + } + if policy.Route.Version == "" { + policy.Route.Version = identity.TraversalPolicyVersion + } + if policy.Route.MaxHops < 0 { + return b.failedWith(identity, diags, "INVALID_ROUTE_POLICY", "route MaxHops cannot be negative"), fmt.Errorf("route MaxHops cannot be negative") + } + // Zero means unlimited. Defaults explicitly advertise the two traversal + // forms that the policy permits rather than relying on omitted JSON fields. + if !policy.Route.AllowsRepeatedEdges && !policy.Route.AllowsSelfLoops { + policy.Route.AllowsRepeatedEdges, policy.Route.AllowsSelfLoops = true, true + } + if policy.Projection.SuggestionLimit == 0 { + policy.Projection.SuggestionLimit = DefaultSuggestionLimit + } + identity.TraversalPolicyVersion = first(identity.TraversalPolicyVersion, policy.Route.Version) + identity.ProjectionPolicyVersion = first(identity.ProjectionPolicyVersion, policy.Projection.Version) + idSeed := identityDigest(identity) + + // A resource type is a concrete generated FHIR type, not a collection or + // arbitrary path. Deduplicate only exact resource observations; their + // populatedness remains an annotation of the single capability. + resourceMap := map[string]ResourceObservation{} + for _, raw := range resources { + t := strings.TrimSpace(raw.ResourceType) + if !validResourceType(t) { + diags = append(diags, diag("INVALID_RESOURCE_TYPE", "resource type is not a concrete generated type", t)) + continue + } + if prior, ok := resourceMap[t]; ok { + prior.Populated = prior.Populated || raw.Populated + if raw.DocumentCount > prior.DocumentCount { + prior.DocumentCount = raw.DocumentCount + } + resourceMap[t] = prior + } else { + raw.ResourceType = t + resourceMap[t] = raw + } + } + types := make([]string, 0, len(resourceMap)) + for t := range resourceMap { + types = append(types, t) + } + sort.Strings(types) + nodes := []Node{} + auditNodes := []Node{} + nodeByType := map[string]Node{} + for _, t := range types { + o := resourceMap[t] + n := Node{ID: digestID("n_", idSeed, t), ResourceType: t, Populated: o.Populated, DocumentCount: o.DocumentCount} + if !o.Populated && o.DocumentCount <= 0 { + n.BlockedReason = "resource collection is not populated" + auditNodes = append(auditNodes, n) + diags = append(diags, diag("NOT_POPULATED", "resource inventory did not observe any rows", t)) + continue + } + proof, e := b.Compiler.ProbeNode(ctx, n) + if e != nil || !proof.Allowed || !proof.RowRootEligible || len(proof.SupportedOperations) == 0 { + reason := proof.Reason + if e != nil { + reason = e.Error() + } + if reason == "" { + reason = "compiler did not prove a supported row root" + } + n.BlockedReason = reason + auditNodes = append(auditNodes, n) + diags = append(diags, diag("NODE_NOT_PROVEN", "resource observation failed compiler proof", t)) + continue + } + n.RowRootEligible = proof.RowRootEligible + n.RowGrain = proof.RowGrain + n.SupportedOperations = append([]Operation(nil), proof.SupportedOperations...) + n.CapabilityVersion = identity.CompilerVersion + nodes = append(nodes, n) + nodeByType[t] = n + } + + // Sort relationships by their complete identity before assigning ordinals; + // this makes repeated edges deterministic and preserves self-loops. + sort.SliceStable(relationships, func(i, j int) bool { + return relationshipSortKey(relationships[i]) < relationshipSortKey(relationships[j]) + }) + edges := []Edge{} + auditEdges := []Edge{} + edgeOrd := map[string]int{} + for _, r := range relationships { + src, dst := strings.TrimSpace(r.SourceResourceType), strings.TrimSpace(r.TargetResourceType) + base := relationshipKey(RelationshipObservation{SourceResourceType: src, TargetResourceType: dst, Label: strings.TrimSpace(r.Label), StorageDirection: strings.TrimSpace(r.StorageDirection)}) + ord := edgeOrd[base] + edgeOrd[base] = ord + 1 + e := Edge{ID: digestID("e_", idSeed, base, fmt.Sprint(ord)), FromNodeID: digestID("n_", idSeed, src), ToNodeID: digestID("n_", idSeed, dst), Label: strings.TrimSpace(r.Label), StorageDirection: strings.TrimSpace(r.StorageDirection), SourceResourceType: src, TargetResourceType: dst, ObservedEdgeCount: r.ObservedEdgeCount, AllowsRepeatedTarget: r.AllowsRepeatedTarget} + if !validResourceType(src) || !validResourceType(dst) || e.Label == "" || nodeByType[src].ID == "" || nodeByType[dst].ID == "" { + e.BlockedReason = "relationship endpoints or label are not a usable generated traversal" + auditEdges = append(auditEdges, e) + diags = append(diags, diag("INVALID_RELATIONSHIP", "relationship endpoint or label is invalid or unproven", base)) + continue + } + proof, eProbe := b.Compiler.ProbeEdge(ctx, e) + if eProbe != nil || !proof.Allowed { + reason := proof.Reason + if eProbe != nil { + reason = eProbe.Error() + } + if reason == "" { + reason = "compiler did not prove traversal" + } + e.BlockedReason = reason + auditEdges = append(auditEdges, e) + diags = append(diags, diag("EDGE_NOT_PROVEN", "relationship observation failed compiler proof", base)) + continue + } + edges = append(edges, e) + } + + // Candidate IDs are local to this snapshot and occurrence-stable even when + // evidence repeats the same path. Paths are validated before any probe. + sort.SliceStable(fields, func(i, j int) bool { return fieldSortKey(fields[i]) < fieldSortKey(fields[j]) }) + candidates := []Candidate{} + auditCandidates := []Candidate{} + candOrd := map[string]int{} + for _, f := range fields { + t, path := strings.TrimSpace(f.ResourceType), canonicalPath(f.Path) + base := t + "\x00" + path + ord := candOrd[base] + candOrd[base] = ord + 1 + c := Candidate{ID: digestID("c_", idSeed, base, fmt.Sprint(ord)), NodeID: digestID("n_", idSeed, t), ResourceType: t, FieldPath: path, Label: first(strings.TrimSpace(f.Label), path), LogicalType: f.LogicalType, Cardinality: f.Cardinality, Observed: f.Observed, ObservedDocumentCount: f.ObservedDocumentCount, Populated: f.Populated} + c.SuggestedValues = append([]string(nil), f.SuggestedValues...) + c.SuggestionsComplete = f.SuggestionsComplete + c.SuggestionsTruncated = f.SuggestionsTruncated + sort.Strings(c.SuggestedValues) + if policy.Projection.SuggestionLimit > 0 && len(c.SuggestedValues) > policy.Projection.SuggestionLimit { + c.SuggestedValues = c.SuggestedValues[:policy.Projection.SuggestionLimit] + c.SuggestionsTruncated = true + c.SuggestionsComplete = false + } + if !validResourceType(t) || path == "" || nodeByType[t].ID == "" { + c.BlockedReason = "field path or owning resource is not usable" + auditCandidates = append(auditCandidates, c) + diags = append(diags, diag("INVALID_FIELD_PATH", "field evidence did not resolve to a usable node/path", base)) + continue + } + proof, eProbe := b.Compiler.ProbeCandidate(ctx, c) + if eProbe != nil || !proof.Allowed || len(proof.ProjectionModes) == 0 || len(proof.SupportedOperations) == 0 { + reason := proof.Reason + if eProbe != nil { + reason = eProbe.Error() + } + if reason == "" { + reason = "compiler did not prove field projection" + } + c.BlockedReason = reason + auditCandidates = append(auditCandidates, c) + diags = append(diags, diag("CANDIDATE_NOT_PROVEN", "field observation failed compiler proof", base)) + continue + } + c.LogicalType = first(proof.LogicalType, c.LogicalType) + c.Cardinality = first(proof.Cardinality, c.Cardinality) + c.ProjectionModes = append([]ProjectionMode(nil), proof.ProjectionModes...) + c.FilterOperators = append([]FilterOperator(nil), proof.FilterOperators...) + c.ChartAggregations = append([]ChartAggregation(nil), proof.ChartAggregations...) + c.SupportedOperations = append([]Operation(nil), proof.SupportedOperations...) + candidates = append(candidates, c) + } + status := StatusReady + if !b.Complete || b.Truncated { + status = StatusBuilding + } + if len(diags) > 0 && (b.Fields == nil) { + status = StatusFailed + } + s := NewSnapshot(identity, policy, status, b.Complete, b.Truncated, nodes, edges, candidates, diags) + s.AuditNodes = auditNodes + s.AuditEdges = auditEdges + s.AuditCandidates = auditCandidates + s = rehash(s) + return s, nil +} + +func (b Builder) failed(identity SnapshotIdentity, code, message string) Snapshot { + return b.failedWith(identity, nil, code, message) +} +func (b Builder) failedWith(identity SnapshotIdentity, ds []Diagnostic, code, message string) Snapshot { + ds = append(ds, diag(code, message, "")) + return NewSnapshot(identity, b.Policy, StatusFailed, false, b.Truncated, nil, nil, nil, ds) +} +func rehash(s Snapshot) Snapshot { + s.Token = "" + p := s.CanonicalPayload() + sum := sha256sum(p) + s.Token = "sha256:" + sum + return s +} +func identityDigest(identity SnapshotIdentity) string { + raw, _ := json.Marshal(identity) + return sha256sum(raw) +} +func sha256sum(p []byte) string { h := sha256.New(); h.Write(p); return fmt.Sprintf("%x", h.Sum(nil)) } +func diag(code, message, detail string) Diagnostic { + d := Diagnostic{Severity: "ERROR", Stage: "capability", Code: code, Message: message} + if detail != "" { + d.Details = map[string]any{"value": detail} + } + return d +} +func first(a, b string) string { + if strings.TrimSpace(a) != "" { + return a + } + return b +} +func relationshipKey(r RelationshipObservation) string { + return strings.TrimSpace(r.SourceResourceType) + "\x00" + strings.TrimSpace(r.TargetResourceType) + "\x00" + strings.TrimSpace(r.Label) + "\x00" + strings.TrimSpace(r.StorageDirection) +} +func relationshipSortKey(r RelationshipObservation) string { + return relationshipKey(r) + fmt.Sprintf("\x00%d\x00%d", r.ObservedEdgeCount, boolInt(r.AllowsRepeatedTarget)) +} +func fieldKey(f FieldObservation) string { + return strings.TrimSpace(f.ResourceType) + "\x00" + canonicalPath(f.Path) + "\x00" + strings.TrimSpace(f.Label) + "\x00" + f.LogicalType +} +func fieldSortKey(f FieldObservation) string { + values := append([]string(nil), f.SuggestedValues...) + sort.Strings(values) + return fieldKey(f) + "\x00" + f.Cardinality + fmt.Sprintf("\x00%d\x00%d\x00%d\x00%d\x00%d\x00%s", f.ObservedDocumentCount, boolInt(f.Observed), boolInt(f.Populated), boolInt(f.SuggestionsComplete), boolInt(f.SuggestionsTruncated), strings.Join(values, "\x01")) +} +func boolInt(v bool) int { + if v { + return 1 + } + return 0 +} + +var resourceTypePattern = regexp.MustCompile(`^[A-Z][A-Za-z0-9]*$`) +var pathSegmentPattern = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_-]*(\[\])?$`) + +func validResourceType(s string) bool { return resourceTypePattern.MatchString(strings.TrimSpace(s)) } +func canonicalPath(raw string) string { + p := strings.TrimSpace(raw) + if p == "" || strings.HasPrefix(p, ".") || strings.HasSuffix(p, ".") || strings.Contains(p, "..") { + return "" + } + segs := strings.Split(p, ".") + for i := range segs { + segs[i] = strings.TrimSpace(segs[i]) + if !pathSegmentPattern.MatchString(segs[i]) { + return "" + } + } + return strings.Join(segs, ".") +} diff --git a/internal/explorer/capability/builder_test.go b/internal/explorer/capability/builder_test.go new file mode 100644 index 00000000..43695d30 --- /dev/null +++ b/internal/explorer/capability/builder_test.go @@ -0,0 +1,165 @@ +package capability + +import ( + "context" + "reflect" + "testing" +) + +func testIdentity() SnapshotIdentity { + return SnapshotIdentity{Project: "p", Generation: "g", AuthorizationScopeDigest: "scope", SchemaDigest: "schema", ResourceInventoryDigest: "inventory", RelationshipDigest: "relationships", FieldDigest: "fields", ProtocolVersion: "protocol-1", CompilerVersion: "compiler-1", TraversalPolicyVersion: "route-1", ProjectionPolicyVersion: "projection-1"} +} + +func testProbe() ProbeFuncs { + return ProbeFuncs{ + Node: func(_ context.Context, n Node) (NodeProof, error) { + return NodeProof{Allowed: true, RowRootEligible: true, RowGrain: "RESOURCE", SupportedOperations: []Operation{OperationSelect, OperationFilter}}, nil + }, + Edge: func(_ context.Context, _ Edge) (EdgeProof, error) { return EdgeProof{Allowed: true}, nil }, + Candidate: func(_ context.Context, _ Candidate) (CandidateProof, error) { + return CandidateProof{Allowed: true, ProjectionModes: []ProjectionMode{ProjectionFirst, ProjectionArray}, FilterOperators: []FilterOperator{FilterEquals}, SupportedOperations: []Operation{OperationSelect, OperationFilter}}, nil + }, + } +} + +func testBuilder(obs SliceObserver) Builder { + return NewBuilder(testIdentity(), obs, obs, obs, testProbe()) +} + +func TestSnapshotHashIsOrderIndependentAndIdentityComplete(t *testing.T) { + nodes := []Node{{ID: "n_b", ResourceType: "B"}, {ID: "n_a", ResourceType: "A"}} + edges := []Edge{{ID: "e_b", FromNodeID: "n_b", ToNodeID: "n_a"}, {ID: "e_a", FromNodeID: "n_a", ToNodeID: "n_b"}} + candidates := []Candidate{{ID: "c_b", NodeID: "n_b", FieldPath: "z", ProjectionModes: []ProjectionMode{ProjectionArray, ProjectionFirst}}, {ID: "c_a", NodeID: "n_a", FieldPath: "a", ProjectionModes: []ProjectionMode{ProjectionFirst, ProjectionArray}}} + p := Policy{Route: RoutePolicy{Version: "r", AllowsRepeatedEdges: true, AllowsSelfLoops: true}, Projection: ProjectionPolicy{Version: "p", Modes: []ProjectionMode{ProjectionArray, ProjectionFirst}, SuggestionLimit: 3}} + a := NewSnapshot(testIdentity(), p, StatusReady, true, false, nodes, edges, candidates, nil) + b := NewSnapshot(testIdentity(), p, StatusReady, true, false, []Node{nodes[1], nodes[0]}, []Edge{edges[1], edges[0]}, []Candidate{candidates[1], candidates[0]}, nil) + if a.Token != b.Token { + t.Fatalf("reordering payload changed token: %s != %s", a.Token, b.Token) + } + fields := []struct { + name string + edit func(*SnapshotIdentity) + }{ + {"project", func(i *SnapshotIdentity) { i.Project = "other" }}, {"generation", func(i *SnapshotIdentity) { i.Generation = "other" }}, {"scope", func(i *SnapshotIdentity) { i.AuthorizationScopeDigest = "other" }}, {"schema", func(i *SnapshotIdentity) { i.SchemaDigest = "other" }}, {"inventory", func(i *SnapshotIdentity) { i.ResourceInventoryDigest = "other" }}, {"relationships", func(i *SnapshotIdentity) { i.RelationshipDigest = "other" }}, {"fields", func(i *SnapshotIdentity) { i.FieldDigest = "other" }}, {"protocol", func(i *SnapshotIdentity) { i.ProtocolVersion = "other" }}, {"compiler", func(i *SnapshotIdentity) { i.CompilerVersion = "other" }}, {"traversal", func(i *SnapshotIdentity) { i.TraversalPolicyVersion = "other" }}, {"projection", func(i *SnapshotIdentity) { i.ProjectionPolicyVersion = "other" }}, + } + for _, tc := range fields { + id := testIdentity() + tc.edit(&id) + if NewSnapshot(id, p, StatusReady, true, false, nil, nil, nil, nil).Token == a.Token { + t.Errorf("changing %s did not change token", tc.name) + } + } +} + +func TestBuilderUsesProofAndCopiesObservation(t *testing.T) { + obs := SliceObserver{Resources: []ResourceObservation{{ResourceType: "Patient", Populated: true, DocumentCount: 4}, {ResourceType: "Observation", Populated: true}}, Relationships: []RelationshipObservation{{SourceResourceType: "Patient", TargetResourceType: "Patient", Label: "partOf", StorageDirection: "OUTBOUND"}, {SourceResourceType: "Patient", TargetResourceType: "Patient", Label: "partOf", StorageDirection: "OUTBOUND"}}, Fields: []FieldObservation{{ResourceType: "Patient", Path: "name", Label: "Name", LogicalType: "string", SuggestedValues: []string{"B", "A"}, Observed: true, Populated: true}}} + s := testBuilder(obs).Build + snapshot, err := s(context.Background()) + if err != nil || !snapshot.Usable() { + t.Fatalf("build failed: %#v %#v", snapshot, err) + } + if len(snapshot.Nodes) != 2 || len(snapshot.Edges) != 2 || len(snapshot.Candidates) != 1 { + t.Fatalf("unexpected capabilities: %#v", snapshot) + } + if snapshot.Edges[0].ID == snapshot.Edges[1].ID { + t.Fatal("repeated edges need distinct snapshot-local IDs") + } + obs.Resources[0].ResourceType = "Mutated" + obs.Fields[0].SuggestedValues[0] = "Mutated" + if snapshot.Nodes[0].ResourceType == "Mutated" || snapshot.Candidates[0].SuggestedValues[0] == "Mutated" { + t.Fatal("builder retained caller-owned mutable data") + } +} + +func TestUnpopulatedInventoryResourcesStayOutOfUsableNodes(t *testing.T) { + obs := SliceObserver{Resources: []ResourceObservation{{ResourceType: "Patient", Populated: true, DocumentCount: 1}, {ResourceType: "Observation", DocumentCount: 0}}, Fields: []FieldObservation{}} + s, err := testBuilder(obs).Build(context.Background()) + if err != nil { + t.Fatal(err) + } + if len(s.Nodes) != 1 || s.Nodes[0].ResourceType != "Patient" { + t.Fatalf("unpopulated resource was advertised: %#v", s.Nodes) + } + if len(s.AuditNodes) != 1 || s.AuditNodes[0].BlockedReason == "" { + t.Fatalf("unpopulated resource was not retained for audit: %#v", s.AuditNodes) + } +} + +func TestIDsAreBoundToSnapshotIdentity(t *testing.T) { + obs := SliceObserver{Resources: []ResourceObservation{{ResourceType: "Patient", Populated: true}}, Fields: []FieldObservation{{ResourceType: "Patient", Path: "name"}}} + a, err := testBuilder(obs).Build(context.Background()) + if err != nil { + t.Fatal(err) + } + id := testIdentity() + id.Generation = "other-generation" + b := NewBuilder(id, obs, obs, obs, testProbe()) + other, err := b.Build(context.Background()) + if err != nil { + t.Fatal(err) + } + if a.Nodes[0].ID == other.Nodes[0].ID || a.Candidates[0].ID == other.Candidates[0].ID { + t.Fatal("opaque IDs escaped their snapshot identity") + } + if _, ok := a.Node(other.Nodes[0].ID); ok { + t.Fatal("snapshot A resolved a node minted by snapshot B") + } +} + +func TestBuilderRejectsMalformedEvidenceAndCompilerFailures(t *testing.T) { + obs := SliceObserver{Resources: []ResourceObservation{{ResourceType: "Patient"}}, Relationships: []RelationshipObservation{{SourceResourceType: "Patient", TargetResourceType: "Bad/Type", Label: "x"}}, Fields: []FieldObservation{{ResourceType: "Patient", Path: "name..given"}}} + // Build with a rejecting node leaves no usable root and retains audit data. + b := testBuilder(obs) + got, buildErr := b.Build(context.Background()) + if buildErr != nil { + t.Fatal(buildErr) + } + if len(got.Edges) != 0 || len(got.Candidates) != 0 || len(got.AuditEdges) == 0 || len(got.AuditCandidates) == 0 { + t.Fatalf("blocked evidence escaped usable graph: %#v", got) + } +} + +func TestBuilderFieldEnrichmentIsFailClosed(t *testing.T) { + obs := SliceObserver{Resources: []ResourceObservation{{ResourceType: "Patient"}}, Relationships: nil, Fields: nil} + b := NewBuilder(testIdentity(), obs, obs, nil, testProbe()) + s, err := b.Build(context.Background()) + if err == nil || s.Status != StatusFailed || s.Usable() { + t.Fatalf("missing enrichment was not failed closed: %#v, %v", s, err) + } +} + +func TestIncompleteAndTruncatedSnapshotsAreNotUsable(t *testing.T) { + obs := SliceObserver{} + b := testBuilder(obs) + b.Complete = false + s, err := b.Build(context.Background()) + if err != nil || s.Status != StatusBuilding || s.Usable() { + t.Fatalf("incomplete snapshot: %#v %v", s, err) + } + b.Complete, b.Truncated = true, true + s, err = b.Build(context.Background()) + if err != nil || s.Status != StatusBuilding || s.Usable() { + t.Fatalf("truncated snapshot: %#v %v", s, err) + } +} + +func TestRoutePolicyAllowsFiniteRepeatedAndSelfLoopRoutes(t *testing.T) { + p := RoutePolicy{Version: "route", MaxHops: 0, AllowsRepeatedEdges: true, AllowsSelfLoops: true} + route := []string{"n", "n", "m", "n", "m", "n", "m", "n", "m", "n"} + if !p.Allows(route) { + t.Fatal("unbounded route policy rejected finite route") + } + if (RoutePolicy{MaxHops: 4, AllowsRepeatedEdges: true, AllowsSelfLoops: true}).Allows(route) { + t.Fatal("explicit bounded route policy accepted too many hops") + } +} + +func TestCloneDefensivelyCopiesNestedDiagnostics(t *testing.T) { + d := []Diagnostic{{Code: "x", Details: map[string]any{"nested": map[string]any{"values": []any{"a"}}}}} + s := NewSnapshot(testIdentity(), Policy{}, StatusReady, true, false, nil, nil, nil, d) + clone := s.Clone() + clone.Diagnostics[0].Details["nested"].(map[string]any)["values"].([]any)[0] = "changed" + if reflect.DeepEqual(s.Diagnostics, clone.Diagnostics) { + t.Fatal("clone shares nested diagnostics") + } +} diff --git a/internal/explorer/capability/domain.go b/internal/explorer/capability/domain.go new file mode 100644 index 00000000..2a373c36 --- /dev/null +++ b/internal/explorer/capability/domain.go @@ -0,0 +1,390 @@ +// Package capability contains the immutable, compiler-backed contract exposed +// by Explorer's traversal Builder. It deliberately has no dependency on the +// database, generated schema, or HTTP layers: adapters provide observations and +// compiler proofs through the small interfaces in builder.go. +package capability + +import ( + "crypto/sha256" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "sort" + "strings" +) + +type Status string + +const ( + StatusBuilding Status = "BUILDING" + StatusReady Status = "READY" + StatusFailed Status = "FAILED" +) + +// These aliases make the wire values convenient to use without making callers +// depend on the underlying spelling. +const ( + BUILDING Status = StatusBuilding + READY Status = StatusReady + FAILED Status = StatusFailed +) + +type Operation string + +const ( + OperationSelect Operation = "SELECT" + OperationFilter Operation = "FILTER" + OperationChart Operation = "CHART" + OperationSort Operation = "SORT" + OperationAggregate Operation = "AGGREGATE" +) + +type ProjectionMode string + +const ( + ProjectionScalar ProjectionMode = "SCALAR" + ProjectionFirst ProjectionMode = "FIRST" + ProjectionArray ProjectionMode = "ARRAY" + ProjectionDistinctArray ProjectionMode = "DISTINCT_ARRAY" +) + +// Short aliases are useful to adapters that mirror the frontend vocabulary. +const ( + FIRST ProjectionMode = ProjectionFirst + ARRAY ProjectionMode = ProjectionArray + DISTINCT_ARRAY ProjectionMode = ProjectionDistinctArray +) + +type FilterOperator string + +const ( + FilterEquals FilterOperator = "EQUALS" + FilterIn FilterOperator = "IN" + FilterExists FilterOperator = "EXISTS" +) + +type ChartAggregation string + +const ( + ChartCount ChartAggregation = "COUNT" + ChartSum ChartAggregation = "SUM" + ChartMin ChartAggregation = "MIN" + ChartMax ChartAggregation = "MAX" + ChartAvg ChartAggregation = "AVG" +) + +// SnapshotIdentity contains every external identity that can change the +// meaning of a capability document. Versions are intentionally independent: +// changing a renderer/compiler artifact must invalidate old Builder state even +// when the observed graph is unchanged. +type SnapshotIdentity struct { + Project string `json:"project"` + Generation string `json:"generation"` + AuthorizationScopeDigest string `json:"authorizationScopeDigest"` + SchemaDigest string `json:"schemaDigest"` + ResourceInventoryDigest string `json:"resourceInventoryDigest"` + RelationshipDigest string `json:"relationshipDigest"` + FieldDigest string `json:"fieldDigest"` + ProtocolVersion string `json:"protocolVersion"` + CompilerVersion string `json:"compilerVersion"` + TraversalPolicyVersion string `json:"traversalPolicyVersion"` + ProjectionPolicyVersion string `json:"projectionPolicyVersion"` +} + +type RoutePolicy struct { + Version string `json:"version"` + MaxHops int `json:"maxHops"` // zero means unlimited + AllowsRepeatedEdges bool `json:"allowsRepeatedEdges"` + AllowsSelfLoops bool `json:"allowsSelfLoops"` +} + +// Allows accepts every finite route (including zero-hop routes, repeated +// edges, and self-loops) unless the caller explicitly configured MaxHops. +// There is deliberately no implicit four-hop limit. +func (p RoutePolicy) Allows(route []string) bool { + if p.MaxHops > 0 && len(route) > p.MaxHops { + return false + } + for _, id := range route { + if strings.TrimSpace(id) == "" { + return false + } + } + return true +} + +type ProjectionPolicy struct { + Version string `json:"version"` + Modes []ProjectionMode `json:"modes"` + SuggestionLimit int `json:"suggestionLimit"` +} + +type Policy struct { + Route RoutePolicy `json:"route"` + Projection ProjectionPolicy `json:"projection"` +} + +type Node struct { + ID string `json:"nodeId"` + ResourceType string `json:"resourceType"` + RowRootEligible bool `json:"rowRootEligible"` + RowGrain string `json:"rowGrain,omitempty"` + Populated bool `json:"populated"` + DocumentCount int64 `json:"documentCount,omitempty"` + SupportedOperations []Operation `json:"supportedOperations"` + BlockedReason string `json:"blockedReason,omitempty"` + CapabilityVersion string `json:"capabilityVersion,omitempty"` +} + +type Edge struct { + ID string `json:"edgeId"` + FromNodeID string `json:"fromNodeId"` + ToNodeID string `json:"toNodeId"` + Label string `json:"label"` + StorageDirection string `json:"storageDirection,omitempty"` + SourceResourceType string `json:"sourceResourceType"` + TargetResourceType string `json:"targetResourceType"` + ObservedEdgeCount int64 `json:"observedEdgeCount,omitempty"` + AllowsRepeatedTarget bool `json:"allowsRepeatedTarget,omitempty"` + BlockedReason string `json:"blockedReason,omitempty"` +} + +type Candidate struct { + ID string `json:"candidateId"` + NodeID string `json:"nodeId"` + ResourceType string `json:"resourceType"` + FieldPath string `json:"fieldPath"` + Label string `json:"label"` + LogicalType string `json:"logicalType"` + Cardinality string `json:"cardinality,omitempty"` + ProjectionModes []ProjectionMode `json:"projectionModes"` + FilterOperators []FilterOperator `json:"filterOperators"` + ChartAggregations []ChartAggregation `json:"chartAggregations"` + SupportedOperations []Operation `json:"supportedOperations"` + Observed bool `json:"observed"` + ObservedDocumentCount int64 `json:"observedDocumentCount,omitempty"` + Populated bool `json:"populated"` + SuggestedValues []string `json:"suggestedValues,omitempty"` + SuggestionsComplete bool `json:"suggestionsComplete"` + SuggestionsTruncated bool `json:"suggestionsTruncated"` + BlockedReason string `json:"blockedReason,omitempty"` +} + +type Diagnostic struct { + Severity string `json:"severity"` + Stage string `json:"stage,omitempty"` + Code string `json:"code"` + Message string `json:"message"` + Details map[string]any `json:"details,omitempty"` + Retryable bool `json:"retryable,omitempty"` +} + +// Snapshot is immutable by convention: constructors and accessors copy all +// maps/slices, while Token is derived from a private canonical payload. The +// exported fields keep the package ergonomic for JSON adapters; use Clone (or +// the accessors) when handing a snapshot to code that may mutate values. +type Snapshot struct { + Identity SnapshotIdentity `json:"identity"` + Policy Policy `json:"policy"` + Status Status `json:"status"` + Complete bool `json:"complete"` + Truncated bool `json:"truncated"` + Nodes []Node `json:"nodes"` + Edges []Edge `json:"edges"` + Candidates []Candidate `json:"candidates"` + Diagnostics []Diagnostic `json:"diagnostics"` + AuditNodes []Node `json:"auditNodes,omitempty"` + AuditEdges []Edge `json:"auditEdges,omitempty"` + AuditCandidates []Candidate `json:"auditCandidates,omitempty"` + Token string `json:"token"` +} + +// CapabilitySnapshot is the descriptive name used at API seams; Snapshot is +// retained as the concise package-local spelling. +type CapabilitySnapshot = Snapshot + +var ( + ErrSnapshotUnavailable = errors.New("capability snapshot is unavailable") + ErrStaleSnapshot = errors.New("capability snapshot token is stale") +) + +func (s Snapshot) Usable() bool { return s.Status == StatusReady && s.Complete && !s.Truncated } +func (s Snapshot) IsUsable() bool { return s.Usable() } + +func (s Snapshot) ValidateToken(token string) error { + if token == "" || token != s.Token { + return ErrStaleSnapshot + } + if !s.Usable() { + return ErrSnapshotUnavailable + } + return nil +} + +func (s Snapshot) Clone() Snapshot { return cloneSnapshot(s) } + +func (s Snapshot) Node(id string) (Node, bool) { + for _, n := range s.Nodes { + if n.ID == id { + return cloneNodes([]Node{n})[0], true + } + } + return Node{}, false +} +func (s Snapshot) Edge(id string) (Edge, bool) { + for _, e := range s.Edges { + if e.ID == id { + return e, true + } + } + return Edge{}, false +} +func (s Snapshot) Candidate(id string) (Candidate, bool) { + for _, c := range s.Candidates { + if c.ID == id { + return cloneCandidates([]Candidate{c})[0], true + } + } + return Candidate{}, false +} + +// CanonicalPayload returns a fresh copy of the exact payload hashed into Token. +func (s Snapshot) CanonicalPayload() []byte { + c := cloneSnapshot(s) + c.Token = "" + raw, _ := json.Marshal(canonicalSnapshot(c)) + return raw +} + +func canonicalSnapshot(s Snapshot) Snapshot { + s.Nodes = append([]Node(nil), s.Nodes...) + s.Edges = append([]Edge(nil), s.Edges...) + s.Candidates = append([]Candidate(nil), s.Candidates...) + s.AuditNodes = append([]Node(nil), s.AuditNodes...) + s.AuditEdges = append([]Edge(nil), s.AuditEdges...) + s.AuditCandidates = append([]Candidate(nil), s.AuditCandidates...) + s.Diagnostics = append([]Diagnostic(nil), s.Diagnostics...) + sort.Slice(s.Nodes, func(i, j int) bool { return s.Nodes[i].ID < s.Nodes[j].ID }) + sort.Slice(s.Edges, func(i, j int) bool { return s.Edges[i].ID < s.Edges[j].ID }) + sort.Slice(s.Candidates, func(i, j int) bool { return s.Candidates[i].ID < s.Candidates[j].ID }) + sort.Slice(s.AuditNodes, func(i, j int) bool { return s.AuditNodes[i].ID < s.AuditNodes[j].ID }) + sort.Slice(s.AuditEdges, func(i, j int) bool { return s.AuditEdges[i].ID < s.AuditEdges[j].ID }) + sort.Slice(s.AuditCandidates, func(i, j int) bool { return s.AuditCandidates[i].ID < s.AuditCandidates[j].ID }) + sort.Slice(s.Diagnostics, func(i, j int) bool { + if s.Diagnostics[i].Code != s.Diagnostics[j].Code { + return s.Diagnostics[i].Code < s.Diagnostics[j].Code + } + return s.Diagnostics[i].Message < s.Diagnostics[j].Message + }) + sort.Slice(s.Policy.Projection.Modes, func(i, j int) bool { return s.Policy.Projection.Modes[i] < s.Policy.Projection.Modes[j] }) + normalizeNodeSlices(s.Nodes) + normalizeCandidateSlices(s.Candidates) + normalizeNodeSlices(s.AuditNodes) + normalizeCandidateSlices(s.AuditCandidates) + normalizeCandidateSlices(s.Candidates) + normalizeCandidateValues(s.Candidates) + normalizeCandidateValues(s.AuditCandidates) + return s +} + +func NewSnapshot(identity SnapshotIdentity, policy Policy, status Status, complete, truncated bool, nodes []Node, edges []Edge, candidates []Candidate, diagnostics []Diagnostic) Snapshot { + s := Snapshot{Identity: identity, Policy: policy, Status: status, Complete: complete, Truncated: truncated, Nodes: nodes, Edges: edges, Candidates: candidates, Diagnostics: diagnostics} + s = cloneSnapshot(s) + payload := s.CanonicalPayload() + sum := sha256.Sum256(payload) + s.Token = "sha256:" + hex.EncodeToString(sum[:]) + return s +} + +func normalizeNodeSlices(nodes []Node) { + for i := range nodes { + sort.Slice(nodes[i].SupportedOperations, func(a, b int) bool { return nodes[i].SupportedOperations[a] < nodes[i].SupportedOperations[b] }) + } +} +func normalizeCandidateSlices(cs []Candidate) { + for i := range cs { + sort.Slice(cs[i].ProjectionModes, func(a, b int) bool { return cs[i].ProjectionModes[a] < cs[i].ProjectionModes[b] }) + sort.Slice(cs[i].FilterOperators, func(a, b int) bool { return cs[i].FilterOperators[a] < cs[i].FilterOperators[b] }) + sort.Slice(cs[i].ChartAggregations, func(a, b int) bool { return cs[i].ChartAggregations[a] < cs[i].ChartAggregations[b] }) + sort.Slice(cs[i].SupportedOperations, func(a, b int) bool { return cs[i].SupportedOperations[a] < cs[i].SupportedOperations[b] }) + } +} +func normalizeCandidateValues(cs []Candidate) { + for i := range cs { + sort.Strings(cs[i].SuggestedValues) + } +} + +func cloneSnapshot(s Snapshot) Snapshot { + s.Nodes = cloneNodes(s.Nodes) + s.AuditNodes = cloneNodes(s.AuditNodes) + s.Edges = append([]Edge(nil), s.Edges...) + s.AuditEdges = append([]Edge(nil), s.AuditEdges...) + s.Candidates = cloneCandidates(s.Candidates) + s.AuditCandidates = cloneCandidates(s.AuditCandidates) + s.Diagnostics = cloneDiagnostics(s.Diagnostics) + s.Policy.Projection.Modes = append([]ProjectionMode(nil), s.Policy.Projection.Modes...) + return s +} +func cloneNodes(v []Node) []Node { + out := append([]Node(nil), v...) + for i := range out { + out[i].SupportedOperations = append([]Operation(nil), out[i].SupportedOperations...) + } + return out +} +func cloneCandidates(v []Candidate) []Candidate { + out := append([]Candidate(nil), v...) + for i := range out { + out[i].ProjectionModes = append([]ProjectionMode(nil), out[i].ProjectionModes...) + out[i].FilterOperators = append([]FilterOperator(nil), out[i].FilterOperators...) + out[i].ChartAggregations = append([]ChartAggregation(nil), out[i].ChartAggregations...) + out[i].SupportedOperations = append([]Operation(nil), out[i].SupportedOperations...) + out[i].SuggestedValues = append([]string(nil), out[i].SuggestedValues...) + } + return out +} +func cloneDiagnostics(v []Diagnostic) []Diagnostic { + out := append([]Diagnostic(nil), v...) + for i := range out { + if v[i].Details != nil { + out[i].Details = map[string]any{} + for k, val := range v[i].Details { + out[i].Details[k] = cloneAny(val) + } + } + } + return out +} + +func cloneAny(v any) any { + switch x := v.(type) { + case map[string]any: + m := make(map[string]any, len(x)) + for k, val := range x { + m[k] = cloneAny(val) + } + return m + case []any: + a := make([]any, len(x)) + for i, val := range x { + a[i] = cloneAny(val) + } + return a + case []string: + return append([]string(nil), x...) + case map[string]string: + return map[string]string(x) + default: + return v + } +} + +func digestID(prefix string, values ...string) string { + h := sha256.New() + for _, v := range values { + fmt.Fprintf(h, "%d:%s|", len(v), v) + } + return prefix + hex.EncodeToString(h.Sum(nil))[:24] +} diff --git a/internal/explorer/capabilitystore/repository.go b/internal/explorer/capabilitystore/repository.go new file mode 100644 index 00000000..a07ebdfc --- /dev/null +++ b/internal/explorer/capabilitystore/repository.go @@ -0,0 +1,234 @@ +// Package capabilitystore contains persistence adapters for immutable +// Explorer capability snapshots. +package capabilitystore + +import ( + "bytes" + "context" + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + "reflect" + "sort" + "sync" + + "github.com/calypr/loom/internal/explorer/capability" +) + +var ( + ErrNotFound = errors.New("capability snapshot not found") + ErrInvalidSnapshot = errors.New("invalid capability snapshot") + ErrTokenCollision = errors.New("capability snapshot token collision") +) + +// Repository persists complete snapshots. Put is content-addressed and never +// changes an existing document. GetByIdentity returns a READY snapshot when +// one exists; otherwise it returns the best available diagnostic snapshot. +type Repository interface { + GetByToken(context.Context, string) (*capability.Snapshot, error) + GetByIdentity(context.Context, capability.SnapshotIdentity) (*capability.Snapshot, error) + Put(context.Context, capability.Snapshot) (*capability.Snapshot, error) +} + +// Store is retained as a short name for callers that use stores throughout +// the rest of Explorer. +type Store = Repository + +type identityKey struct { + Identity capability.SnapshotIdentity +} + +// MemoryStore is a concurrency-safe, defensive-copy repository for tests and +// local deployments. The values held by the store are never handed directly +// to callers. +type MemoryStore struct { + mu sync.RWMutex + byToken map[string]capability.Snapshot + byIdentity map[identityKey]map[string]struct{} +} + +func NewMemoryStore() *MemoryStore { + return &MemoryStore{byToken: make(map[string]capability.Snapshot), byIdentity: make(map[identityKey]map[string]struct{})} +} + +func NewMemoryRepository() *MemoryStore { return NewMemoryStore() } + +func (s *MemoryStore) Put(ctx context.Context, snapshot capability.Snapshot) (*capability.Snapshot, error) { + if err := contextErr(ctx); err != nil { + return nil, err + } + if err := validate(snapshot); err != nil { + return nil, err + } + + s.mu.Lock() + defer s.mu.Unlock() + if previous, ok := s.byToken[snapshot.Token]; ok { + if !bytes.Equal(previous.CanonicalPayload(), snapshot.CanonicalPayload()) { + return nil, fmt.Errorf("%w: %s", ErrTokenCollision, snapshot.Token) + } + out := clone(previous) + return &out, nil + } + + stored := clone(snapshot) + s.byToken[stored.Token] = stored + key := identityKey{Identity: stored.Identity} + if s.byIdentity[key] == nil { + s.byIdentity[key] = make(map[string]struct{}) + } + s.byIdentity[key][stored.Token] = struct{}{} + out := clone(stored) + return &out, nil +} + +func (s *MemoryStore) GetByToken(ctx context.Context, token string) (*capability.Snapshot, error) { + if err := contextErr(ctx); err != nil { + return nil, err + } + s.mu.RLock() + defer s.mu.RUnlock() + value, ok := s.byToken[token] + if !ok { + return nil, ErrNotFound + } + out := clone(value) + return &out, nil +} + +func (s *MemoryStore) GetByIdentity(ctx context.Context, identity capability.SnapshotIdentity) (*capability.Snapshot, error) { + if err := contextErr(ctx); err != nil { + return nil, err + } + s.mu.RLock() + defer s.mu.RUnlock() + tokens := s.byIdentity[identityKey{Identity: identity}] + if len(tokens) == 0 { + return nil, ErrNotFound + } + ordered := make([]string, 0, len(tokens)) + for token := range tokens { + ordered = append(ordered, token) + } + sort.Strings(ordered) + for _, status := range []capability.Status{capability.StatusReady, capability.StatusBuilding, capability.StatusFailed} { + for _, token := range ordered { + value := s.byToken[token] + if value.Status == status { + out := clone(value) + return &out, nil + } + } + } + return nil, ErrNotFound +} + +func validate(snapshot capability.Snapshot) error { + if snapshot.Token == "" { + return fmt.Errorf("%w: token is required", ErrInvalidSnapshot) + } + if snapshot.Status == capability.StatusReady && !snapshot.Usable() { + return fmt.Errorf("%w: READY snapshot must be complete and not truncated", ErrInvalidSnapshot) + } + want := snapshotToken(snapshot) + if snapshot.Token != want { + return fmt.Errorf("%w: token does not match canonical snapshot content", ErrInvalidSnapshot) + } + return nil +} + +// ValidateSnapshot applies the repository invariants without requiring a +// caller to select a particular adapter. +func ValidateSnapshot(snapshot capability.Snapshot) error { return validate(snapshot) } + +func snapshotToken(snapshot capability.Snapshot) string { + sum := sha256.Sum256(snapshot.CanonicalPayload()) + return "sha256:" + hex.EncodeToString(sum[:]) +} + +func contextErr(ctx context.Context) error { + if ctx == nil { + return nil + } + select { + case <-ctx.Done(): + return ctx.Err() + default: + return nil + } +} + +func clone(in capability.Snapshot) capability.Snapshot { + out := in.Clone() + for i := range out.Diagnostics { + out.Diagnostics[i].Details = cloneDetails(out.Diagnostics[i].Details) + } + return out +} + +// cloneDetails recursively copies JSON-like diagnostic values. Snapshot.Clone +// already copies the outer map; this closes the less obvious alias through a +// nested map or slice in Details. +func cloneDetails(in map[string]any) map[string]any { + if in == nil { + return nil + } + out := make(map[string]any, len(in)) + for key, value := range in { + cloned := cloneValue(reflect.ValueOf(value)) + if cloned.IsValid() { + out[key] = cloned.Interface() + } else { + out[key] = nil + } + } + return out +} + +func cloneValue(value reflect.Value) reflect.Value { + if !value.IsValid() { + return reflect.ValueOf((*any)(nil)).Elem() + } + switch value.Kind() { + case reflect.Interface: + if value.IsNil() { + return reflect.Zero(value.Type()) + } + copied := cloneValue(value.Elem()) + out := reflect.New(value.Type()).Elem() + out.Set(copied) + return out + case reflect.Map: + if value.IsNil() { + return reflect.Zero(value.Type()) + } + out := reflect.MakeMapWithSize(value.Type(), value.Len()) + iter := value.MapRange() + for iter.Next() { + out.SetMapIndex(cloneValue(iter.Key()), cloneValue(iter.Value())) + } + return out + case reflect.Slice: + if value.IsNil() { + return reflect.Zero(value.Type()) + } + out := reflect.MakeSlice(value.Type(), value.Len(), value.Len()) + reflect.Copy(out, value) + for i := 0; i < out.Len(); i++ { + out.Index(i).Set(cloneValue(value.Index(i))) + } + return out + case reflect.Pointer: + if value.IsNil() { + return reflect.Zero(value.Type()) + } + out := reflect.New(value.Type().Elem()) + out.Elem().Set(cloneValue(value.Elem())) + return out + default: + return value + } +} + +var _ Repository = (*MemoryStore)(nil) diff --git a/internal/explorer/capabilitystore/repository_test.go b/internal/explorer/capabilitystore/repository_test.go new file mode 100644 index 00000000..9aa5ed12 --- /dev/null +++ b/internal/explorer/capabilitystore/repository_test.go @@ -0,0 +1,92 @@ +package capabilitystore + +import ( + "context" + "errors" + "testing" + + "github.com/calypr/loom/internal/explorer/capability" +) + +func testSnapshot(status capability.Status, complete bool) capability.Snapshot { + return capability.NewSnapshot( + capability.SnapshotIdentity{ + Project: "project-a", Generation: "generation-a", AuthorizationScopeDigest: "scope-a", + SchemaDigest: "schema-a", RelationshipDigest: "relationship-a", FieldDigest: "field-a", + ProtocolVersion: "protocol-a", CompilerVersion: "compiler-a", TraversalPolicyVersion: "traversal-a", ProjectionPolicyVersion: "projection-a", + }, + capability.Policy{Route: capability.RoutePolicy{Version: "route-a"}, Projection: capability.ProjectionPolicy{Version: "projection-a", Modes: []capability.ProjectionMode{capability.ProjectionFirst}}}, + status, complete, false, + []capability.Node{{ID: "node-a", ResourceType: "Patient", RowRootEligible: true, SupportedOperations: []capability.Operation{capability.OperationSelect}}}, + nil, nil, + []capability.Diagnostic{{Code: "notice", Message: "kept", Details: map[string]any{"nested": map[string]any{"value": "original"}}}}, + ) +} + +func TestMemoryStoreIsIdempotentAndDefensive(t *testing.T) { + ctx := context.Background() + store := NewMemoryStore() + want := testSnapshot(capability.StatusReady, true) + got, err := store.Put(ctx, want) + if err != nil { + t.Fatal(err) + } + got.Nodes[0].SupportedOperations[0] = capability.OperationFilter + got.Diagnostics[0].Details["nested"].(map[string]any)["value"] = "changed" + gotAgain, err := store.Put(ctx, want) + if err != nil { + t.Fatal(err) + } + if gotAgain.Nodes[0].SupportedOperations[0] != capability.OperationSelect { + t.Fatal("Put returned an aliased node slice") + } + read, err := store.GetByToken(ctx, want.Token) + if err != nil { + t.Fatal(err) + } + if read.Diagnostics[0].Details["nested"].(map[string]any)["value"] != "original" { + t.Fatal("nested diagnostic data was aliased") + } + if read.Token != want.Token { + t.Fatalf("token=%q, want %q", read.Token, want.Token) + } +} + +func TestMemoryStoreIdentityPrefersReadyAndRetainsFailedDiagnostics(t *testing.T) { + ctx := context.Background() + store := NewMemoryStore() + failed := testSnapshot(capability.StatusFailed, false) + if _, err := store.Put(ctx, failed); err != nil { + t.Fatal(err) + } + got, err := store.GetByIdentity(ctx, failed.Identity) + if err != nil || got.Status != capability.StatusFailed { + t.Fatalf("failed lookup=(%v, %v)", got, err) + } + ready := testSnapshot(capability.StatusReady, true) + if _, err := store.Put(ctx, ready); err != nil { + t.Fatal(err) + } + got, err = store.GetByIdentity(ctx, ready.Identity) + if err != nil || got.Status != capability.StatusReady { + t.Fatalf("ready lookup=(%v, %v)", got, err) + } +} + +func TestMemoryStoreRejectsUnusableReadyAndTokenCollision(t *testing.T) { + ctx := context.Background() + store := NewMemoryStore() + unusable := testSnapshot(capability.StatusReady, false) + if _, err := store.Put(ctx, unusable); !errors.Is(err, ErrInvalidSnapshot) { + t.Fatalf("Put unusable READY error=%v", err) + } + first := testSnapshot(capability.StatusFailed, false) + if _, err := store.Put(ctx, first); err != nil { + t.Fatal(err) + } + collision := testSnapshot(capability.StatusReady, true) + collision.Token = first.Token + if _, err := store.Put(ctx, collision); !errors.Is(err, ErrInvalidSnapshot) { + t.Fatalf("Put token collision error=%v", err) + } +} diff --git a/internal/explorer/catalog.go b/internal/explorer/catalog.go index 593f2a44..a5169e40 100644 --- a/internal/explorer/catalog.go +++ b/internal/explorer/catalog.go @@ -23,13 +23,18 @@ type CatalogNode struct { type CatalogEdge struct{ ID, FromNodeID, ToNodeID, Label string } type CatalogSelection struct { - ID string - NodeID string - FieldRef string - Select string - LogicalType string - Filterable bool - Chartable bool + ID string + NodeID string + FieldRef string + Select string + LogicalType string + Cardinality string + ProjectionModes []string + DefaultProjectionMode string + FilterOperators []string + ChartOperations []string + Filterable bool + Chartable bool } // DiscoveryResult makes incomplete discovery explicit. Production catalog @@ -52,20 +57,31 @@ type CatalogSnapshot struct { } func NewCatalogSnapshot(project, generation, scope string, catalog Catalog, complete, truncated bool, diagnostics []Diagnostic) (CatalogSnapshot, error) { + return NewCatalogSnapshotWithSchema(project, generation, scope, "", catalog, complete, truncated, diagnostics) +} + +// NewCatalogSnapshotWithSchema is the compatibility snapshot constructor used +// while V1 authoring documents are migrated to compiler-owned capabilities. +// The schema digest is part of the content address: attaching it after token +// construction would allow a generated-schema change to reuse stale opaque +// node, edge, and selection IDs. +func NewCatalogSnapshotWithSchema(project, generation, scope, schemaDigest string, catalog Catalog, complete, truncated bool, diagnostics []Diagnostic) (CatalogSnapshot, error) { nodes := append([]CatalogNode(nil), catalog.Nodes...) sort.Slice(nodes, func(i, j int) bool { return nodes[i].ID < nodes[j].ID }) + edges := append([]CatalogEdge(nil), catalog.Edges...) + sort.Slice(edges, func(i, j int) bool { return edges[i].ID < edges[j].ID }) selectionIDs := make([]string, 0, len(catalog.Selections)) for id := range catalog.Selections { selectionIDs = append(selectionIDs, id) } sort.Strings(selectionIDs) identity := struct { - Project, Generation, Scope string - Nodes []CatalogNode - Edges []CatalogEdge - Selections []CatalogSelection - Complete, Truncated bool - }{Project: project, Generation: generation, Scope: scope, Nodes: nodes, Edges: append([]CatalogEdge(nil), catalog.Edges...), Complete: complete, Truncated: truncated} + Project, Generation, Scope, SchemaDigest string + Nodes []CatalogNode + Edges []CatalogEdge + Selections []CatalogSelection + Complete, Truncated bool + }{Project: project, Generation: generation, Scope: scope, SchemaDigest: schemaDigest, Nodes: nodes, Edges: edges, Complete: complete, Truncated: truncated} for _, id := range selectionIDs { identity.Selections = append(identity.Selections, catalog.Selections[id]) } @@ -74,7 +90,7 @@ func NewCatalogSnapshot(project, generation, scope string, catalog Catalog, comp return CatalogSnapshot{}, err } sum := sha256.Sum256(raw) - return CatalogSnapshot{Project: project, Generation: generation, AuthorizationScopeDigest: scope, Catalog: catalog, Complete: complete, Truncated: truncated, Diagnostics: append([]Diagnostic(nil), diagnostics...), Token: "sha256:" + hex.EncodeToString(sum[:])}, nil + return CatalogSnapshot{Project: project, Generation: generation, AuthorizationScopeDigest: scope, Catalog: catalog, ResolvedSchemaDigest: schemaDigest, Complete: complete, Truncated: truncated, Diagnostics: append([]Diagnostic(nil), diagnostics...), Token: "sha256:" + hex.EncodeToString(sum[:])}, nil } func (s CatalogSnapshot) ValidateToken(token string) error { if token == "" || token != s.Token { diff --git a/internal/explorer/catalog_test.go b/internal/explorer/catalog_test.go index 6be288c6..41de1d47 100644 --- a/internal/explorer/catalog_test.go +++ b/internal/explorer/catalog_test.go @@ -20,3 +20,21 @@ func TestCatalogSnapshotBindsIdentityAndBlocksIncompleteDiscovery(t *testing.T) t.Fatalf("err=%v", err) } } + +func TestCatalogSnapshotTokenBindsResolvedSchemaDigest(t *testing.T) { + catalog := Catalog{Selections: map[string]CatalogSelection{}} + a, err := NewCatalogSnapshotWithSchema("p", "g", "scope", "schema-a", catalog, true, false, nil) + if err != nil { + t.Fatal(err) + } + b, err := NewCatalogSnapshotWithSchema("p", "g", "scope", "schema-b", catalog, true, false, nil) + if err != nil { + t.Fatal(err) + } + if a.Token == b.Token { + t.Fatalf("schema-specific snapshots reused token %q", a.Token) + } + if a.ResolvedSchemaDigest != "schema-a" || b.ResolvedSchemaDigest != "schema-b" { + t.Fatalf("schema digests were not retained: a=%q b=%q", a.ResolvedSchemaDigest, b.ResolvedSchemaDigest) + } +} diff --git a/internal/explorer/compilation.go b/internal/explorer/compilation.go index a8803d22..72fea38c 100644 --- a/internal/explorer/compilation.go +++ b/internal/explorer/compilation.go @@ -17,9 +17,16 @@ type Compilation struct { } type EmittedColumn struct { - OutputID, NodeID, SelectionID, PublicColumn string - LogicalType string - Filterable, Chartable bool + EmissionID string `json:"emissionId"` + OutputID string `json:"outputId"` + NodeID string `json:"nodeId,omitempty"` + SelectionID string `json:"selectionId,omitempty"` + CandidateID string `json:"candidateId,omitempty"` + OccurrenceID string `json:"occurrenceId,omitempty"` + PublicColumn string `json:"publicColumn"` + LogicalType string `json:"logicalType"` + Filterable bool `json:"filterable"` + Chartable bool `json:"chartable"` } func OpaqueID(prefix, identity string) string { diff --git a/internal/explorer/compilation/translate.go b/internal/explorer/compilation/translate.go new file mode 100644 index 00000000..1d128d53 --- /dev/null +++ b/internal/explorer/compilation/translate.go @@ -0,0 +1,503 @@ +// Package compilation translates the V2 Builder intent into the persistence- +// neutral recipe understood by the dataframe compiler. It deliberately has +// no HTTP, store, or server dependencies: a capability snapshot is the only +// authority consulted while compiling an intent. +package compilation + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "fmt" + "regexp" + "sort" + "strings" + + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataframe/spec" + "github.com/calypr/loom/internal/explorer/authoringv2" + "github.com/calypr/loom/internal/explorer/capability" +) + +const TranslationVersion = "authoring-v2-native-1" + +// Error is a structured translation failure. Stage, Code, Path, and Details +// are intentionally transport-neutral so an HTTP adapter can map it to its +// own diagnostic envelope without parsing an error string. +type Error struct { + Stage string + Code string + Path string + Message string + Details map[string]any + Cause error +} + +func (e *Error) Error() string { + if e == nil { + return "compilation error" + } + if e.Path == "" { + return e.Code + ": " + e.Message + } + return e.Code + " at " + e.Path + ": " + e.Message +} +func (e *Error) Unwrap() error { + if e == nil { + return nil + } + return e.Cause +} + +func fail(stage, code, path, message string, details map[string]any, cause error) error { + return &Error{Stage: stage, Code: code, Path: path, Message: message, Details: details, Cause: cause} +} + +// EmittedColumn is the immutable public output-column contract generated for +// one candidate occurrence. It intentionally mirrors the useful subset of +// explorer.EmittedColumn without importing the parent Explorer package. +type EmittedColumn struct { + EmissionID string `json:"emissionId"` + OutputID string `json:"outputId"` + NodeID string `json:"nodeId,omitempty"` + SelectionID string `json:"selectionId,omitempty"` + CandidateID string `json:"candidateId,omitempty"` + OccurrenceID string `json:"occurrenceId,omitempty"` + PublicColumn string `json:"publicColumn"` + LogicalType string `json:"logicalType"` + Filterable bool `json:"filterable"` + Chartable bool `json:"chartable"` +} + +type IdentityMapping struct { + CandidateID string `json:"candidateId"` + OccurrenceID string `json:"occurrenceId"` + EmissionIDs []string `json:"emissionIds"` +} + +// PresentationConfig is compiler-owned presentation data. The Builder may +// provide labels, visibility, and order, but never executable selectors. +type PresentationConfig struct { + OutputID string `json:"outputId"` + Title string `json:"title"` + Columns []PresentationColumn `json:"columns"` +} +type PresentationColumn struct { + EmissionID string `json:"emissionId"` + PublicColumn string `json:"publicColumn"` + Label string `json:"label"` + Visible bool `json:"visible"` + Order int `json:"order"` +} + +type OutputColumn struct { + EmissionID string `json:"emissionId"` + PublicColumn string `json:"publicColumn"` + CandidateID string `json:"candidateId"` + OccurrenceID string `json:"occurrenceId"` + LogicalType string `json:"logicalType"` + Filterable bool `json:"filterable"` + Chartable bool `json:"chartable"` +} +type OutputContract struct { + OutputID string `json:"outputId"` + Columns []OutputColumn `json:"columns"` +} + +// Result is a complete, deterministic native compilation artifact. +type Result struct { + Bundle recipe.Bundle + RecipeDigest string + EmittedColumns []EmittedColumn + IdentityMappings []IdentityMapping + Presentation PresentationConfig + OutputContract OutputContract +} + +// Compilation is a descriptive alias for callers that use the domain term +// rather than the translation verb. +type Compilation = Result + +// Compile translates one V2 document against the exact capability snapshot. +// It performs no catalog discovery, probing, profiling, or recipe execution. +func Compile(ctx context.Context, project, explorerID string, document authoringv2.Document, snapshot capability.Snapshot) (Result, error) { + if err := contextErr(ctx); err != nil { + return Result{}, err + } + project = strings.TrimSpace(project) + explorerID = strings.TrimSpace(explorerID) + if project == "" { + return Result{}, fail("protocol", "PROJECT_REQUIRED", "$.project", "project is required", nil, nil) + } + if explorerID == "" { + return Result{}, fail("protocol", "EXPLORER_REQUIRED", "$.explorerId", "explorerId is required", nil, nil) + } + if err := snapshot.ValidateToken(snapshot.Token); err != nil { + return Result{}, fail("capability", "CAPABILITY_SNAPSHOT_UNUSABLE", "$.snapshot", "capability snapshot is unavailable or stale", map[string]any{"token": snapshot.Token}, err) + } + if snapshot.Identity.Project != project { + return Result{}, fail("capability", "PROJECT_MISMATCH", "$.project", "capability snapshot belongs to a different project", map[string]any{"snapshotProject": snapshot.Identity.Project, "project": project}, nil) + } + if err := document.Validate(); err != nil { + return Result{}, fail("intent", "INVALID_DOCUMENT", "$", err.Error(), nil, err) + } + if err := validateSnapshot(snapshot); err != nil { + return Result{}, err + } + occurrences, routeEdges, err := resolveRoute(document, snapshot) + if err != nil { + return Result{}, err + } + if err := validateSelections(document, snapshot, occurrences); err != nil { + return Result{}, err + } + + root := occurrences[0] + rowGrain, ok := spec.InferRowGrain(root.ResourceType) + if !ok || !root.RowRootEligible { + return Result{}, fail("lower", "UNSUPPORTED_ROW_ROOT", "$.rootNodeId", "root node is not an eligible recipe row root", map[string]any{"nodeId": root.ID, "resourceType": root.ResourceType}, nil) + } + assignments := make([]assignment, 0, len(document.Selections)) + seenPairs := map[string]bool{} + for i, selection := range document.Selections { + occurrenceID := selection.OccurrenceID + if occurrenceID == "" { + occurrenceID = occurrences[len(occurrences)-1].ID + } + candidate, _ := snapshot.Candidate(selection.CandidateID) + key := selection.CandidateID + "\x00" + occurrenceID + if seenPairs[key] { + return Result{}, fail("intent", "DUPLICATE_SELECTION", fmt.Sprintf("$.selections[%d]", i), "candidate occurrence is selected more than once", map[string]any{"candidateId": selection.CandidateID, "occurrenceId": occurrenceID}, nil) + } + seenPairs[key] = true + assignments = append(assignments, assignment{Selection: selection, Candidate: candidate, OccurrenceID: occurrenceID}) + } + // Route order is semantic; candidate order within an occurrence is stable + // by ID so receipt identity does not depend on browser array ordering. + sort.SliceStable(assignments, func(i, j int) bool { + ai, aj := occurrenceIndex(occurrences, assignments[i].OccurrenceID), occurrenceIndex(occurrences, assignments[j].OccurrenceID) + if ai != aj { + return ai < aj + } + return assignments[i].Candidate.ID < assignments[j].Candidate.ID + }) + + emitted := make([]EmittedColumn, 0, len(assignments)) + mappings := make([]IdentityMapping, 0, len(assignments)) + byPair := map[string]*IdentityMapping{} + fieldsByOccurrence := map[string][]recipe.Field{} + for _, a := range assignments { + public := generatedID("c_", a.Candidate.ID+"\x00"+a.OccurrenceID) + emission := generatedID("em_", document.Output.ID+"\x00"+a.OccurrenceID+"\x00"+a.Candidate.ID) + column := EmittedColumn{EmissionID: emission, OutputID: document.Output.ID, NodeID: a.Candidate.NodeID, SelectionID: a.Candidate.ID, CandidateID: a.Candidate.ID, OccurrenceID: a.OccurrenceID, PublicColumn: public, LogicalType: a.Candidate.LogicalType, Filterable: supportsOperation(a.Candidate.SupportedOperations, capability.OperationFilter), Chartable: supportsOperation(a.Candidate.SupportedOperations, capability.OperationChart)} + emitted = append(emitted, column) + pair := a.Candidate.ID + "\x00" + a.OccurrenceID + if byPair[pair] == nil { + mappings = append(mappings, IdentityMapping{CandidateID: a.Candidate.ID, OccurrenceID: a.OccurrenceID}) + byPair[pair] = &mappings[len(mappings)-1] + } + byPair[pair].EmissionIDs = append(byPair[pair].EmissionIDs, emission) + alias := "root" + if idx := occurrenceIndex(occurrences, a.OccurrenceID); idx > 0 { + alias = routeAlias(idx - 1) + } + fieldPath := strings.TrimPrefix(strings.TrimSpace(a.Candidate.FieldPath), "root.") + fieldsByOccurrence[a.OccurrenceID] = append(fieldsByOccurrence[a.OccurrenceID], recipe.Field{Name: public, FieldRef: a.Candidate.FieldPath, Expr: recipe.Expression{Select: alias + "." + fieldPath}, ValueMode: projectionValueMode(a.Selection.ProjectionMode)}) + } + + output := recipe.Output{Name: document.Output.ID, RootResourceType: root.ResourceType, RowGrain: string(rowGrain), Fields: fieldsByOccurrence[authoringv2.RootOccurrenceID]} + var lowerRoute func(int) []recipe.Traversal + lowerRoute = func(i int) []recipe.Traversal { + if i >= len(routeEdges) { + return nil + } + item := recipe.Traversal{ + Name: recipeName(routeEdges[i].Label, routeEdges[i].ID), + Alias: routeAlias(i), + ToResourceType: occurrences[i+1].ResourceType, + MatchMode: recipe.MatchOptional, + Fields: fieldsByOccurrence[occurrences[i+1].ID], + Traversals: lowerRoute(i + 1), + } + return []recipe.Traversal{item} + } + output.Traversals = lowerRoute(0) + bundle := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "explorer_" + safeName(project) + "_" + safeName(explorerID), TranslationVersion: TranslationVersion, Outputs: []recipe.Output{output}} + if err := bundle.Validate(); err != nil { + return Result{}, fail("lower", "INVALID_RECIPE", "$.recipe", err.Error(), nil, err) + } + digest, err := bundle.Digest() + if err != nil { + return Result{}, fail("lower", "RECIPE_DIGEST_FAILED", "$.recipe", "recipe digest could not be calculated", nil, err) + } + presentation, err := makePresentation(document, emitted) + if err != nil { + return Result{}, err + } + contract := OutputContract{OutputID: document.Output.ID} + for _, c := range emitted { + contract.Columns = append(contract.Columns, OutputColumn{EmissionID: c.EmissionID, PublicColumn: c.PublicColumn, CandidateID: c.CandidateID, OccurrenceID: c.OccurrenceID, LogicalType: c.LogicalType, Filterable: c.Filterable, Chartable: c.Chartable}) + } + return Result{Bundle: bundle, RecipeDigest: digest, EmittedColumns: emitted, IdentityMappings: mappings, Presentation: presentation, OutputContract: contract}, nil +} + +func Translate(project, explorerID string, document authoringv2.Document, snapshot capability.Snapshot) (Result, error) { + return Compile(context.Background(), project, explorerID, document, snapshot) +} + +type occurrence struct { + ID, NodeID, ResourceType string + RowRootEligible bool +} +type assignment struct { + Selection authoringv2.Selection + Candidate capability.Candidate + OccurrenceID string +} + +func validateSnapshot(s capability.Snapshot) error { + nodes := map[string]capability.Node{} + for i, n := range s.Nodes { + if strings.TrimSpace(n.ID) == "" || strings.TrimSpace(n.ResourceType) == "" { + return fail("capability", "INVALID_NODE", fmt.Sprintf("$.snapshot.nodes[%d]", i), "node id and resourceType are required", nil, nil) + } + if _, ok := nodes[n.ID]; ok { + return fail("capability", "DUPLICATE_NODE", fmt.Sprintf("$.snapshot.nodes[%d]", i), "duplicate node id", map[string]any{"nodeId": n.ID}, nil) + } + nodes[n.ID] = n + } + edges := map[string]bool{} + for i, e := range s.Edges { + if e.ID == "" || nodes[e.FromNodeID].ID == "" || nodes[e.ToNodeID].ID == "" || strings.TrimSpace(e.Label) == "" { + return fail("capability", "INVALID_EDGE", fmt.Sprintf("$.snapshot.edges[%d]", i), "edge has stale endpoints or empty label", nil, nil) + } + if edges[e.ID] { + return fail("capability", "DUPLICATE_EDGE", fmt.Sprintf("$.snapshot.edges[%d]", i), "duplicate edge id", map[string]any{"edgeId": e.ID}, nil) + } + edges[e.ID] = true + } + candidates := map[string]bool{} + for i, c := range s.Candidates { + if c.ID == "" || nodes[c.NodeID].ID == "" || strings.TrimSpace(c.FieldPath) == "" { + return fail("capability", "INVALID_CANDIDATE", fmt.Sprintf("$.snapshot.candidates[%d]", i), "candidate has stale node or empty field path", nil, nil) + } + if candidates[c.ID] { + return fail("capability", "DUPLICATE_CANDIDATE", fmt.Sprintf("$.snapshot.candidates[%d]", i), "duplicate candidate id", map[string]any{"candidateId": c.ID}, nil) + } + candidates[c.ID] = true + } + return nil +} + +func resolveRoute(d authoringv2.Document, s capability.Snapshot) ([]occurrence, []capability.Edge, error) { + nodes := map[string]capability.Node{} + for _, n := range s.Nodes { + nodes[n.ID] = n + } + root, ok := nodes[d.RootNodeID] + if !ok { + return nil, nil, fail("route", "STALE_ROOT_NODE", "$.rootNodeId", "root node is not in the capability snapshot", map[string]any{"nodeId": d.RootNodeID}, nil) + } + if !root.RowRootEligible { + return nil, nil, fail("route", "ROOT_NOT_ELIGIBLE", "$.rootNodeId", "root node is not row-root eligible", nil, nil) + } + edges := map[string]capability.Edge{} + for _, e := range s.Edges { + edges[e.ID] = e + } + occ := []occurrence{{ID: authoringv2.RootOccurrenceID, NodeID: root.ID, ResourceType: root.ResourceType, RowRootEligible: root.RowRootEligible}} + path := []capability.Edge{} + seen := map[string]bool{} + seenOccurrences := map[string]bool{authoringv2.RootOccurrenceID: true} + current := root.ID + for i, step := range d.RouteSteps { + e, ok := edges[step.EdgeID] + if !ok { + return nil, nil, fail("route", "STALE_EDGE", fmt.Sprintf("$.routeSteps[%d].edgeId", i), "route edge is not in the capability snapshot", map[string]any{"edgeId": step.EdgeID}, nil) + } + if e.FromNodeID != current { + return nil, nil, fail("route", "DISCONNECTED_ROUTE", fmt.Sprintf("$.routeSteps[%d]", i), "route edge does not start at the current occurrence node", map[string]any{"expectedNodeId": current, "actualNodeId": e.FromNodeID}, nil) + } + if seen[e.ID] && !s.Policy.Route.AllowsRepeatedEdges { + return nil, nil, fail("route", "REPEATED_EDGE_NOT_ALLOWED", fmt.Sprintf("$.routeSteps[%d].edgeId", i), "route policy does not allow repeated edges", nil, nil) + } + if e.FromNodeID == e.ToNodeID && !s.Policy.Route.AllowsSelfLoops { + return nil, nil, fail("route", "SELF_LOOP_NOT_ALLOWED", fmt.Sprintf("$.routeSteps[%d].edgeId", i), "route policy does not allow self-loops", nil, nil) + } + seen[e.ID] = true + id := step.OccurrenceID + if id == "" { + id = authoringv2.DerivedOccurrenceID(i) + } + if seenOccurrences[id] { + return nil, nil, fail("route", "DUPLICATE_OCCURRENCE", fmt.Sprintf("$.routeSteps[%d].occurrenceId", i), "route occurrence id is not unique", map[string]any{"occurrenceId": id}, nil) + } + seenOccurrences[id] = true + n := nodes[e.ToNodeID] + occ = append(occ, occurrence{ID: id, NodeID: n.ID, ResourceType: n.ResourceType, RowRootEligible: n.RowRootEligible}) + path = append(path, e) + current = e.ToNodeID + } + if s.Policy.Route.MaxHops > 0 && len(path) > s.Policy.Route.MaxHops { + return nil, nil, fail("route", "ROUTE_TOO_LONG", "$.routeSteps", "route exceeds capability route policy", map[string]any{"maxHops": s.Policy.Route.MaxHops, "hops": len(path)}, nil) + } + return occ, path, nil +} + +func validateSelections(d authoringv2.Document, s capability.Snapshot, occ []occurrence) error { + byOcc := map[string]occurrence{} + for _, o := range occ { + byOcc[o.ID] = o + } + tail := occ[len(occ)-1].ID + for i, sel := range d.Selections { + c, ok := s.Candidate(sel.CandidateID) + if !ok { + return fail("intent", "STALE_CANDIDATE", fmt.Sprintf("$.selections[%d].candidateId", i), "candidate is not in the capability snapshot", map[string]any{"candidateId": sel.CandidateID}, nil) + } + id := sel.OccurrenceID + if id == "" { + id = tail + } + o, ok := byOcc[id] + if !ok { + return fail("intent", "STALE_OCCURRENCE", fmt.Sprintf("$.selections[%d].occurrenceId", i), "selection occurrence is not in the route", map[string]any{"occurrenceId": id}, nil) + } + if c.NodeID != o.NodeID { + return fail("intent", "SELECTION_NODE_MISMATCH", fmt.Sprintf("$.selections[%d]", i), "candidate does not belong to the selected route occurrence", map[string]any{"candidateNodeId": c.NodeID, "occurrenceNodeId": o.NodeID}, nil) + } + allowed := false + for _, m := range c.ProjectionModes { + if strings.EqualFold(string(m), sel.ProjectionMode) { + allowed = true + break + } + } + if !allowed { + return fail("intent", "UNSUPPORTED_PROJECTION_MODE", fmt.Sprintf("$.selections[%d].projectionMode", i), "projection mode is not advertised by the capability snapshot", map[string]any{"candidateId": c.ID, "projectionMode": sel.ProjectionMode, "supported": c.ProjectionModes}, nil) + } + } + return nil +} + +func occurrenceIndex(all []occurrence, id string) int { + for i, o := range all { + if o.ID == id { + return i + } + } + return -1 +} +func routeAlias(i int) string { return fmt.Sprintf("route_%d", i) } +func supportsOperation(items []capability.Operation, want capability.Operation) bool { + for _, v := range items { + if v == want { + return true + } + } + return false +} +func projectionValueMode(mode string) recipe.ValueMode { + switch strings.ToUpper(strings.TrimSpace(mode)) { + case string(capability.ProjectionFirst): + return recipe.ValueModeFirst + case string(capability.ProjectionArray): + return recipe.ValueModeAll + case string(capability.ProjectionDistinctArray): + return recipe.ValueModeDistinct + default: + return recipe.ValueModeAuto + } +} + +var namePattern = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*$`) + +func recipeName(label, id string) string { + if namePattern.MatchString(label) { + return label + } + return "edge_" + shortHash(id) +} +func safeName(s string) string { + var b strings.Builder + for _, r := range strings.ToLower(s) { + if r >= 'a' && r <= 'z' || r >= '0' && r <= '9' || r == '_' { + b.WriteRune(r) + } else { + b.WriteByte('_') + } + } + v := strings.Trim(b.String(), "_") + if v == "" { + return "x" + } + if v[0] >= '0' && v[0] <= '9' { + return "x_" + v + } + return v +} +func shortHash(s string) string { + sum := sha256.Sum256([]byte(s)) + return hex.EncodeToString(sum[:])[:16] +} +func generatedID(prefix, s string) string { return prefix + shortHash(s) } +func contextErr(ctx context.Context) error { + if ctx == nil { + return nil + } + select { + case <-ctx.Done(): + return fail("compile", "CONTEXT_CANCELED", "$", ctx.Err().Error(), nil, ctx.Err()) + default: + return nil + } +} + +func makePresentation(d authoringv2.Document, emitted []EmittedColumn) (PresentationConfig, error) { + result := PresentationConfig{OutputID: d.Output.ID, Title: d.Output.Title, Columns: make([]PresentationColumn, 0, len(emitted))} + byKey := map[string][]int{} + for i, c := range emitted { + byKey[c.EmissionID] = append(byKey[c.EmissionID], i) + byKey[c.CandidateID] = append(byKey[c.CandidateID], i) + byKey[c.CandidateID+"\x00"+c.OccurrenceID] = append(byKey[c.CandidateID+"\x00"+c.OccurrenceID], i) + } + for i, c := range emitted { + p := authoringv2.Presentation{} + if raw, ok := d.Presentation[c.EmissionID]; ok { + p = raw + } else if raw, ok := d.Presentation[c.CandidateID+"\x00"+c.OccurrenceID]; ok { + p = raw + } else if raw, ok := d.Presentation[c.CandidateID]; ok { + if len(byKey[c.CandidateID]) > 1 { + return PresentationConfig{}, fail("presentation", "AMBIGUOUS_PRESENTATION", "$.presentation."+c.CandidateID, "presentation key matches multiple candidate occurrences", nil, nil) + } + p = raw + } + label := c.PublicColumn + if strings.TrimSpace(p.Label) != "" { + label = p.Label + } + visible := true + if p.Visible != nil { + visible = *p.Visible + } + order := i + if p.Order != nil { + order = *p.Order + } + result.Columns = append(result.Columns, PresentationColumn{EmissionID: c.EmissionID, PublicColumn: c.PublicColumn, Label: label, Visible: visible, Order: order}) + } + for key := range d.Presentation { + found := false + for _, c := range emitted { + if key == c.EmissionID || key == c.CandidateID || key == c.CandidateID+"\x00"+c.OccurrenceID { + found = true + break + } + } + if !found { + return PresentationConfig{}, fail("presentation", "STALE_PRESENTATION", "$.presentation."+key, "presentation references an unselected emission", map[string]any{"key": key}, nil) + } + } + return result, nil +} diff --git a/internal/explorer/compilation/translate_test.go b/internal/explorer/compilation/translate_test.go new file mode 100644 index 00000000..ddf908b7 --- /dev/null +++ b/internal/explorer/compilation/translate_test.go @@ -0,0 +1,110 @@ +package compilation + +import ( + "context" + "errors" + "fmt" + "strings" + "testing" + + "github.com/calypr/loom/internal/explorer/authoringv2" + "github.com/calypr/loom/internal/explorer/capability" +) + +func fixtureSnapshot() capability.Snapshot { + identity := capability.SnapshotIdentity{Project: "project-a", Generation: "generation-a", AuthorizationScopeDigest: "scope-a", SchemaDigest: "schema-a", CompilerVersion: "compiler-a"} + policy := capability.Policy{Route: capability.RoutePolicy{Version: "route-a", AllowsRepeatedEdges: true, AllowsSelfLoops: true}, Projection: capability.ProjectionPolicy{Version: "projection-a", Modes: []capability.ProjectionMode{capability.ProjectionScalar, capability.ProjectionFirst, capability.ProjectionArray, capability.ProjectionDistinctArray}}} + nodes := []capability.Node{{ID: "n_patient", ResourceType: "Patient", RowRootEligible: true, RowGrain: "patient"}, {ID: "n_encounter", ResourceType: "Encounter", RowRootEligible: true, RowGrain: "resource"}} + edges := []capability.Edge{{ID: "e_encounter", FromNodeID: "n_patient", ToNodeID: "n_encounter", Label: "encounters"}, {ID: "e_self", FromNodeID: "n_encounter", ToNodeID: "n_encounter", Label: "revisits"}} + ops := []capability.Operation{capability.OperationSelect, capability.OperationFilter, capability.OperationChart} + candidates := []capability.Candidate{{ID: "c_patient_id", NodeID: "n_patient", ResourceType: "Patient", FieldPath: "id", LogicalType: "string", ProjectionModes: []capability.ProjectionMode{capability.ProjectionScalar}, SupportedOperations: ops}, {ID: "c_encounter_code", NodeID: "n_encounter", ResourceType: "Encounter", FieldPath: "code.coding[].code", LogicalType: "string", ProjectionModes: []capability.ProjectionMode{capability.ProjectionFirst, capability.ProjectionArray, capability.ProjectionDistinctArray}, SupportedOperations: ops}} + return capability.NewSnapshot(identity, policy, capability.StatusReady, true, false, nodes, edges, candidates, nil) +} + +func BenchmarkCompileRepresentativeBuilderState(b *testing.B) { + snapshot := fixtureSnapshot() + for candidateIndex := 0; candidateIndex < 5; candidateIndex++ { + snapshot.Candidates = append(snapshot.Candidates, capability.Candidate{ + ID: "c_encounter_" + fmt.Sprint(candidateIndex), NodeID: "n_encounter", + ResourceType: "Encounter", FieldPath: "subject.display" + fmt.Sprint(candidateIndex), + LogicalType: "string", ProjectionModes: []capability.ProjectionMode{capability.ProjectionFirst}, + SupportedOperations: []capability.Operation{capability.OperationSelect}, + }) + } + // NewSnapshot recomputes the token after extending the benchmark fixture. + snapshot = capability.NewSnapshot(snapshot.Identity, snapshot.Policy, capability.StatusReady, true, false, snapshot.Nodes, snapshot.Edges, snapshot.Candidates, nil) + document := authoringv2.Document{APIVersion: authoringv2.APIVersion, Kind: authoringv2.Kind, Output: authoringv2.Output{ID: "representative", Title: "Representative"}, RootNodeID: "n_patient", Presentation: map[string]authoringv2.Presentation{}} + for hop := 0; hop < 20; hop++ { + edgeID := "e_self" + if hop == 0 { + edgeID = "e_encounter" + } + occurrenceID := fmt.Sprintf("hop-%d", hop) + document.RouteSteps = append(document.RouteSteps, authoringv2.RouteStep{EdgeID: edgeID, OccurrenceID: occurrenceID}) + for candidateIndex := 0; candidateIndex < 5; candidateIndex++ { + document.Selections = append(document.Selections, authoringv2.Selection{CandidateID: "c_encounter_" + fmt.Sprint(candidateIndex), OccurrenceID: occurrenceID, ProjectionMode: "FIRST"}) + } + } + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + if _, err := Compile(context.Background(), "project-a", "explorer-a", document, snapshot); err != nil { + b.Fatal(err) + } + } +} + +func fixtureDocument() authoringv2.Document { + return authoringv2.Document{APIVersion: authoringv2.APIVersion, Kind: authoringv2.Kind, Output: authoringv2.Output{ID: "patient_output", Title: "Patients"}, RootNodeID: "n_patient", RouteSteps: []authoringv2.RouteStep{{EdgeID: "e_encounter", OccurrenceID: "encounter"}, {EdgeID: "e_self", OccurrenceID: "encounter_again"}}, Selections: []authoringv2.Selection{{CandidateID: "c_patient_id", OccurrenceID: "base", ProjectionMode: "SCALAR"}, {CandidateID: "c_encounter_code", OccurrenceID: "encounter_again", ProjectionMode: "DISTINCT_ARRAY"}}, Presentation: map[string]authoringv2.Presentation{"c_patient_id": {Label: "Patient ID"}}} +} + +func TestCompileNativeV2BuildsNestedRouteAndStableColumns(t *testing.T) { + snapshot := fixtureSnapshot() + result, err := Compile(context.Background(), "project-a", "explorer-a", fixtureDocument(), snapshot) + if err != nil { + t.Fatal(err) + } + if len(result.Bundle.Outputs) != 1 || len(result.Bundle.Outputs[0].Traversals) != 1 || len(result.Bundle.Outputs[0].Traversals[0].Traversals) != 1 { + t.Fatalf("route was not lowered as a nested chain: %#v", result.Bundle.Outputs[0].Traversals) + } + if got := result.Bundle.Outputs[0].Traversals[0].Traversals[0].Fields[0].ValueMode; got != "DISTINCT" { + t.Fatalf("projection value mode=%q", got) + } + if len(result.EmittedColumns) != 2 || result.EmittedColumns[0].EmissionID == result.EmittedColumns[1].EmissionID { + t.Fatalf("emissions=%#v", result.EmittedColumns) + } + if result.Presentation.Columns[0].Label != "Patient ID" || !result.Presentation.Columns[0].Visible { + t.Fatalf("presentation=%#v", result.Presentation) + } + again, err := Compile(context.Background(), "project-a", "explorer-a", fixtureDocument(), snapshot) + if err != nil || again.RecipeDigest != result.RecipeDigest || again.EmittedColumns[0].EmissionID != result.EmittedColumns[0].EmissionID { + t.Fatalf("compile is not stable: first=%#v again=%#v err=%v", result, again, err) + } +} + +func TestCompileAllowsRepeatedSelfLoopAndLongFiniteRoutes(t *testing.T) { + snapshot := fixtureSnapshot() + document := fixtureDocument() + for i := 0; i < 12; i++ { + document.RouteSteps = append(document.RouteSteps, authoringv2.RouteStep{EdgeID: "e_self", OccurrenceID: "loop-" + string(rune('a'+i))}) + } + document.Selections[1].OccurrenceID = "loop-l" + if _, err := Compile(context.Background(), "project-a", "explorer-a", document, snapshot); err != nil { + t.Fatal(err) + } +} + +func TestCompileRejectsMismatchesWithStructuredErrors(t *testing.T) { + document := fixtureDocument() + _, err := Compile(context.Background(), "other-project", "explorer-a", document, fixtureSnapshot()) + var structured *Error + if !errors.As(err, &structured) || structured.Code != "PROJECT_MISMATCH" || structured.Stage != "capability" || structured.Path != "$.project" { + t.Fatalf("error=%#v", err) + } + document = fixtureDocument() + document.Selections[0].ProjectionMode = "ARRAY" + _, err = Compile(context.Background(), "project-a", "explorer-a", document, fixtureSnapshot()) + if !errors.As(err, &structured) || structured.Code != "UNSUPPORTED_PROJECTION_MODE" || !strings.Contains(structured.Path, "projectionMode") { + t.Fatalf("projection error=%#v", err) + } +} diff --git a/internal/explorer/compilation_receipt.go b/internal/explorer/compilation_receipt.go new file mode 100644 index 00000000..ce14c078 --- /dev/null +++ b/internal/explorer/compilation_receipt.go @@ -0,0 +1,323 @@ +package explorer + +// This file contains the immutable boundary between Explorer authoring and +// execution. A receipt is a durable, server-owned description of one exact +// compilation. It deliberately contains a resolved semantic recipe, not +// physical plans, rendered AQL, bind variables, or storage identifiers. + +import ( + "crypto/sha256" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "strings" + "time" + + "github.com/calypr/loom/internal/dataframe/recipe" +) + +const ( + // CompilationReceiptFormatVersion changes when the persisted receipt shape + // or its execution invariants change incompatibly. + CompilationReceiptFormatVersion = 1 + // CompilationReceiptCompilerContractVersion changes when compilation + // semantics change in a way that can alter a resolved receipt. + CompilationReceiptCompilerContractVersion = "loom.explorer.compiler/v2" + + // Short aliases make the current contract convenient for repositories and + // callers that do not need to distinguish the receipt prefix. + CurrentReceiptFormatVersion = CompilationReceiptFormatVersion + CurrentCompilerContractVersion = CompilationReceiptCompilerContractVersion + CurrentCompilationContractVersion = CompilationReceiptCompilerContractVersion +) + +// ErrReceiptRecompileRequired is returned for an old receipt that has no +// resolved recipe artifact. Such a receipt cannot be safely upgraded by an +// execution request because doing so would reinterpret authoring intent. +var ErrReceiptRecompileRequired = errors.New("RECEIPT_RECOMPILE_REQUIRED") + +// CompilationArtifactDigest returns the content identity used for canonical +// JSON artifacts embedded in a receipt, such as the public output contract. +func CompilationArtifactDigest(raw json.RawMessage) (string, error) { + canonical, err := canonicalRaw(raw) + if err != nil { + return "", err + } + if len(canonical) == 0 { + return "", fmt.Errorf("compilation artifact is required") + } + sum := sha256.Sum256(canonical) + return "sha256:" + hex.EncodeToString(sum[:]), nil +} + +// CompilationReceipt is immutable once persisted and content-addressed by +// ReceiptID. NormalizedBundle is authoring intent retained for export and +// compatibility; Bundle is the resolved recipe used by execution. Neither +// field contains a physical IR or rendered query. +type CompilationReceipt struct { + ID string `json:"id"` + ReceiptFormatVersion int `json:"receiptFormatVersion"` + CompilerContractVersion string `json:"compilerContractVersion"` + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + IntentDigest string `json:"intentDigest"` + SnapshotToken string `json:"snapshotToken"` + AuthorizationScopeDigest string `json:"authorizationScopeDigest,omitempty"` + CapabilitySchemaDigest string `json:"capabilitySchemaDigest,omitempty"` + SourceGeneration string `json:"sourceGeneration"` + CompilationKey string `json:"compilationKey,omitempty"` + RecipeDigest string `json:"recipeDigest"` + ResolvedRecipeDigest string `json:"resolvedRecipeDigest,omitempty"` + ResolvedSchemaDigest string `json:"resolvedSchemaDigest,omitempty"` + OutputContractDigest string `json:"outputContractDigest,omitempty"` + NormalizedBundle json.RawMessage `json:"normalizedBundle"` + Bundle recipe.Bundle `json:"compiledRecipe"` + CompiledConfig json.RawMessage `json:"compiledConfig,omitempty"` + PublicOutputContract json.RawMessage `json:"publicOutputContract,omitempty"` + IdentityMappings []IdentityMapping `json:"identityMappings"` + EmittedColumns []EmittedColumn `json:"emittedColumns"` + OutputFingerprints map[string]string `json:"outputFingerprints,omitempty"` + Warnings []CompilationWarning `json:"warnings,omitempty"` + RequestID string `json:"requestId,omitempty"` + CreatedAt time.Time `json:"createdAt"` +} + +type IdentityMapping struct { + CandidateID string `json:"candidateId"` + OccurrenceID string `json:"occurrenceId"` + EmissionIDs []string `json:"emissionIds"` +} + +// CompilationWarning is the deterministic, request-independent diagnostic +// subset that can be frozen in a receipt. Request IDs and timestamps must not +// be included here because they would make equivalent receipts differ. +type CompilationWarning struct { + Severity string `json:"severity,omitempty"` + Code string `json:"code"` + Stage string `json:"stage,omitempty"` + FieldPath string `json:"fieldPath,omitempty"` + Message string `json:"message"` + Details map[string]any `json:"details,omitempty"` +} + +// CompilationKey returns the idempotency identity for one authoring request. +// It covers semantic inputs and compiler contracts, but not resolved output; +// this permits a repository lookup before doing the expensive compilation. +func CompilationKey(r CompilationReceipt) (string, error) { + identity := struct { + ReceiptFormatVersion int `json:"receiptFormatVersion"` + CompilerContractVersion string `json:"compilerContractVersion"` + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + IntentDigest string `json:"intentDigest"` + NormalizedBundle []byte `json:"normalizedBundle,omitempty"` + SnapshotToken string `json:"snapshotToken"` + AuthorizationScope string `json:"authorizationScopeDigest,omitempty"` + CapabilitySchema string `json:"capabilitySchemaDigest,omitempty"` + SourceGeneration string `json:"sourceGeneration"` + }{} + normalized, err := canonicalRaw(r.NormalizedBundle) + if err != nil { + return "", fmt.Errorf("canonical normalized bundle: %w", err) + } + identity = struct { + ReceiptFormatVersion int `json:"receiptFormatVersion"` + CompilerContractVersion string `json:"compilerContractVersion"` + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + IntentDigest string `json:"intentDigest"` + NormalizedBundle []byte `json:"normalizedBundle,omitempty"` + SnapshotToken string `json:"snapshotToken"` + AuthorizationScope string `json:"authorizationScopeDigest,omitempty"` + CapabilitySchema string `json:"capabilitySchemaDigest,omitempty"` + SourceGeneration string `json:"sourceGeneration"` + }{ + r.ReceiptFormatVersion, r.CompilerContractVersion, r.Project, r.ExplorerID, + r.IntentDigest, normalized, r.SnapshotToken, + r.AuthorizationScopeDigest, r.CapabilitySchemaDigest, r.SourceGeneration, + } + return digestIdentity("compile_", identity) +} + +// ReceiptID returns the content identity for the complete immutable artifact. +// ID, RequestID, and CreatedAt are intentionally excluded. +func ReceiptID(r CompilationReceipt) (string, error) { + key, err := CompilationKey(r) + if err != nil { + return "", err + } + compiledConfig, err := canonicalRaw(r.CompiledConfig) + if err != nil { + return "", fmt.Errorf("canonical compiled config: %w", err) + } + publicContract, err := canonicalRaw(r.PublicOutputContract) + if err != nil { + return "", fmt.Errorf("canonical public output contract: %w", err) + } + identity := struct { + CompilationKey string `json:"compilationKey"` + RecipeDigest string `json:"recipeDigest"` + ResolvedRecipeDigest string `json:"resolvedRecipeDigest,omitempty"` + ResolvedSchemaDigest string `json:"resolvedSchemaDigest,omitempty"` + OutputContractDigest string `json:"outputContractDigest,omitempty"` + Bundle recipe.Bundle `json:"compiledRecipe"` + CompiledConfig []byte `json:"compiledConfig,omitempty"` + PublicOutputContract []byte `json:"publicOutputContract,omitempty"` + Mappings []IdentityMapping `json:"identityMappings"` + Emissions []EmittedColumn `json:"emittedColumns"` + Fingerprints map[string]string `json:"outputFingerprints,omitempty"` + Warnings []CompilationWarning `json:"warnings,omitempty"` + }{ + key, r.RecipeDigest, r.ResolvedRecipeDigest, r.ResolvedSchemaDigest, + r.OutputContractDigest, r.Bundle, compiledConfig, + publicContract, r.IdentityMappings, r.EmittedColumns, + r.OutputFingerprints, r.Warnings, + } + return digestIdentity("receipt_", identity) +} + +func digestIdentity(prefix string, identity any) (string, error) { + raw, err := json.Marshal(identity) + if err != nil { + return "", err + } + canonical, err := canonicalJSONBytes(raw) + if err != nil { + return "", err + } + sum := sha256.Sum256(canonical) + return prefix + hex.EncodeToString(sum[:]), nil +} + +func canonicalRaw(raw json.RawMessage) ([]byte, error) { + if len(raw) == 0 { + return nil, nil + } + if strings.TrimSpace(string(raw)) == "null" { + return nil, nil + } + return canonicalJSONBytes(raw) +} + +// Validate checks that a receipt is a supported, executable artifact. +func (r CompilationReceipt) Validate() error { + if r.ReceiptFormatVersion != 0 && r.ReceiptFormatVersion != CompilationReceiptFormatVersion { + return fmt.Errorf("unsupported receipt format version %d", r.ReceiptFormatVersion) + } + if r.CompilerContractVersion != "" && r.CompilerContractVersion != CompilationReceiptCompilerContractVersion { + return fmt.Errorf("unsupported compiler contract %q", r.CompilerContractVersion) + } + if strings.TrimSpace(r.Project) == "" || strings.TrimSpace(r.ExplorerID) == "" { + return fmt.Errorf("receipt project and explorerId are required") + } + if r.Bundle.RecipeSchemaVersion <= 0 { + return ErrReceiptRecompileRequired + } + if r.ReceiptFormatVersion == CompilationReceiptFormatVersion { + required := []struct { + name string + value string + }{ + {"compilerContractVersion", r.CompilerContractVersion}, + {"intentDigest", r.IntentDigest}, + {"snapshotToken", r.SnapshotToken}, + {"authorizationScopeDigest", r.AuthorizationScopeDigest}, + {"capabilitySchemaDigest", r.CapabilitySchemaDigest}, + {"sourceGeneration", r.SourceGeneration}, + {"compilationKey", r.CompilationKey}, + {"recipeDigest", r.RecipeDigest}, + {"resolvedRecipeDigest", r.ResolvedRecipeDigest}, + {"resolvedSchemaDigest", r.ResolvedSchemaDigest}, + {"outputContractDigest", r.OutputContractDigest}, + } + for _, field := range required { + if strings.TrimSpace(field.value) == "" { + return fmt.Errorf("receipt %s is required", field.name) + } + } + key, err := CompilationKey(r) + if err != nil { + return err + } + if r.CompilationKey != key { + return fmt.Errorf("receipt compilation key mismatch: got %q want %q", r.CompilationKey, key) + } + resolvedDigest, err := r.Bundle.Digest() + if err != nil { + return fmt.Errorf("digest resolved recipe: %w", err) + } + if r.ResolvedRecipeDigest != resolvedDigest { + return fmt.Errorf("receipt resolved recipe digest mismatch: got %q want %q", r.ResolvedRecipeDigest, resolvedDigest) + } + contract, contractErr := DecodePublicOutputContract(r.PublicOutputContract) + if contractErr != nil { + return contractErr + } + if contractErr := contract.ValidateAgainst(r.Bundle, r.EmittedColumns); contractErr != nil { + return contractErr + } + contractDigest, err := CompilationArtifactDigest(r.PublicOutputContract) + if err != nil { + return fmt.Errorf("%w: digest public output contract: %v", ErrReceiptRecompileRequired, err) + } + if r.OutputContractDigest != contractDigest { + return fmt.Errorf("%w: receipt output contract digest mismatch: got %q want %q", ErrReceiptRecompileRequired, r.OutputContractDigest, contractDigest) + } + } + if r.ID != "" { + if err := r.ValidateID(); err != nil { + return err + } + } + if len(r.NormalizedBundle) > 0 { + if _, err := canonicalJSONBytes(r.NormalizedBundle); err != nil { + return fmt.Errorf("invalid normalized bundle: %w", err) + } + } + if len(r.CompiledConfig) > 0 { + if _, err := canonicalJSONBytes(r.CompiledConfig); err != nil { + return fmt.Errorf("invalid compiled config: %w", err) + } + } + if len(r.PublicOutputContract) > 0 { + if _, err := canonicalJSONBytes(r.PublicOutputContract); err != nil { + return fmt.Errorf("invalid public output contract: %w", err) + } + } + return nil +} + +// ValidateID verifies the stored ID against the receipt's content identity. +func (r CompilationReceipt) ValidateID() error { + if strings.TrimSpace(r.ID) == "" { + return fmt.Errorf("receipt id is required") + } + expected, err := ReceiptID(r) + if err != nil { + return fmt.Errorf("calculate receipt id: %w", err) + } + if r.ID != expected { + return fmt.Errorf("receipt id mismatch: got %q want %q", r.ID, expected) + } + return nil +} + +// ValidateID is also available as a package helper for repository code that +// prefers functional validation. +func ValidateID(r CompilationReceipt) error { return r.ValidateID() } + +// CloneCompilationReceipt returns a deep copy suitable for memory stores and +// tests. JSON round-tripping also clones nested recipe slices and maps while +// retaining the persisted wire shape. +func CloneCompilationReceipt(in CompilationReceipt) (CompilationReceipt, error) { + raw, err := json.Marshal(in) + if err != nil { + return CompilationReceipt{}, err + } + var out CompilationReceipt + if err := json.Unmarshal(raw, &out); err != nil { + return CompilationReceipt{}, err + } + return out, nil +} diff --git a/internal/explorer/compilation_receipt_test.go b/internal/explorer/compilation_receipt_test.go new file mode 100644 index 00000000..eaae127b --- /dev/null +++ b/internal/explorer/compilation_receipt_test.go @@ -0,0 +1,148 @@ +package explorer + +import ( + "encoding/json" + "errors" + "testing" + "time" + + "github.com/calypr/loom/internal/dataframe/recipe" +) + +func testReceipt() CompilationReceipt { + r := CompilationReceipt{ + ReceiptFormatVersion: CompilationReceiptFormatVersion, + CompilerContractVersion: CompilationReceiptCompilerContractVersion, + Project: "project-a", + ExplorerID: "explorer-a", + IntentDigest: "sha256:intent", + SnapshotToken: "sha256:snapshot", + AuthorizationScopeDigest: "sha256:scope", + CapabilitySchemaDigest: "sha256:schema", + SourceGeneration: "generation-a", + RecipeDigest: "sha256:recipe", + ResolvedSchemaDigest: "sha256:resolved-schema", + NormalizedBundle: json.RawMessage(`{"documents":[]}`), + Bundle: recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "receipt-test", TranslationVersion: "test", Outputs: []recipe.Output{{Name: "out", RootResourceType: "Patient", RowGrain: "patient"}}}, + CompiledConfig: json.RawMessage(`{"views":[]}`), + PublicOutputContract: json.RawMessage(`{"outputId":"out","columns":[]}`), + Warnings: []CompilationWarning{{Code: "EMPTY_OUTPUT", Message: "output has no selected fields"}}, + } + r.ResolvedRecipeDigest, _ = r.Bundle.Digest() + r.OutputContractDigest, _ = CompilationArtifactDigest(r.PublicOutputContract) + r.CompilationKey, _ = CompilationKey(r) + return r +} + +func TestCompilationReceiptIdentityExcludesMutableMetadata(t *testing.T) { + base := testReceipt() + id, err := ReceiptID(base) + if err != nil { + t.Fatal(err) + } + base.ID = "some-other-id" + base.RequestID = "request-2" + base.CreatedAt = time.Now().UTC() + got, err := ReceiptID(base) + if err != nil { + t.Fatal(err) + } + if got != id { + t.Fatalf("mutable metadata changed receipt ID: %q != %q", got, id) + } +} + +func TestCompilationKeyChangesWithScopeAndCompilerContract(t *testing.T) { + base := testReceipt() + first, err := CompilationKey(base) + if err != nil { + t.Fatal(err) + } + base.AuthorizationScopeDigest = "sha256:other-scope" + second, err := CompilationKey(base) + if err != nil { + t.Fatal(err) + } + if first == second { + t.Fatal("scope did not change compilation key") + } + base = testReceipt() + base.CompilerContractVersion = "loom.explorer.compiler/next" + third, err := CompilationKey(base) + if err != nil { + t.Fatal(err) + } + if first == third { + t.Fatal("compiler contract did not change compilation key") + } +} + +func TestCompilationReceiptValidateRejectsArtifactlessLegacyReceipt(t *testing.T) { + r := CompilationReceipt{Project: "project-a", ExplorerID: "explorer-a", ID: "receipt_legacy"} + if err := r.Validate(); !errors.Is(err, ErrReceiptRecompileRequired) { + t.Fatalf("error=%v, want %v", err, ErrReceiptRecompileRequired) + } +} + +func TestCompilationReceiptValidateIDAndDeepClone(t *testing.T) { + r := testReceipt() + var err error + r.ID, err = ReceiptID(r) + if err != nil { + t.Fatal(err) + } + if err := r.Validate(); err != nil { + t.Fatal(err) + } + clone, err := CloneCompilationReceipt(r) + if err != nil { + t.Fatal(err) + } + clone.OutputFingerprints = map[string]string{"out": "fingerprint"} + clone.Warnings[0].Details = map[string]any{"source": "test"} + if r.OutputFingerprints != nil || r.Warnings[0].Details != nil { + t.Fatal("clone mutation changed original receipt") + } + clone.ID = "receipt_wrong" + if err := clone.ValidateID(); err == nil { + t.Fatal("accepted mismatched receipt ID") + } +} + +func TestCompilationReceiptValidateRejectsForgedCompilationArtifacts(t *testing.T) { + r := testReceipt() + r.ID, _ = ReceiptID(r) + r.CompilationKey = "compile_forged" + if err := r.Validate(); err == nil { + t.Fatal("accepted a forged compilation key") + } + r = testReceipt() + r.PublicOutputContract = json.RawMessage(`{"outputs":[{"id":"forged"}]}`) + r.ID, _ = ReceiptID(r) + if err := r.Validate(); err == nil { + t.Fatal("accepted a public output contract with a stale digest") + } +} + +func TestCompilationReceiptJSONRoundTripKeepsIdentity(t *testing.T) { + r := testReceipt() + first, err := ReceiptID(r) + if err != nil { + t.Fatal(err) + } + raw, err := json.Marshal(r) + if err != nil { + t.Fatal(err) + } + var decoded CompilationReceipt + if err := json.Unmarshal(raw, &decoded); err != nil { + t.Fatal(err) + } + second, err := ReceiptID(decoded) + if err != nil { + t.Fatal(err) + } + if first != second { + t.Fatalf("JSON round trip changed receipt ID: %q != %q", first, second) + } +} diff --git a/internal/explorer/config_v2.go b/internal/explorer/config_v2.go index 5fd64252..d3f71fb5 100644 --- a/internal/explorer/config_v2.go +++ b/internal/explorer/config_v2.go @@ -11,6 +11,7 @@ import ( "strings" "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/projectid" ) // ConfigV2 is the portable Explorer artifact. Both repository and interactive @@ -93,6 +94,163 @@ type FileActions struct { Actions map[string]string `json:"actions,omitempty"` } +// PresentationRepairError reports a presentation reference that cannot be +// repaired without making a view unusable. Ordinary stale references are +// removed by RepairConfigV2Presentation and returned as WARN diagnostics. +type PresentationRepairError struct { + Diagnostic Diagnostic +} + +func (e *PresentationRepairError) Error() string { + if e == nil { + return "invalid Explorer presentation" + } + return e.Diagnostic.Message +} + +// RepairConfigV2Presentation removes presentation references that are absent +// from the authoritative emitted output schema. The schema is deliberately +// supplied by the caller because recipe parsing alone cannot know dynamic or +// snapshot-dependent output columns. +func RepairConfigV2Presentation(cfg ConfigV2, available map[string]map[string]bool) (ConfigV2, []Diagnostic, error) { + if len(available) == 0 { + return cfg, nil, nil + } + diagnostics := make([]Diagnostic, 0) + stale := func(path, output, column, reference string) { + diagnostics = append(diagnostics, Diagnostic{ + Severity: "WARN", + Stage: "presentation", + Code: "STALE_PRESENTATION_REFERENCE", + FieldPath: path, + Message: fmt.Sprintf("removed stale %s presentation reference to output column %q", reference, column), + Details: map[string]any{ + "outputId": output, + "column": column, + "referenceKind": reference, + }, + }) + } + hasColumn := func(output, column string) bool { + columns, ok := available[output] + return ok && columns[column] + } + allColumns := func(column string) bool { + for _, columns := range available { + if columns[column] { + return true + } + } + return false + } + + for viewIndex := range cfg.Views { + view := &cfg.Views[viewIndex] + if _, ok := available[view.Output]; !ok { + return cfg, diagnostics, &PresentationRepairError{Diagnostic: Diagnostic{ + Severity: "ERROR", + Stage: "presentation", + Code: "STALE_PRESENTATION_OUTPUT", + FieldPath: fmt.Sprintf("$.views[%d].output", viewIndex), + Message: fmt.Sprintf("view %q references an output absent from the compiled schema", view.ID), + Details: map[string]any{"viewId": view.ID, "outputId": view.Output}, + }} + } + columns := view.Table.Columns[:0] + for columnIndex, column := range view.Table.Columns { + if hasColumn(view.Output, column.Column) { + columns = append(columns, column) + continue + } + stale(fmt.Sprintf("$.views[%d].table.columns[%d].column", viewIndex, columnIndex), view.Output, column.Column, "table") + } + view.Table.Columns = columns + if len(view.Table.Columns) == 0 { + return cfg, diagnostics, &PresentationRepairError{Diagnostic: Diagnostic{ + Severity: "ERROR", + Stage: "presentation", + Code: "STALE_PRESENTATION_EMPTY_VIEW", + FieldPath: fmt.Sprintf("$.views[%d].table.columns", viewIndex), + Message: fmt.Sprintf("view %q has no table columns after stale presentation repair", view.ID), + Details: map[string]any{"viewId": view.ID, "outputId": view.Output}, + }} + } + if view.RowLabel != "" && !hasColumn(view.Output, view.RowLabel) { + stale(fmt.Sprintf("$.views[%d].rowLabel", viewIndex), view.Output, view.RowLabel, "rowLabel") + view.RowLabel = "" + } + filters := view.Filters[:0] + for filterIndex, filter := range view.Filters { + if hasColumn(view.Output, filter.Column) { + filters = append(filters, filter) + continue + } + stale(fmt.Sprintf("$.views[%d].filters[%d].column", viewIndex, filterIndex), view.Output, filter.Column, "filter") + } + view.Filters = filters + charts := view.Charts[:0] + for chartIndex, chart := range view.Charts { + if hasColumn(view.Output, chart.Column) { + charts = append(charts, chart) + continue + } + stale(fmt.Sprintf("$.views[%d].charts[%d].column", viewIndex, chartIndex), view.Output, chart.Column, "chart") + } + view.Charts = charts + for column := range view.FixedFilters { + if hasColumn(view.Output, column) { + continue + } + stale(fmt.Sprintf("$.views[%d].fixedFilters.%s", viewIndex, column), view.Output, column, "fixedFilter") + delete(view.FixedFilters, column) + } + for actionIndex := range view.Actions { + action := &view.Actions[actionIndex] + kept := action.Columns[:0] + for columnIndex, column := range action.Columns { + if hasColumn(view.Output, column) { + kept = append(kept, column) + continue + } + stale(fmt.Sprintf("$.views[%d].actions[%d].columns[%d]", viewIndex, actionIndex, columnIndex), view.Output, column, "action") + } + action.Columns = kept + } + } + + for output, filters := range cfg.SharedFilters { + kept := filters[:0] + for index, filter := range filters { + if hasColumn(filter.Output, filter.Column) { + kept = append(kept, filter) + continue + } + stale(fmt.Sprintf("$.sharedFilters.%s[%d].column", output, index), filter.Output, filter.Column, "sharedFilter") + } + if len(kept) == 0 { + delete(cfg.SharedFilters, output) + } else { + cfg.SharedFilters[output] = kept + } + } + for extension, columns := range cfg.FileActions.Extensions { + kept := columns[:0] + for index, column := range columns { + if allColumns(column) { + kept = append(kept, column) + continue + } + stale(fmt.Sprintf("$.fileActions.extensions.%s[%d]", extension, index), "", column, "fileAction") + } + if len(kept) == 0 { + delete(cfg.FileActions.Extensions, extension) + } else { + cfg.FileActions.Extensions[extension] = kept + } + } + return cfg, diagnostics, nil +} + // DecodeConfigV2 rejects the legacy explorerConfig/tabs envelope and every // unknown field. The recipe gets its own strict decoder and validator. func DecodeConfigV2(raw []byte, project string) (ConfigV2, recipe.Bundle, error) { @@ -129,13 +287,7 @@ func CanonicalConfigV2(raw []byte, project, explorerID, management string) (Conf if err != nil { return cfg, bundle, nil, "", err } - decoder := json.NewDecoder(bytes.NewReader(raw)) - decoder.UseNumber() - var value any - if err := decoder.Decode(&value); err != nil { - return cfg, bundle, nil, "", fmt.Errorf("canonicalize ExplorerConfigV2: %w", err) - } - canonical, err := json.Marshal(value) + canonical, err := canonicalJSONBytes(raw) if err != nil { return cfg, bundle, nil, "", fmt.Errorf("canonicalize ExplorerConfigV2: %w", err) } @@ -157,9 +309,10 @@ func decodeConfigV2(raw []byte, project, explorerID, management string) (ConfigV if cfg.APIVersion != ConfigV2APIVersion || cfg.Kind != "ExplorerConfig" { return cfg, recipe.Bundle{}, fmt.Errorf("apiVersion must be %q and kind must be ExplorerConfig", ConfigV2APIVersion) } - if cfg.Project != project { + if projectid.Canonical(cfg.Project) != projectid.Canonical(project) { return cfg, recipe.Bundle{}, fmt.Errorf("config project must match deployment project") } + cfg.Project = projectid.Canonical(project) if cfg.Explorer.ID != explorerID || !strings.EqualFold(cfg.Explorer.Management, management) { return cfg, recipe.Bundle{}, fmt.Errorf("config explorer identity or management mode does not match deployment") } diff --git a/internal/explorer/config_v2_test.go b/internal/explorer/config_v2_test.go index c84f5460..23145f2e 100644 --- a/internal/explorer/config_v2_test.go +++ b/internal/explorer/config_v2_test.go @@ -46,3 +46,41 @@ func TestDecodeConfigV2RejectsLegacyAndUnknownFields(t *testing.T) { } } } + +func TestRepairConfigV2PresentationRemovesStaleReferences(t *testing.T) { + cfg := ConfigV2{ + APIVersion: ConfigV2APIVersion, + Kind: "ExplorerConfig", + Project: "project-a", + Explorer: ConfigExplorer{ID: "custom", Title: "Custom", Management: "interactive"}, + Views: []ConfigView{{ + ID: "patient", Title: "Patients", Output: "Patient", RowLabel: "stale", + Table: ConfigTable{Columns: []ConfigColumn{{Column: "id"}, {Column: "stale"}}}, + Filters: []ConfigFilter{{Column: "id"}, {Column: "stale"}}, + Charts: []ConfigChart{{Column: "id"}, {Column: "stale"}}, + FixedFilters: map[string][]string{"id": {"x"}, "stale": {"x"}}, + Actions: []ConfigAction{{Type: "download", Title: "Download", Columns: []string{"id", "stale"}}}, + }}, + SharedFilters: map[string][]SharedFilter{"patient": {{Output: "Patient", Column: "id"}, {Output: "Patient", Column: "stale"}}}, + FileActions: FileActions{Extensions: map[string][]string{"csv": {"id", "stale"}}}, + } + repaired, diagnostics, err := RepairConfigV2Presentation(cfg, map[string]map[string]bool{"Patient": {"id": true}}) + if err != nil { + t.Fatal(err) + } + view := repaired.Views[0] + if len(view.Table.Columns) != 1 || len(view.Filters) != 1 || len(view.Charts) != 1 || view.RowLabel != "" { + t.Fatalf("stale view references were not repaired: %#v", view) + } + if _, ok := view.FixedFilters["stale"]; ok || len(view.Actions[0].Columns) != 1 || len(repaired.SharedFilters["patient"]) != 1 || len(repaired.FileActions.Extensions["csv"]) != 1 { + t.Fatalf("stale secondary references were not repaired: %#v %#v %#v", view, repaired.SharedFilters, repaired.FileActions) + } + if len(diagnostics) != 8 { + t.Fatalf("diagnostics = %d, want 8: %#v", len(diagnostics), diagnostics) + } + for _, diagnostic := range diagnostics { + if diagnostic.Code != "STALE_PRESENTATION_REFERENCE" || diagnostic.Severity != "WARN" { + t.Fatalf("unexpected diagnostic: %#v", diagnostic) + } + } +} diff --git a/internal/explorer/memory_store.go b/internal/explorer/memory_store.go index 5544238f..41f87b44 100644 --- a/internal/explorer/memory_store.go +++ b/internal/explorer/memory_store.go @@ -2,6 +2,8 @@ package explorer import ( "context" + "encoding/json" + "reflect" "sort" "sync" "time" @@ -13,12 +15,13 @@ type MemoryStore struct { mu sync.Mutex explorers map[string]Explorer revisions map[string]Revision + receipts map[string]CompilationReceipt configs map[string]RepositoryConfig repositoryConfigs map[string]RepositoryConfig } func NewMemoryStore() *MemoryStore { - return &MemoryStore{explorers: map[string]Explorer{}, revisions: map[string]Revision{}, configs: map[string]RepositoryConfig{}, repositoryConfigs: map[string]RepositoryConfig{}} + return &MemoryStore{explorers: map[string]Explorer{}, revisions: map[string]Revision{}, receipts: map[string]CompilationReceipt{}, configs: map[string]RepositoryConfig{}, repositoryConfigs: map[string]RepositoryConfig{}} } func configKey(project, id string) string { return project + "\x00" + id } func (s *MemoryStore) ListConfigs(_ context.Context, project string) ([]RepositoryConfig, error) { @@ -121,6 +124,258 @@ func (s *MemoryStore) SaveDraft(_ context.Context, e Explorer, expected int64, e s.explorers[k] = e return &e, nil } +func (s *MemoryStore) InsertCompilationReceipt(_ context.Context, receipt CompilationReceipt) (*CompilationReceipt, error) { + s.mu.Lock() + defer s.mu.Unlock() + if err := validateCompilationReceipt(receipt); err != nil { + return nil, err + } + if prior, ok := s.receipts[receipt.ID]; ok { + if !sameCompilationReceipt(prior, receipt) { + return nil, ErrCorruptReceipt + } + copy := cloneReceipt(prior) + return ©, nil + } + s.receipts[receipt.ID] = cloneReceipt(receipt) + copy := cloneReceipt(receipt) + return ©, nil +} +func (s *MemoryStore) GetCompilationReceipt(_ context.Context, id string) (*CompilationReceipt, error) { + s.mu.Lock() + defer s.mu.Unlock() + receipt, ok := s.receipts[id] + if !ok { + return nil, ErrNotFound + } + if err := validateCompilationReceipt(receipt); err != nil { + return nil, err + } + copy := cloneReceipt(receipt) + return ©, nil +} + +func (s *MemoryStore) GetCompilationReceiptForExplorer(_ context.Context, project, explorerID, id string) (*CompilationReceipt, error) { + s.mu.Lock() + defer s.mu.Unlock() + receipt, ok := s.receipts[id] + if !ok || receipt.Project != project || receipt.ExplorerID != explorerID { + return nil, ErrNotFound + } + if err := validateCompilationReceipt(receipt); err != nil { + return nil, err + } + copy := cloneReceipt(receipt) + return ©, nil +} + +func (s *MemoryStore) GetCompilationReceiptByCompilationKey(_ context.Context, project, explorerID, compilationKey string) (*CompilationReceipt, error) { + s.mu.Lock() + defer s.mu.Unlock() + var found *CompilationReceipt + for _, receipt := range s.receipts { + if receipt.Project != project || receipt.ExplorerID != explorerID || receiptCompilationKey(receipt) != compilationKey { + continue + } + if err := validateCompilationReceipt(receipt); err != nil { + return nil, err + } + candidate := cloneReceipt(receipt) + if found == nil || candidate.ID < found.ID { + found = &candidate + } + } + if found == nil { + return nil, ErrNotFound + } + return found, nil +} + +func (s *MemoryStore) CompilationReceiptStats(_ context.Context, project string) (ReceiptStoreStats, error) { + s.mu.Lock() + defer s.mu.Unlock() + stats := ReceiptStoreStats{} + referenced := map[string]bool{} + for _, revision := range s.revisions { + if revision.CompilationReceiptID != "" { + referenced[revision.CompilationReceiptID] = true + } + } + for id, receipt := range s.receipts { + if project != "" && receipt.Project != project { + continue + } + if err := validateCompilationReceipt(receipt); err != nil { + return ReceiptStoreStats{}, err + } + stats.Count++ + if raw, err := json.Marshal(receipt); err == nil { + stats.ApproxBytes += int64(len(raw)) + } + if stats.OldestCreatedAt.IsZero() || (!receipt.CreatedAt.IsZero() && receipt.CreatedAt.Before(stats.OldestCreatedAt)) { + stats.OldestCreatedAt = receipt.CreatedAt + } + if !referenced[id] { + stats.UnreferencedCount++ + } + } + return stats, nil +} + +func (s *MemoryStore) PublishAuthoring(_ context.Context, receipt CompilationReceipt, revision Revision) (*Revision, error) { + s.mu.Lock() + defer s.mu.Unlock() + key := explorerKey(revision.Project, revision.ExplorerID) + owner, ok := s.explorers[key] + if !ok { + return nil, ErrNotFound + } + if existing, ok := s.revisions[revision.ID]; ok && owner.ActiveRevisionID == revision.ID { + copy := existing + return ©, nil + } + if receipt.ID == "" || revision.CompilationReceiptID != receipt.ID { + return nil, ErrImmutableRevision + } + if err := validateCompilationReceipt(receipt); err != nil { + return nil, err + } + if prior, ok := s.receipts[receipt.ID]; ok && !sameCompilationReceipt(prior, receipt) { + return nil, ErrCorruptReceipt + } + now := time.Now().UTC() + if owner.ActiveRevisionID != "" { + prior := s.revisions[owner.ActiveRevisionID] + prior.Status = RevisionSuperseded + s.revisions[prior.ID] = prior + } + revision.Status = RevisionActive + revision.ActivatedAt = &now + revision.Publication.State = string(RevisionActive) + revision.Publication.RevisionID = revision.ID + revision.Publication.UpdatedAt = now + if _, ok := s.receipts[receipt.ID]; !ok { + s.receipts[receipt.ID] = cloneReceipt(receipt) + } + s.revisions[revision.ID] = revision + owner.ActiveRevisionID = revision.ID + owner.ActiveConfig = append([]byte(nil), revision.Config...) + owner.RecipeDigest = revision.RecipeDigest + owner.ResolvedSchemaDigest = revision.ResolvedSchemaDigest + owner.SourceGeneration = revision.SourceGeneration + owner.Materializations = append([]Materialization(nil), revision.Materializations...) + owner.EmittedColumns = append([]EmittedColumn(nil), revision.EmittedColumns...) + owner.Dataset = revision.Dataset + owner.Publication = revision.Publication + owner.Diagnostics = append([]Diagnostic(nil), revision.Diagnostics...) + owner.UpdatedAt = now + s.explorers[key] = owner + copy := revision + return ©, nil +} +func cloneReceipt(in CompilationReceipt) CompilationReceipt { + return cloneReflect(reflect.ValueOf(in)).Interface().(CompilationReceipt) +} + +var timeType = reflect.TypeOf(time.Time{}) + +// cloneReflect keeps the memory adapter honest as the immutable receipt grows: +// nested recipe slices/maps and raw JSON must never alias caller-owned state. +func cloneReflect(v reflect.Value) reflect.Value { + if !v.IsValid() { + return v + } + if v.Type() == timeType { + return v + } + switch v.Kind() { + case reflect.Interface: + if v.IsNil() { + return reflect.Zero(v.Type()) + } + out := reflect.New(v.Type()).Elem() + value := cloneReflect(v.Elem()) + out.Set(value) + return out + case reflect.Ptr: + if v.IsNil() { + return reflect.Zero(v.Type()) + } + out := reflect.New(v.Type().Elem()) + out.Elem().Set(cloneReflect(v.Elem())) + return out + case reflect.Slice: + if v.IsNil() { + return reflect.Zero(v.Type()) + } + out := reflect.MakeSlice(v.Type(), v.Len(), v.Len()) + for i := 0; i < v.Len(); i++ { + out.Index(i).Set(cloneReflect(v.Index(i))) + } + return out + case reflect.Array: + out := reflect.New(v.Type()).Elem() + for i := 0; i < v.Len(); i++ { + out.Index(i).Set(cloneReflect(v.Index(i))) + } + return out + case reflect.Map: + if v.IsNil() { + return reflect.Zero(v.Type()) + } + out := reflect.MakeMapWithSize(v.Type(), v.Len()) + iter := v.MapRange() + for iter.Next() { + out.SetMapIndex(cloneReflect(iter.Key()), cloneReflect(iter.Value())) + } + return out + case reflect.Struct: + out := reflect.New(v.Type()).Elem() + out.Set(v) + for i := 0; i < v.NumField(); i++ { + if out.Field(i).CanSet() && v.Field(i).CanInterface() { + out.Field(i).Set(cloneReflect(v.Field(i))) + } + } + return out + default: + return v + } +} + +func receiptCompilationKey(receipt CompilationReceipt) string { + value := reflect.ValueOf(receipt) + field := value.FieldByName("CompilationKey") + if field.IsValid() && field.Kind() == reflect.String && field.String() != "" { + return field.String() + } + // IntentDigest was the pre-receipt compilation key and is retained as a + // compatibility fallback while old documents are being migrated. + return receipt.IntentDigest +} + +func (s *MemoryStore) PurgeDraftAuthoring(_ context.Context) error { + s.mu.Lock() + defer s.mu.Unlock() + referenced := map[string]bool{} + for _, revision := range s.revisions { + if revision.CompilationReceiptID != "" { + referenced[revision.CompilationReceiptID] = true + } + } + for id := range s.receipts { + if !referenced[id] { + delete(s.receipts, id) + } + } + for key, value := range s.explorers { + value.DraftConfig = nil + value.DraftVersion = 0 + value.DraftDigest = "" + s.explorers[key] = value + } + return nil +} func (s *MemoryStore) InsertRevision(_ context.Context, r Revision) (*Revision, error) { s.mu.Lock() defer s.mu.Unlock() @@ -170,9 +425,12 @@ func (s *MemoryStore) ActivateInteractive(_ context.Context, p, id, revisionID s if !ok { return ErrNotFound } - if r.Status != RevisionReady { + if r.Status != RevisionReady && !(r.Status == RevisionActive && e.ActiveRevisionID == revisionID) { return ErrImmutableRevision } + if r.Status == RevisionActive && e.ActiveRevisionID == revisionID { + return nil + } if e.ActiveRevisionID != "" { prior := s.revisions[e.ActiveRevisionID] prior.Status = RevisionSuperseded diff --git a/internal/explorer/output_contract.go b/internal/explorer/output_contract.go new file mode 100644 index 00000000..042da3e4 --- /dev/null +++ b/internal/explorer/output_contract.go @@ -0,0 +1,136 @@ +package explorer + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "strings" + + "github.com/calypr/loom/internal/dataframe/recipe" +) + +// PublicOutputContract is the current, transport-neutral public output +// contract persisted inside a compilation receipt. It describes the one +// output selected by the V2 Builder; executable selectors and physical names +// are deliberately absent. +type PublicOutputContract struct { + OutputID string `json:"outputId"` + Columns []PublicOutputColumn `json:"columns"` +} + +type PublicOutputColumn struct { + EmissionID string `json:"emissionId"` + PublicColumn string `json:"publicColumn"` + CandidateID string `json:"candidateId,omitempty"` + OccurrenceID string `json:"occurrenceId,omitempty"` + LogicalType string `json:"logicalType"` + Filterable bool `json:"filterable"` + Chartable bool `json:"chartable"` +} + +// DecodePublicOutputContract strictly decodes the current contract shape. +// Null columns are accepted because an empty V2 selection is a valid mutable +// editor state and the current compiler serializes its nil slice as null. +// Missing columns, unknown fields, duplicate keys, and trailing JSON are not +// accepted. +func DecodePublicOutputContract(raw json.RawMessage) (PublicOutputContract, error) { + if len(bytes.TrimSpace(raw)) == 0 || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { + return PublicOutputContract{}, invalidOutputContract("contract is required") + } + if err := rejectDuplicateJSONKeys(raw); err != nil { + return PublicOutputContract{}, invalidOutputContract("duplicate or malformed JSON key: %v", err) + } + var fields map[string]json.RawMessage + if err := json.Unmarshal(raw, &fields); err != nil || fields == nil { + if err == nil { + err = errors.New("contract must be a JSON object") + } + return PublicOutputContract{}, invalidOutputContract("malformed JSON object: %v", err) + } + if _, ok := fields["outputId"]; !ok { + return PublicOutputContract{}, invalidOutputContract("outputId is required") + } + if _, ok := fields["columns"]; !ok { + return PublicOutputContract{}, invalidOutputContract("columns is required") + } + var contract PublicOutputContract + decoder := json.NewDecoder(bytes.NewReader(raw)) + decoder.DisallowUnknownFields() + if err := decoder.Decode(&contract); err != nil { + return PublicOutputContract{}, invalidOutputContract("decode failed: %v", err) + } + var trailing any + if err := decoder.Decode(&trailing); err != io.EOF { + if err == nil { + err = errors.New("trailing JSON value") + } + return PublicOutputContract{}, invalidOutputContract("trailing JSON: %v", err) + } + if strings.TrimSpace(contract.OutputID) == "" { + return PublicOutputContract{}, invalidOutputContract("outputId is required") + } + for i, column := range contract.Columns { + if strings.TrimSpace(column.EmissionID) == "" { + return PublicOutputContract{}, invalidOutputContract("columns[%d].emissionId is required", i) + } + if strings.TrimSpace(column.PublicColumn) == "" { + return PublicOutputContract{}, invalidOutputContract("columns[%d].publicColumn is required", i) + } + if strings.TrimSpace(column.LogicalType) == "" { + return PublicOutputContract{}, invalidOutputContract("columns[%d].logicalType is required", i) + } + } + return contract, nil +} + +// ValidateAgainst proves that the typed public contract is exactly the +// compiler-owned emitted-column sequence for the receipt's bundle. It checks +// output identity, order, IDs, and every public metadata bit. A mismatch is a +// receipt integrity failure and therefore requires explicit recompilation. +func (c PublicOutputContract) ValidateAgainst(bundle recipe.Bundle, emitted []EmittedColumn) error { + if strings.TrimSpace(c.OutputID) == "" { + return invalidOutputContract("outputId is required") + } + outputFound := false + for _, output := range bundle.Outputs { + if output.Name == c.OutputID { + outputFound = true + break + } + } + if !outputFound { + return invalidOutputContract("outputId %q is absent from the compiled recipe", c.OutputID) + } + if len(c.Columns) != len(emitted) { + return invalidOutputContract("column count %d does not match emitted column count %d", len(c.Columns), len(emitted)) + } + seenEmission := make(map[string]struct{}, len(emitted)) + seenPublic := make(map[string]struct{}, len(emitted)) + for i, column := range emitted { + if strings.TrimSpace(column.OutputID) != c.OutputID { + return invalidOutputContract("emittedColumns[%d] belongs to output %q, want %q", i, column.OutputID, c.OutputID) + } + if strings.TrimSpace(column.EmissionID) == "" || strings.TrimSpace(column.PublicColumn) == "" { + return invalidOutputContract("emittedColumns[%d] has an empty identity", i) + } + if _, exists := seenEmission[column.EmissionID]; exists { + return invalidOutputContract("duplicate emissionId %q", column.EmissionID) + } + if _, exists := seenPublic[column.PublicColumn]; exists { + return invalidOutputContract("duplicate publicColumn %q", column.PublicColumn) + } + seenEmission[column.EmissionID] = struct{}{} + seenPublic[column.PublicColumn] = struct{}{} + actual := c.Columns[i] + if actual.EmissionID != column.EmissionID || actual.PublicColumn != column.PublicColumn || actual.CandidateID != column.CandidateID || actual.OccurrenceID != column.OccurrenceID || actual.LogicalType != column.LogicalType || actual.Filterable != column.Filterable || actual.Chartable != column.Chartable { + return invalidOutputContract("columns[%d] does not match emittedColumns[%d]", i, i) + } + } + return nil +} + +func invalidOutputContract(format string, args ...any) error { + return fmt.Errorf("%w: public output contract %s", ErrReceiptRecompileRequired, fmt.Sprintf(format, args...)) +} diff --git a/internal/explorer/output_contract_test.go b/internal/explorer/output_contract_test.go new file mode 100644 index 00000000..9340181c --- /dev/null +++ b/internal/explorer/output_contract_test.go @@ -0,0 +1,82 @@ +package explorer + +import ( + "encoding/json" + "errors" + "testing" + + "github.com/calypr/loom/internal/dataframe/recipe" +) + +func contractFixture() (recipe.Bundle, []EmittedColumn, PublicOutputContract) { + bundle := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "contract-test", TranslationVersion: "test", Outputs: []recipe.Output{{Name: "patients", RootResourceType: "Patient", RowGrain: "patient"}}} + emitted := []EmittedColumn{ + {EmissionID: "em_id", OutputID: "patients", CandidateID: "c_id", OccurrenceID: "base", PublicColumn: "c_id_base", LogicalType: "string", Filterable: true, Chartable: false}, + {EmissionID: "em_name", OutputID: "patients", CandidateID: "c_name", OccurrenceID: "base", PublicColumn: "c_name_base", LogicalType: "string", Filterable: false, Chartable: true}, + } + contract := PublicOutputContract{OutputID: "patients", Columns: []PublicOutputColumn{ + {EmissionID: "em_id", PublicColumn: "c_id_base", CandidateID: "c_id", OccurrenceID: "base", LogicalType: "string", Filterable: true, Chartable: false}, + {EmissionID: "em_name", PublicColumn: "c_name_base", CandidateID: "c_name", OccurrenceID: "base", LogicalType: "string", Filterable: false, Chartable: true}, + }} + return bundle, emitted, contract +} + +func TestDecodePublicOutputContractIsStrict(t *testing.T) { + valid := json.RawMessage(`{"outputId":"patients","columns":[]}`) + if _, err := DecodePublicOutputContract(valid); err != nil { + t.Fatal(err) + } + for name, raw := range map[string]json.RawMessage{ + "missing columns": []byte(`{"outputId":"patients"}`), + "unknown field": []byte(`{"outputId":"patients","columns":[],"aql":"for x in c return x"}`), + "duplicate field": []byte(`{"outputId":"patients","columns":[],"columns":[]}`), + "trailing value": []byte(`{"outputId":"patients","columns":[]} {}`), + "not object": []byte(`[]`), + } { + t.Run(name, func(t *testing.T) { + if _, err := DecodePublicOutputContract(raw); !errors.Is(err, ErrReceiptRecompileRequired) { + t.Fatalf("error=%v, want ErrReceiptRecompileRequired", err) + } + }) + } +} + +func TestPublicOutputContractMatchesBundleAndOrderedEmissions(t *testing.T) { + bundle, emitted, contract := contractFixture() + if err := contract.ValidateAgainst(bundle, emitted); err != nil { + t.Fatal(err) + } + for name, mutate := range map[string]func(*recipe.Bundle, []EmittedColumn, *PublicOutputContract){ + "output identity": func(b *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContract) { c.OutputID = "missing" }, + "column order": func(_ *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContract) { + c.Columns[0], c.Columns[1] = c.Columns[1], c.Columns[0] + }, + "emission metadata": func(_ *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContract) { c.Columns[0].Filterable = false }, + "column count": func(_ *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContract) { c.Columns = c.Columns[:1] }, + "duplicate emission": func(_ *recipe.Bundle, e []EmittedColumn, _ *PublicOutputContract) { e[1].EmissionID = e[0].EmissionID }, + "duplicate public column": func(_ *recipe.Bundle, e []EmittedColumn, _ *PublicOutputContract) { + e[1].PublicColumn = e[0].PublicColumn + }, + "foreign emitted output": func(_ *recipe.Bundle, e []EmittedColumn, _ *PublicOutputContract) { e[0].OutputID = "other" }, + } { + t.Run(name, func(t *testing.T) { + b, e, c := bundle, append([]EmittedColumn(nil), emitted...), contract + c.Columns = append([]PublicOutputColumn(nil), contract.Columns...) + mutate(&b, e, &c) + if err := c.ValidateAgainst(b, e); !errors.Is(err, ErrReceiptRecompileRequired) { + t.Fatalf("error=%v, want ErrReceiptRecompileRequired", err) + } + }) + } +} + +func TestCompilationReceiptValidateRejectsMismatchedPublicContract(t *testing.T) { + r := testReceipt() + r.PublicOutputContract = json.RawMessage(`{"outputId":"out","columns":[{"emissionId":"em_bad","publicColumn":"c_bad","logicalType":"string","filterable":false,"chartable":false}]}`) + r.OutputContractDigest, _ = CompilationArtifactDigest(r.PublicOutputContract) + r.CompilationKey, _ = CompilationKey(r) + r.ID = "" + if err := r.Validate(); !errors.Is(err, ErrReceiptRecompileRequired) { + t.Fatalf("error=%v, want ErrReceiptRecompileRequired", err) + } +} diff --git a/internal/explorer/receipt_store_test.go b/internal/explorer/receipt_store_test.go new file mode 100644 index 00000000..f4dc3228 --- /dev/null +++ b/internal/explorer/receipt_store_test.go @@ -0,0 +1,82 @@ +package explorer + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/calypr/loom/internal/dataframe/recipe" +) + +func TestMemoryReceiptStoreIsTenantScopedAndImmutable(t *testing.T) { + ctx := context.Background() + store := NewMemoryStore() + receipt := CompilationReceipt{ + ID: "receipt-one", Project: "project-a", ExplorerID: "explorer-a", IntentDigest: "compile-a", + CreatedAt: time.Date(2026, 1, 2, 0, 0, 0, 0, time.UTC), + Bundle: recipe.Bundle{Outputs: []recipe.Output{{Name: "output", Fields: []recipe.Field{{Name: "field"}}}}}, + } + if _, err := store.InsertCompilationReceipt(ctx, receipt); err != nil { + t.Fatal(err) + } + // Mutating both the input and the returned value must not mutate storage. + receipt.Bundle.Outputs[0].Fields[0].Name = "caller-mutated" + got, err := store.GetCompilationReceiptForExplorer(ctx, "project-a", "explorer-a", "receipt-one") + if err != nil { + t.Fatal(err) + } + got.Bundle.Outputs[0].Fields[0].Name = "reader-mutated" + gotAgain, err := store.GetCompilationReceiptForExplorer(ctx, "project-a", "explorer-a", "receipt-one") + if err != nil { + t.Fatal(err) + } + if gotAgain.Bundle.Outputs[0].Fields[0].Name != "field" { + t.Fatalf("receipt nested recipe aliased storage: %q", gotAgain.Bundle.Outputs[0].Fields[0].Name) + } + if _, err := store.GetCompilationReceiptForExplorer(ctx, "project-b", "explorer-a", "receipt-one"); !errors.Is(err, ErrNotFound) { + t.Fatalf("cross-tenant lookup error=%v", err) + } +} + +func TestMemoryReceiptStoreDetectsImmutableCollisionAndFindsKey(t *testing.T) { + ctx := context.Background() + store := NewMemoryStore() + base := CompilationReceipt{ID: "receipt-same", Project: "p", ExplorerID: "e", IntentDigest: "key-a"} + if _, err := store.InsertCompilationReceipt(ctx, base); err != nil { + t.Fatal(err) + } + changed := base + changed.IntentDigest = "key-b" + if _, err := store.InsertCompilationReceipt(ctx, changed); !errors.Is(err, ErrCorruptReceipt) { + t.Fatalf("collision error=%v", err) + } + found, err := store.GetCompilationReceiptByCompilationKey(ctx, "p", "e", "key-a") + if err != nil || found.ID != base.ID { + t.Fatalf("key lookup=%#v, err=%v", found, err) + } +} + +func TestMemoryReceiptStoreStats(t *testing.T) { + ctx := context.Background() + store := NewMemoryStore() + old := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC) + for _, r := range []CompilationReceipt{ + {ID: "receipt-kept", Project: "p", ExplorerID: "e", IntentDigest: "a", CreatedAt: old}, + {ID: "receipt-orphan", Project: "p", ExplorerID: "e", IntentDigest: "b", CreatedAt: old.Add(time.Hour)}, + } { + if _, err := store.InsertCompilationReceipt(ctx, r); err != nil { + t.Fatal(err) + } + } + if _, err := store.InsertRevision(ctx, Revision{ID: "revision", Project: "p", ExplorerID: "e", CompilationReceiptID: "receipt-kept"}); err != nil { + t.Fatal(err) + } + stats, err := store.CompilationReceiptStats(ctx, "p") + if err != nil { + t.Fatal(err) + } + if stats.Count != 2 || stats.UnreferencedCount != 1 || stats.ApproxBytes <= 0 || !stats.OldestCreatedAt.Equal(old) { + t.Fatalf("stats=%+v", stats) + } +} diff --git a/internal/explorer/service.go b/internal/explorer/service.go index af22654f..5432831c 100644 --- a/internal/explorer/service.go +++ b/internal/explorer/service.go @@ -8,9 +8,11 @@ import ( "encoding/json" "errors" "fmt" + "strings" "time" "github.com/calypr/loom/internal/dataframe/publication" + "github.com/calypr/loom/internal/projectid" ) // Service is the persistence-neutral lifecycle coordinator. Compiler and @@ -27,31 +29,76 @@ func NewService(store Store) (*Service, error) { return &Service{store: store, now: func() time.Time { return time.Now().UTC() }}, nil } func (s *Service) List(ctx context.Context, project string) ([]Explorer, error) { - return s.store.List(ctx, project) + return s.store.List(ctx, projectid.Legacy(project)) } func (s *Service) RepositoryConfig(ctx context.Context, project string) (*RepositoryConfig, error) { - return s.store.GetRepositoryConfig(ctx, project) + return s.store.GetRepositoryConfig(ctx, projectid.Legacy(project)) } func (s *Service) SaveRepositoryConfig(ctx context.Context, value RepositoryConfig) (*RepositoryConfig, error) { + value.Project = projectid.Legacy(value.Project) return s.store.SaveRepositoryConfig(ctx, value) } func (s *Service) ListConfigs(ctx context.Context, project string) ([]RepositoryConfig, error) { - return s.store.ListConfigs(ctx, project) + return s.store.ListConfigs(ctx, projectid.Legacy(project)) } func (s *Service) Config(ctx context.Context, project, id string) (*RepositoryConfig, error) { - return s.store.GetConfig(ctx, project, id) + return s.store.GetConfig(ctx, projectid.Legacy(project), id) } func (s *Service) SaveConfig(ctx context.Context, value RepositoryConfig) (*RepositoryConfig, error) { + value.Project = projectid.Legacy(value.Project) return s.store.SaveConfig(ctx, value) } func (s *Service) Get(ctx context.Context, project, id string) (*Explorer, error) { - return s.store.Get(ctx, project, id) + return s.store.Get(ctx, projectid.Legacy(project), id) +} + +// EnsureRepositoryExplorer creates the repository-owned default identity when +// a migration is importing a configuration that has not previously been +// deployed through Loom. Existing identities are returned unchanged so the +// subsequent immutable revision publication can switch the active pointer in +// its normal transaction. +func (s *Service) EnsureRepositoryExplorer(ctx context.Context, project, id, title, actor string) (*Explorer, error) { + project = projectid.Canonical(project) + if id == "" { + id = "default" + } + if id != "default" { + return nil, fmt.Errorf("repository Explorer identity must be default") + } + owner, err := s.store.Get(ctx, projectid.Legacy(project), id) + if err == nil { + return owner, nil + } + if !errors.Is(err, ErrNotFound) { + return nil, err + } + if strings.TrimSpace(title) == "" { + title = "Explorer" + } + return s.store.CreateRepository(ctx, Explorer{ + Project: projectid.Legacy(project), + ExplorerID: id, + Title: title, + ManagementMode: ManagementRepository, + UpdatedBy: actor, + UpdatedAt: s.now(), + }) +} + +// CreateEmptyInteractive creates only the Explorer identity. Unpublished +// Explorers have no persisted authoring content and hydrate as an empty valid +// Builder model. +func (s *Service) CreateEmptyInteractive(ctx context.Context, project, id, title, actor string) (*Explorer, error) { + if id == "" || id == "default" { + return nil, fmt.Errorf("invalid interactive Explorer identity") + } + return s.store.CreateInteractive(ctx, Explorer{Project: projectid.Legacy(project), ExplorerID: id, Title: title, ManagementMode: ManagementInteractive, UpdatedBy: actor, UpdatedAt: s.now()}) } func (s *Service) Revision(ctx context.Context, id string) (*Revision, error) { return s.store.GetRevision(ctx, id) } func (s *Service) ActiveRevision(ctx context.Context, project, id string) (*Revision, error) { - e, err := s.store.Get(ctx, project, id) + e, err := s.store.Get(ctx, projectid.Legacy(project), id) if err != nil { return nil, err } @@ -64,6 +111,52 @@ func (s *Service) FailRevision(ctx context.Context, id string, diagnostics []Dia return s.store.TransitionRevision(ctx, id, RevisionFailed, diagnostics) } +func (s *Service) CompilationReceipt(ctx context.Context, id string) (*CompilationReceipt, error) { + return s.store.GetCompilationReceipt(ctx, id) +} + +// CompilationReceiptForExplorer performs the tenant-scoped lookup used by +// execution and publication. The ID-only method above remains for legacy +// callers during the receipt migration. +func (s *Service) CompilationReceiptForExplorer(ctx context.Context, project, explorerID, id string) (*CompilationReceipt, error) { + return s.store.GetCompilationReceiptForExplorer(ctx, projectid.Canonical(project), explorerID, id) +} + +func (s *Service) CompilationReceiptByCompilationKey(ctx context.Context, project, explorerID, compilationKey string) (*CompilationReceipt, error) { + return s.store.GetCompilationReceiptByCompilationKey(ctx, projectid.Canonical(project), explorerID, compilationKey) +} + +func (s *Service) CompilationReceiptStats(ctx context.Context, project string) (ReceiptStoreStats, error) { + return s.store.CompilationReceiptStats(ctx, projectid.Canonical(project)) +} + +func (s *Service) StoreCompilationReceipt(ctx context.Context, receipt CompilationReceipt) (*CompilationReceipt, error) { + return s.store.InsertCompilationReceipt(ctx, receipt) +} + +func (s *Service) PurgeDraftAuthoring(ctx context.Context) error { + return s.store.PurgeDraftAuthoring(ctx) +} + +func (s *Service) InsertAuthoringRevision(ctx context.Context, revision Revision) (*Revision, error) { + if revision.ID == "" || revision.CompilationReceiptID == "" || revision.IntentDigest == "" { + return nil, fmt.Errorf("authoring revision identity is incomplete") + } + revision.Project = projectid.Legacy(revision.Project) + return s.store.InsertRevision(ctx, revision) +} + +// PublishAuthoring atomically stores the server receipt and immutable revision +// and switches the Explorer's active pointer. +func (s *Service) PublishAuthoring(ctx context.Context, receipt CompilationReceipt, revision Revision) (*Revision, error) { + if receipt.ID == "" || revision.ID == "" || revision.CompilationReceiptID != receipt.ID { + return nil, fmt.Errorf("authoring publication identity is incomplete") + } + receipt.Project = projectid.Canonical(receipt.Project) + revision.Project = projectid.Legacy(revision.Project) + return s.store.PublishAuthoring(ctx, receipt, revision) +} + // NewInteractiveRevisionID is opaque and collision-resistant; repository // revisions intentionally use the deterministic tuple identity instead. func NewInteractiveRevisionID() (string, error) { @@ -95,10 +188,11 @@ func (s *Service) UpsertRepositoryV2(ctx context.Context, raw []byte, sourceComm return nil, nil, err } } - project := cfg.Project - owner, err := s.store.Get(ctx, project, "default") + project := projectid.Canonical(cfg.Project) + storageProject := projectid.Legacy(project) + owner, err := s.store.Get(ctx, storageProject, "default") if errors.Is(err, ErrNotFound) { - owner, err = s.store.CreateRepository(ctx, Explorer{Project: project, ExplorerID: "default", Title: cfg.Explorer.Title, ManagementMode: ManagementRepository, DraftConfig: canonical, DraftVersion: 1, DraftDigest: configDigest, SourceGeneration: sourceGeneration, Dataset: dataset, Publication: publication, UpdatedBy: actor, UpdatedAt: s.now()}) + owner, err = s.store.CreateRepository(ctx, Explorer{Project: storageProject, ExplorerID: "default", Title: cfg.Explorer.Title, ManagementMode: ManagementRepository, DraftConfig: canonical, DraftVersion: 1, DraftDigest: configDigest, SourceGeneration: sourceGeneration, Dataset: dataset, Publication: publication, UpdatedBy: actor, UpdatedAt: s.now()}) } else if err == nil { owner.Title, owner.DraftConfig, owner.DraftDigest, owner.SourceGeneration, owner.Dataset, owner.Publication, owner.UpdatedBy = cfg.Explorer.Title, canonical, configDigest, sourceGeneration, dataset, publication, actor owner, err = s.store.SaveDraft(ctx, *owner, owner.DraftVersion) @@ -108,20 +202,20 @@ func (s *Service) UpsertRepositoryV2(ctx context.Context, raw []byte, sourceComm } revisionID := RepositoryRevisionID(project, sourceCommit, configDigest, sourceGeneration) now := s.now() - revision, err := s.store.InsertRevision(ctx, Revision{ID: revisionID, Project: project, ExplorerID: "default", Config: canonical, ConfigDigest: configDigest, Recipe: compiled.Bundle, RecipeDigest: compiled.RecipeDigest, ResolvedSchemaDigest: resolvedSchemaDigest, SourceGeneration: sourceGeneration, SourceCommit: sourceCommit, Dataset: dataset, Publication: publication, Materializations: append([]Materialization(nil), materializations...), EmittedColumns: append([]EmittedColumn(nil), compiled.EmittedColumns...), Status: RevisionReady, CreatedBy: actor, CreatedAt: now, ReadyAt: &now}) + revision, err := s.store.InsertRevision(ctx, Revision{ID: revisionID, Project: storageProject, ExplorerID: "default", Config: canonical, ConfigDigest: configDigest, Recipe: compiled.Bundle, RecipeDigest: compiled.RecipeDigest, ResolvedSchemaDigest: resolvedSchemaDigest, SourceGeneration: sourceGeneration, SourceCommit: sourceCommit, Dataset: dataset, Publication: publication, Materializations: append([]Materialization(nil), materializations...), EmittedColumns: append([]EmittedColumn(nil), compiled.EmittedColumns...), Status: RevisionReady, CreatedBy: actor, CreatedAt: now, ReadyAt: &now}) if err != nil { return nil, nil, err } return owner, revision, nil } func (s *Service) ActivateInteractive(ctx context.Context, project, explorerID, revisionID string) error { - return s.store.ActivateInteractive(ctx, project, explorerID, revisionID) + return s.store.ActivateInteractive(ctx, projectid.Legacy(project), explorerID, revisionID) } func (s *Service) ActivateRepository(ctx context.Context, project, revisionID string) error { - return s.store.ActivateRepository(ctx, project, revisionID) + return s.store.ActivateRepository(ctx, projectid.Legacy(project), revisionID) } func (s *Service) ActivateRepositoryGeneration(ctx context.Context, project, generation, revisionID string) error { - return s.store.ActivateRepositoryGeneration(ctx, project, generation, revisionID) + return s.store.ActivateRepositoryGeneration(ctx, projectid.Legacy(project), generation, revisionID) } // RepositoryRevisionID is stable for retrying the same checked-out repository @@ -143,8 +237,9 @@ func (s *Service) CreateInteractiveV2(ctx context.Context, project, id string, r if err != nil { return nil, err } + canonicalProject := projectid.Canonical(project) return s.store.CreateInteractive(ctx, Explorer{ - Project: project, ExplorerID: id, Title: cfg.Explorer.Title, + Project: projectid.Legacy(canonicalProject), ExplorerID: id, Title: cfg.Explorer.Title, ManagementMode: ManagementInteractive, DraftConfig: canonical, DraftVersion: 1, DraftDigest: digest, UpdatedBy: actor, UpdatedAt: s.now(), }) @@ -163,9 +258,11 @@ func (s *Service) SaveDraftV2(ctx context.Context, project, id string, raw []byt if err != nil { return nil, err } - current, err := s.store.Get(ctx, project, id) + canonicalProject := projectid.Canonical(project) + storageProject := projectid.Legacy(canonicalProject) + current, err := s.store.Get(ctx, storageProject, id) if errors.Is(err, ErrNotFound) && id == "default" { - repository, repositoryErr := s.store.GetRepositoryConfig(ctx, project) + repository, repositoryErr := s.store.GetRepositoryConfig(ctx, storageProject) if repositoryErr != nil { return nil, repositoryErr } @@ -182,7 +279,7 @@ func (s *Service) SaveDraftV2(ctx context.Context, project, id string, raw []byt updatedAt = s.now() } current, err = s.store.CreateRepository(ctx, Explorer{ - Project: project, ExplorerID: "default", Title: cfg.Explorer.Title, + Project: storageProject, ExplorerID: "default", Title: cfg.Explorer.Title, ManagementMode: ManagementRepository, DraftConfig: append([]byte(nil), repository.Config...), DraftVersion: baseVersion, DraftDigest: baseDigest, ActiveRevisionID: repository.ActiveRevisionID, ActiveConfig: append([]byte(nil), repository.Config...), @@ -191,7 +288,7 @@ func (s *Service) SaveDraftV2(ctx context.Context, project, id string, raw []byt UpdatedBy: "repository", UpdatedAt: updatedAt, }) if errors.Is(err, ErrDraftConflict) { - current, err = s.store.Get(ctx, project, id) + current, err = s.store.Get(ctx, storageProject, id) } } if err != nil { diff --git a/internal/explorer/state_v1.go b/internal/explorer/state_v1.go new file mode 100644 index 00000000..077a6877 --- /dev/null +++ b/internal/explorer/state_v1.go @@ -0,0 +1,249 @@ +package explorer + +import ( + "encoding/json" + "time" + + "github.com/calypr/loom/internal/dataset" +) + +const ( + ExplorerStateV1APIVersion = "loom.calypr.org/explorer-state/v1" + ExplorerStateV1Kind = "ExplorerState" + ExplorerBuilderStateV1Kind = "ExplorerBuilderState" +) + +// ExplorerSummaryV1 is the intentionally small collection projection. Builder +// intent, catalog data, and resolved bindings are available only from the +// selected Explorer's /authoring/v1/builder resource. +type ExplorerSummaryV1 struct { + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + Title string `json:"title"` + Management ManagementMode `json:"management"` + ActiveRevisionID string `json:"activeRevisionId,omitempty"` + UpdatedAt time.Time `json:"updatedAt"` +} + +// ExplorerBuilderStateV1 is the complete, server-resolved editing model. The +// catalog and bindings are from the same immutable snapshot as Bundle. +type ExplorerBuilderStateV1 struct { + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + Title string `json:"title"` + Bundle ExplorerAuthoringBundleV1 `json:"bundle"` + Catalog ExplorerBuilderCatalogV1 `json:"catalog"` + Bindings []ExplorerResolvedBindingV1 `json:"bindings"` + Active ExplorerBuilderPublicationV1 `json:"active"` + Diagnostics []AuthoringDiagnostic `json:"diagnostics"` +} + +type ExplorerBuilderCatalogV1 struct { + SnapshotToken string `json:"snapshotToken"` + Generation string `json:"generation"` + ResolvedSchemaDigest string `json:"resolvedSchemaDigest,omitempty"` + AuthorizationScopeDigest string `json:"authorizationScopeDigest,omitempty"` + Nodes []ExplorerCatalogNodeV1 `json:"nodes"` + Edges []ExplorerCatalogEdgeV1 `json:"edges"` + Candidates []ExplorerCandidateV1 `json:"candidates"` +} + +type ExplorerCatalogNodeV1 struct { + NodeID string `json:"nodeId"` + ResourceType string `json:"resourceType"` +} +type ExplorerCatalogEdgeV1 struct { + EdgeID string `json:"edgeId"` + FromNodeID string `json:"fromNodeId"` + ToNodeID string `json:"toNodeId"` + Label string `json:"label"` +} +type ExplorerCandidateV1 struct { + CandidateID string `json:"candidateId"` + NodeID string `json:"nodeId"` + Label string `json:"label"` + LogicalType string `json:"logicalType"` + Filterable bool `json:"filterable"` + Chartable bool `json:"chartable"` +} + +type ExplorerResolvedBindingV1 struct { + OutputID string `json:"outputId"` + OutputTitle string `json:"outputTitle,omitempty"` + BaseNodeID string `json:"baseNodeId"` + BaseResourceType string `json:"baseResourceType"` + RowNodeID string `json:"rowNodeId"` + RowResourceType string `json:"rowResourceType"` + RowGrain string `json:"rowGrain"` + RouteKind string `json:"routeKind"` + RouteOccurrences []ExplorerResolvedOccurrenceV1 `json:"routeOccurrences"` + CandidateEmissions []ExplorerCandidateEmissionV1 `json:"candidateEmissions"` +} +type ExplorerResolvedOccurrenceV1 struct { + OccurrenceID string `json:"occurrenceId"` + Index int `json:"index"` + NodeID string `json:"nodeId"` + ResourceType string `json:"resourceType"` + IncomingEdgeID string `json:"incomingEdgeId,omitempty"` +} +type ExplorerCandidateEmissionV1 struct { + CandidateID string `json:"candidateId"` + OccurrenceID string `json:"occurrenceId"` + EmissionID string `json:"emissionId"` + // PublicColumn is the exact logical key returned in Builder preview rows. + // Browsers must never reconstruct this value from a label or identity. + PublicColumn string `json:"publicColumn"` + Label string `json:"label"` + LogicalType string `json:"logicalType"` + Filterable bool `json:"filterable"` + Chartable bool `json:"chartable"` +} + +// ExplorerPreviewColumnV1 is the authoritative bridge between an authoring +// emission and a preview row. EmissionID owns presentation; PublicColumn owns +// row lookup. +type ExplorerPreviewColumnV1 struct { + OutputID string `json:"outputId"` + CandidateID string `json:"candidateId"` + OccurrenceID string `json:"occurrenceId"` + EmissionID string `json:"emissionId"` + PublicColumn string `json:"publicColumn"` + Label string `json:"label"` + LogicalType string `json:"logicalType"` + Filterable bool `json:"filterable"` + Chartable bool `json:"chartable"` +} +type ExplorerBuilderPublicationV1 struct { + RevisionID string `json:"revisionId,omitempty"` + State string `json:"state,omitempty"` + Generation string `json:"generation,omitempty"` + IntentDigest string `json:"intentDigest,omitempty"` + PublishedAt time.Time `json:"publishedAt,omitempty"` + // Migration is a small, non-sensitive projection of immutable revision + // provenance. Raw source packets remain on the revision for rollback, but + // the Builder can still tell that its default was imported and identify the + // source/digests without downloading those packets. + Migration *ExplorerMigrationSummaryV1 `json:"migration,omitempty"` +} + +type ExplorerMigrationSummaryV1 struct { + Kind string `json:"kind"` + Source string `json:"source"` + SourceProject string `json:"sourceProject"` + SourceExplorerID string `json:"sourceExplorerId"` + OriginalConfigDigest string `json:"originalConfigDigest,omitempty"` + OriginalMappingDigest string `json:"originalMappingDigest,omitempty"` + MigratedAt time.Time `json:"migratedAt"` +} + +// ExplorerStateV1 is the server-owned lifecycle projection consumed by the +// Builder. It carries authoring bundles and publication metadata, but never +// exposes the legacy ExplorerConfig packet or the compiled recipe AST. +type ExplorerStateV1 struct { + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + Title string `json:"title"` + Management ManagementMode `json:"management"` + + Draft ExplorerStateV1Draft `json:"draft"` + Active ExplorerStateV1Active `json:"active"` + Generated ExplorerStateV1Generated `json:"generated"` + Runtime *ExplorerRuntimeV1 `json:"runtime,omitempty"` + + ActiveURL string `json:"activeUrl"` + UpdatedBy string `json:"updatedBy,omitempty"` + UpdatedAt time.Time `json:"updatedAt"` +} + +type ExplorerStateV1Draft struct { + Bundle json.RawMessage `json:"bundle,omitempty"` + Version int64 `json:"version"` + Digest string `json:"digest"` + IntentDigest string `json:"intentDigest,omitempty"` + ReceiptID string `json:"receiptId,omitempty"` +} + +type ExplorerStateV1Active struct { + Bundle json.RawMessage `json:"bundle,omitempty"` + RevisionID string `json:"revisionId,omitempty"` + IntentDigest string `json:"intentDigest,omitempty"` + Status string `json:"status,omitempty"` +} + +type ExplorerStateV1Generated struct { + RecipeDigest string `json:"recipeDigest,omitempty"` + ResolvedSchemaDigest string `json:"resolvedSchemaDigest,omitempty"` + SourceGeneration string `json:"sourceGeneration,omitempty"` + EmittedColumns []EmittedColumn `json:"emittedColumns,omitempty"` + Materializations []Materialization `json:"materializations,omitempty"` + Dataset DatasetMetadata `json:"dataset,omitempty"` + Publication PublicationMetadata `json:"publication,omitempty"` + Diagnostics []Diagnostic `json:"diagnostics,omitempty"` +} + +// ExplorerRuntimeV1 is the renderer-ready projection of one active Explorer +// release. Loom owns this projection so browsers never need to reconstruct +// runtime bindings from authoring intent, compiled configuration, or physical +// publication metadata. +type ExplorerRuntimeV1 struct { + Generation string `json:"generation,omitempty"` + Publication PublicationMetadata `json:"publication,omitempty"` + Schema ExplorerRuntimeSchemaV1 `json:"schema,omitempty"` + Outputs []ExplorerRuntimeOutputV1 `json:"outputs"` + SharedFilters map[string][]ExplorerRuntimeBindingV1 `json:"sharedFilters"` + Diagnostics []Diagnostic `json:"diagnostics"` +} + +type ExplorerRuntimeSchemaV1 struct { + Digest string `json:"digest,omitempty"` + Version string `json:"version,omitempty"` +} + +type ExplorerRuntimeOutputV1 struct { + OutputID string `json:"outputId"` + Name string `json:"name"` + Title string `json:"title"` + RowLabel string `json:"rowLabel"` + Selector dataset.DataframeSelector `json:"selector"` + Columns []ExplorerRuntimeColumnV1 `json:"columns"` + Table ExplorerRuntimeTableV1 `json:"table"` + Filters []ExplorerRuntimeBindingV1 `json:"filters"` + Charts []ExplorerRuntimeBindingV1 `json:"charts"` + FixedFilters map[string][]string `json:"fixedFilters"` + Materialization *Materialization `json:"materialization,omitempty"` +} + +type ExplorerRuntimeColumnV1 struct { + EmissionID string `json:"emissionId"` + Name string `json:"name"` + Label string `json:"label"` + LogicalType string `json:"logicalType"` + Visible bool `json:"visible"` + Order int `json:"order"` + Repeated bool `json:"repeated,omitempty"` + Filterable bool `json:"filterable"` + Sortable bool `json:"sortable,omitempty"` + Chartable bool `json:"chartable"` + Aggregatable bool `json:"aggregatable,omitempty"` +} + +type ExplorerRuntimeTableV1 struct { + Columns []ExplorerRuntimeTableColumnV1 `json:"columns"` +} + +type ExplorerRuntimeTableColumnV1 struct { + EmissionID string `json:"emissionId"` + Visible bool `json:"visible"` +} + +type ExplorerRuntimeBindingV1 struct { + EmissionID string `json:"emissionId"` + OutputID string `json:"outputId,omitempty"` + Label string `json:"label,omitempty"` + Type string `json:"type,omitempty"` + Title string `json:"title,omitempty"` +} diff --git a/internal/explorer/store.go b/internal/explorer/store.go index 8ae5d9d1..5ace5cb9 100644 --- a/internal/explorer/store.go +++ b/internal/explorer/store.go @@ -2,7 +2,11 @@ package explorer import ( "context" + "crypto/sha256" + "encoding/hex" "errors" + "strings" + "time" ) var ( @@ -11,8 +15,59 @@ var ( ErrImmutableRevision = errors.New("explorer revision content is immutable") ErrStaleCatalog = errors.New("stale Explorer authoring catalog") ErrIncompleteCatalog = errors.New("Explorer catalog discovery is incomplete") + // ErrCorruptReceipt means that a persisted receipt does not match its + // content-addressed identity, or that an immutable key was reused for a + // different receipt. Callers must fail closed rather than execute it. + ErrCorruptReceipt = errors.New("corrupt compilation receipt") ) +// ReceiptStoreStats is intentionally read-only and approximate. ApproxBytes +// is a serialized-document estimate, suitable for capacity observations, not +// billing or quota enforcement. +type ReceiptStoreStats struct { + Count int + ApproxBytes int64 + OldestCreatedAt time.Time + UnreferencedCount int +} + +func validateCompilationReceipt(receipt CompilationReceipt) error { + if strings.TrimSpace(receipt.ID) == "" { + return ErrCorruptReceipt + } + // New-format receipts are validated as executable artifacts. A few pre-v2 + // fixtures used human-readable IDs; keep accepting those + // during the migration, but every content-addressed receipt is checked on + // every read and write. + if receipt.ReceiptFormatVersion != 0 || receipt.CompilerContractVersion != "" || receipt.CompilationKey != "" { + if err := receipt.Validate(); err != nil { + return err + } + } + if strings.HasPrefix(receipt.ID, "receipt_") && looksContentAddressedReceiptID(receipt.ID) { + if err := receipt.ValidateID(); err != nil { + return ErrCorruptReceipt + } + } + return nil +} + +func looksContentAddressedReceiptID(id string) bool { + const prefix = "receipt_" + return len(id) == len(prefix)+sha256.Size*2 && hexEncoded(id[len(prefix):]) +} + +func hexEncoded(value string) bool { + _, err := hex.DecodeString(value) + return err == nil +} + +func sameCompilationReceipt(a, b CompilationReceipt) bool { + left, leftErr := ReceiptID(a) + right, rightErr := ReceiptID(b) + return leftErr == nil && rightErr == nil && left == right +} + // Store deliberately exposes only lifecycle mutations for revisions. An // adapter must never replace definition, recipe, digests, source generation, // or frozen materialization mappings after InsertRevision succeeds. @@ -31,10 +86,21 @@ type Store interface { // the stored draft version from the current value rather than trusting the // caller's expected version. SaveDraft(context.Context, Explorer, int64, ...string) (*Explorer, error) + InsertCompilationReceipt(context.Context, CompilationReceipt) (*CompilationReceipt, error) + GetCompilationReceipt(context.Context, string) (*CompilationReceipt, error) + // GetCompilationReceiptForExplorer is the tenant-scoped form. The legacy + // ID-only method remains temporarily for old publication callers. + GetCompilationReceiptForExplorer(context.Context, string, string, string) (*CompilationReceipt, error) + GetCompilationReceiptByCompilationKey(context.Context, string, string, string) (*CompilationReceipt, error) + CompilationReceiptStats(context.Context, string) (ReceiptStoreStats, error) + PublishAuthoring(context.Context, CompilationReceipt, Revision) (*Revision, error) InsertRevision(context.Context, Revision) (*Revision, error) GetRevision(context.Context, string) (*Revision, error) TransitionRevision(context.Context, string, RevisionStatus, []Diagnostic) (*Revision, error) ActivateInteractive(context.Context, string, string, string) error ActivateRepository(context.Context, string, string) error ActivateRepositoryGeneration(context.Context, string, string, string) error + // PurgeDraftAuthoring irreversibly removes every legacy/draft authoring + // field and compilation receipt not referenced by an immutable revision. + PurgeDraftAuthoring(context.Context) error } diff --git a/internal/explorer/types.go b/internal/explorer/types.go index 615251b7..ccea0000 100644 --- a/internal/explorer/types.go +++ b/internal/explorer/types.go @@ -23,7 +23,7 @@ type RepositoryConfig struct { SourceCommit string `json:"sourceCommit"` ExecutionID string `json:"executionId"` ActiveRevisionID string `json:"activeRevisionId,omitempty"` - DraftVersion int64 `json:"draftVersion,omitempty"` + DraftVersion int64 `json:"-"` Materializations []Materialization `json:"materializations"` Dataset DatasetMetadata `json:"dataset"` Publication PublicationMetadata `json:"publication"` @@ -50,12 +50,14 @@ const ( ) type Diagnostic struct { - Severity string `json:"severity"` - Code string `json:"code"` - FieldPath string `json:"fieldPath,omitempty"` - Message string `json:"message"` - Retryable bool `json:"retryable,omitempty"` - RequestID string `json:"requestId,omitempty"` + Severity string `json:"severity"` + Stage string `json:"stage,omitempty"` + Code string `json:"code"` + FieldPath string `json:"fieldPath,omitempty"` + Message string `json:"message"` + Details map[string]any `json:"details,omitempty"` + Retryable bool `json:"retryable,omitempty"` + RequestID string `json:"requestId,omitempty"` } // DatasetMetadata is the live, server-derived shape of a published recipe. @@ -92,9 +94,9 @@ type Explorer struct { ManagementMode ManagementMode `json:"managementMode"` // DraftConfig is the lossless, canonical ExplorerConfigV2 packet used by // the Builder. - DraftConfig json.RawMessage `json:"draftConfig,omitempty"` - DraftVersion int64 `json:"draftVersion"` - DraftDigest string `json:"draftDigest"` + DraftConfig json.RawMessage `json:"-"` + DraftVersion int64 `json:"-"` + DraftDigest string `json:"-"` ActiveRevisionID string `json:"activeRevisionId,omitempty"` ActiveConfig json.RawMessage `json:"activeConfig,omitempty"` RecipeDigest string `json:"recipeDigest,omitempty"` @@ -133,6 +135,9 @@ type Revision struct { // Config is the exact immutable ExplorerConfigV2 packet for this revision. Config json.RawMessage `json:"config,omitempty"` ConfigDigest string `json:"configDigest,omitempty"` + AuthoringBundle json.RawMessage `json:"authoringBundle,omitempty"` + IntentDigest string `json:"intentDigest,omitempty"` + CompilationReceiptID string `json:"compilationReceiptId,omitempty"` Recipe recipe.Bundle `json:"canonicalRecipe"` RecipeDigest string `json:"recipeDigest"` ResolvedSchemaDigest string `json:"resolvedSchemaDigest"` @@ -143,10 +148,35 @@ type Revision struct { Dataset DatasetMetadata `json:"dataset,omitempty"` Publication PublicationMetadata `json:"publication,omitempty"` Diagnostics []Diagnostic `json:"diagnostics"` - Status RevisionStatus `json:"status"` - CreatedBy string `json:"createdBy,omitempty"` - CreatedAt time.Time `json:"createdAt"` - ReadyAt *time.Time `json:"readyAt,omitempty"` - ActivatedAt *time.Time `json:"activatedAt,omitempty"` - FailedAt *time.Time `json:"failedAt,omitempty"` + // Migration records the lossless source packet used to create this + // revision. The authoring bundle is the executable Builder intent, while + // these raw packets provide an auditable rollback path for migrations from + // frontend/repository configuration formats (including fields Loom does not + // yet interpret). + Migration *MigrationMetadata `json:"migration,omitempty"` + Status RevisionStatus `json:"status"` + CreatedBy string `json:"createdBy,omitempty"` + CreatedAt time.Time `json:"createdAt"` + ReadyAt *time.Time `json:"readyAt,omitempty"` + ActivatedAt *time.Time `json:"activatedAt,omitempty"` + FailedAt *time.Time `json:"failedAt,omitempty"` +} + +// MigrationMetadata is intentionally attached to the immutable revision. A +// migration must never discard the source document merely because its known +// fields were translated into authoring-v1. Raw JSON is retained so unknown +// or frontend-specific fields remain available for rollback and future +// translators without leaking them into the executable recipe contract. +type MigrationMetadata struct { + Kind string `json:"kind"` + Source string `json:"source"` + SourceProject string `json:"sourceProject"` + SourceExplorerID string `json:"sourceExplorerId"` + OriginalConfig json.RawMessage `json:"originalConfig,omitempty"` + OriginalMapping json.RawMessage `json:"originalMapping,omitempty"` + OriginalConfigDigest string `json:"originalConfigDigest,omitempty"` + OriginalMappingDigest string `json:"originalMappingDigest,omitempty"` + Actor string `json:"actor,omitempty"` + RequestID string `json:"requestId,omitempty"` + MigratedAt time.Time `json:"migratedAt"` } diff --git a/internal/fhir/schema/compiler_semantics.go b/internal/fhir/schema/compiler_semantics.go index 27fbf5b9..d1239b6b 100644 --- a/internal/fhir/schema/compiler_semantics.go +++ b/internal/fhir/schema/compiler_semantics.go @@ -64,14 +64,39 @@ func ResourceTypes() []string { return out } -// HasResource reports whether resourceType is a generated FHIR resource type. -func HasResource(resourceType string) bool { +// ConcreteResourceType resolves a graph resource type without requiring +// callers at discovery boundaries to already know the generated schema's +// casing. Only concrete FHIR roots are accepted. Backbone definitions, +// abstract Resource, and caller-supplied custom types are intentionally not +// resources even when they are present in generatedDefinitions. +func ConcreteResourceType(resourceType string) (string, bool) { resourceType = strings.TrimSpace(resourceType) if resourceType == "" { - return false + return "", false } index := sort.SearchStrings(generatedResourceTypes, resourceType) - return index < len(generatedResourceTypes) && generatedResourceTypes[index] == resourceType + if index < len(generatedResourceTypes) && generatedResourceTypes[index] == resourceType { + return resourceType, true + } + for _, candidate := range generatedResourceTypes { + if strings.EqualFold(candidate, resourceType) { + return candidate, true + } + } + return "", false +} + +// CanonicalResourceType is retained as a compatibility name for callers that +// need a canonical concrete resource type. +func CanonicalResourceType(resourceType string) (string, bool) { + return ConcreteResourceType(resourceType) +} + +// HasResource reports whether resourceType is a generated concrete FHIR +// resource root. +func HasResource(resourceType string) bool { + _, ok := ConcreteResourceType(resourceType) + return ok } // ResourceExists is the explicit predicate form of HasResource. diff --git a/internal/fhir/schema/compiler_semantics_test.go b/internal/fhir/schema/compiler_semantics_test.go index 01af8a05..10671cf5 100644 --- a/internal/fhir/schema/compiler_semantics_test.go +++ b/internal/fhir/schema/compiler_semantics_test.go @@ -18,6 +18,27 @@ func TestResourceTypesAreSortedDefensiveCopy(t *testing.T) { } } +func TestConcreteResourceTypeRejectsDefinitionsAndUnknowns(t *testing.T) { + for _, test := range []struct { + value string + want string + ok bool + }{ + {value: " Patient ", want: "Patient", ok: true}, + {value: "organization", want: "Organization", ok: true}, + {value: "PractitionerQualification", ok: false}, + {value: "qualification", ok: false}, + {value: "issuer", ok: false}, + {value: "Resource", ok: false}, + {value: "CustomResource", ok: false}, + } { + got, ok := ConcreteResourceType(test.value) + if got != test.want || ok != test.ok { + t.Errorf("ConcreteResourceType(%q) = %q, %v; want %q, %v", test.value, got, ok, test.want, test.ok) + } + } +} + func TestDefinitionExistsIncludesBackbonesWithoutTreatingThemAsResources(t *testing.T) { if !DefinitionExists("Patient") { t.Fatal("Patient should be a generated definition") diff --git a/internal/ingest/documents.go b/internal/ingest/documents.go index 35124356..8bd6ed14 100644 --- a/internal/ingest/documents.go +++ b/internal/ingest/documents.go @@ -11,6 +11,7 @@ import ( "strings" "github.com/bmeg/jsonschemagraph/model" + fhirschema "github.com/calypr/loom/internal/fhir/schema" ) var validKeyPart = regexp.MustCompile(`[^A-Za-z0-9_\-:.@()+,=;$!*'%]`) @@ -36,6 +37,10 @@ type EdgeDocument struct { } func VertexFromFHIRWithExtra(project, resourceType string, payload, extraArgs map[string]any) (VertexDocument, error) { + canonicalType, ok := fhirschema.ConcreteResourceType(resourceType) + if !ok { + return VertexDocument{}, fmt.Errorf("unsupported FHIR graph resource type %q", resourceType) + } id, ok := payload["id"].(string) if !ok || strings.TrimSpace(id) == "" { return VertexDocument{}, fmt.Errorf("%s payload missing string id", resourceType) @@ -53,7 +58,7 @@ func VertexFromFHIRWithExtra(project, resourceType string, payload, extraArgs ma ID: id, Project: project, ProjectID: project, - ResourceType: resourceType, + ResourceType: canonicalType, AuthResourcePath: authResourcePath, Payload: payloadCopy, }, nil @@ -63,6 +68,10 @@ func EdgeFromGrip(project, sourceType string, edge *model.Edge) (EdgeDocument, e if edge == nil { return EdgeDocument{}, fmt.Errorf("nil edge") } + canonicalSourceType, ok := fhirschema.ConcreteResourceType(sourceType) + if !ok { + return EdgeDocument{}, fmt.Errorf("edge %q has unsupported source resource type %q", edge.Id, sourceType) + } if strings.TrimSpace(edge.From) == "" { return EdgeDocument{}, fmt.Errorf("edge %q missing source id", edge.Id) } @@ -80,14 +89,18 @@ func EdgeFromGrip(project, sourceType string, edge *model.Edge) (EdgeDocument, e return EdgeDocument{}, fmt.Errorf("edge %q target type: %w", edge.Id, err) } } + canonicalTargetType, ok := fhirschema.ConcreteResourceType(targetType) + if !ok { + return EdgeDocument{}, fmt.Errorf("edge %q has unsupported target resource type %q", edge.Id, targetType) + } return EdgeDocument{ Key: SanitizeKey(edge.Id), - From: collectionID(sourceType, edge.From), - To: collectionID(targetType, targetID), + From: collectionID(canonicalSourceType, edge.From), + To: collectionID(canonicalTargetType, targetID), Label: edge.Label, Project: project, - FromType: sourceType, - ToType: targetType, + FromType: canonicalSourceType, + ToType: canonicalTargetType, }, nil } diff --git a/internal/ingest/documents_test.go b/internal/ingest/documents_test.go new file mode 100644 index 00000000..b0a330ce --- /dev/null +++ b/internal/ingest/documents_test.go @@ -0,0 +1,35 @@ +package ingest + +import ( + "testing" + + "github.com/bmeg/jsonschemagraph/model" +) + +func TestEdgeFromGripRejectsNonConcreteResourceEndpoints(t *testing.T) { + for _, target := range []string{"PractitionerQualification", "qualification", "issuer", "Resource", "CustomResource"} { + _, err := EdgeFromGrip("project", "Practitioner", &model.Edge{Id: "edge-1", From: "practitioner-1", To: target + "/target-1", Label: "link"}) + if err == nil { + t.Fatalf("target type %q was accepted", target) + } + } +} + +func TestEdgeFromGripCanonicalizesConcreteEndpoints(t *testing.T) { + edge, err := EdgeFromGrip("project", " patient ", &model.Edge{Id: "edge-1", From: "patient-1", To: "specimen-1", Label: "subject_Specimen"}) + if err != nil { + t.Fatal(err) + } + if edge.FromType != "Patient" || edge.ToType != "Specimen" { + t.Fatalf("edge types = %q -> %q, want Patient -> Specimen", edge.FromType, edge.ToType) + } + if edge.From != "Patient/patient-1" || edge.To != "Specimen/specimen-1" { + t.Fatalf("edge endpoints = %q -> %q, want canonical collections", edge.From, edge.To) + } +} + +func TestVertexFromFHIRWithExtraRejectsNonConcreteResourceTypes(t *testing.T) { + if _, err := VertexFromFHIRWithExtra("project", "PractitionerQualification", map[string]any{"id": "qualification-1"}, nil); err == nil { + t.Fatal("backbone definition was accepted as a graph vertex") + } +} diff --git a/internal/ingest/generated_load_test.go b/internal/ingest/generated_load_test.go index b4f91f16..9d629625 100644 --- a/internal/ingest/generated_load_test.go +++ b/internal/ingest/generated_load_test.go @@ -61,6 +61,43 @@ func TestGeneratedResearchSubjectStudyEdgeTargetsResearchStudy(t *testing.T) { } } +func TestGeneratedNestedLinkUsesConcreteRuntimeEndpoints(t *testing.T) { + _, edges, _, err := loadRowGenerated("Practitioner", []byte(`{ + "resourceType": "Practitioner", + "id": "practitioner-1", + "qualification": [{"code": {"text": "board-certified"}, "issuer": {"reference": "Organization/org-1"}}] +}`), "project-1", map[string]float64{}) + if err != nil { + t.Fatalf("loadRowGenerated(Practitioner): %v", err) + } + want := map[string]struct { + from, to, fromType, toType string + }{ + "qualification_issuer": {"Practitioner/practitioner-1", "Organization/org-1", "Practitioner", "Organization"}, + "practitioner_qualification": {"Organization/org-1", "Practitioner/practitioner-1", "Organization", "Practitioner"}, + } + found := map[string]bool{} + for _, raw := range edges { + var edge fhir.EdgeDocument + if err := json.Unmarshal(raw, &edge); err != nil { + t.Fatalf("decode generated edge: %v", err) + } + wantEdge, ok := want[edge.Label] + if !ok { + continue + } + found[edge.Label] = true + if edge.From != wantEdge.from || edge.To != wantEdge.to || edge.FromType != wantEdge.fromType || edge.ToType != wantEdge.toType { + t.Errorf("%s edge = %#v, want %s/%s %s -> %s", edge.Label, edge, wantEdge.fromType, wantEdge.toType, wantEdge.from, wantEdge.to) + } + } + for label := range want { + if !found[label] { + t.Errorf("generated Practitioner edges missing %s", label) + } + } +} + func TestGeneratedLoadAddsProjectIDToEnvelopeAndPayload(t *testing.T) { project := "HTAN_INT-BForePC" vertex, _, _, err := loadRowGenerated("Patient", []byte(`{ diff --git a/internal/ingest/generation_orchestration.go b/internal/ingest/generation_orchestration.go index 316937b4..c5a430d2 100644 --- a/internal/ingest/generation_orchestration.go +++ b/internal/ingest/generation_orchestration.go @@ -218,12 +218,13 @@ func loadGeneration(ctx context.Context, opts LoadOptions) (summary LoadSummary, } merged := catalogs[key] if merged == nil { - merged = catalog.NewProfilerForGeneration( + merged = catalog.NewProfilerForGenerationWithLimits( key.project, key.datasetGeneration, key.authResourcePath, key.resourceType, - catalog.NewShapePlanCache(), + catalog.NewShapePlanCacheWithLimit(opts.CatalogLimits.MaxShapePlans), + opts.CatalogLimits, ) catalogs[key] = merged } diff --git a/internal/ingest/generation_workers.go b/internal/ingest/generation_workers.go index 9b5781d3..5face82f 100644 --- a/internal/ingest/generation_workers.go +++ b/internal/ingest/generation_workers.go @@ -122,8 +122,8 @@ func loadFile( } } - linesChan := make(chan fileLine, 10000) - writeChan := make(chan fileWriteTask, 100) + linesChan := make(chan fileLine, opts.LineQueueSize) + writeChan := make(chan fileWriteTask, opts.WriteQueueSize) fileCtx, cancel := context.WithCancel(ctx) defer cancel() @@ -164,11 +164,11 @@ func loadFile( } }() - const workerCount = 8 + workerCount := opts.WorkerCount var workersWG sync.WaitGroup workerTimingsChan := make(chan map[string]float64, workerCount) workerCatalogsChan := make(chan *catalog.Profiler, workerCount) - shapeCache := catalog.NewShapePlanCache() + shapeCache := catalog.NewShapePlanCacheWithLimit(opts.CatalogLimits.MaxShapePlans) var fileRows int64 var fileVertices int64 @@ -210,7 +210,7 @@ func loadFile( go func() { defer workersWG.Done() localTimings := make(map[string]float64) - localCatalog := catalog.NewProfilerForGeneration(opts.Project, datasetGeneration, opts.AuthResourcePath, resourceType, shapeCache) + localCatalog := catalog.NewProfilerForGenerationWithLimits(opts.Project, datasetGeneration, opts.AuthResourcePath, resourceType, shapeCache, opts.CatalogLimits) vertexBatch := make([]json.RawMessage, 0, opts.BatchSize) edgeBatch := make([]json.RawMessage, 0, opts.BatchSize) @@ -398,7 +398,7 @@ func loadFile( result.RowErrors = rowErrors result.StageSeconds = make(map[string]float64) result.RelationshipCounts = make(map[catalog.RelationshipKey]int64) - mergedCatalog := catalog.NewProfilerForGeneration(opts.Project, datasetGeneration, opts.AuthResourcePath, resourceType, shapeCache) + mergedCatalog := catalog.NewProfilerForGenerationWithLimits(opts.Project, datasetGeneration, opts.AuthResourcePath, resourceType, shapeCache, opts.CatalogLimits) for timings := range workerTimingsChan { for key, value := range timings { switch key { diff --git a/internal/ingest/load_options.go b/internal/ingest/load_options.go index 74330b6a..81471e9d 100644 --- a/internal/ingest/load_options.go +++ b/internal/ingest/load_options.go @@ -5,6 +5,7 @@ import ( "fmt" "os" + "github.com/calypr/loom/internal/catalog" publication "github.com/calypr/loom/internal/dataset" arangostore "github.com/calypr/loom/internal/store/arango" ) @@ -18,6 +19,10 @@ type LoadOptions struct { BatchSize int ProgressEvery int WriterCount int + WorkerCount int + LineQueueSize int + WriteQueueSize int + CatalogLimits catalog.ProfileLimits Truncate bool FailFast bool UseGeneric bool @@ -83,6 +88,16 @@ func normalizeLoadOptions(opts LoadOptions) LoadOptions { if opts.WriterCount <= 0 { opts.WriterCount = 8 } + if opts.WorkerCount <= 0 { + opts.WorkerCount = opts.WriterCount + } + if opts.LineQueueSize <= 0 { + opts.LineQueueSize = 1024 + } + if opts.WriteQueueSize <= 0 { + opts.WriteQueueSize = 16 + } + opts.CatalogLimits = catalog.NormalizeProfileLimits(opts.CatalogLimits) if opts.WriteAPI == "" { opts.WriteAPI = "import" } diff --git a/internal/ingest/load_options_test.go b/internal/ingest/load_options_test.go new file mode 100644 index 00000000..53e77d20 --- /dev/null +++ b/internal/ingest/load_options_test.go @@ -0,0 +1,43 @@ +package ingest + +import ( + "testing" + + "github.com/calypr/loom/internal/catalog" +) + +func TestNormalizeLoadOptionsUsesBoundedConcurrencyDefaults(t *testing.T) { + got := normalizeLoadOptions(LoadOptions{WriterCount: 3}) + if got.WorkerCount != 3 { + t.Fatalf("worker count = %d, want writer count 3", got.WorkerCount) + } + if got.LineQueueSize <= 0 || got.WriteQueueSize <= 0 { + t.Fatalf("queue sizes = line %d write %d, want positive bounded defaults", got.LineQueueSize, got.WriteQueueSize) + } + if got.CatalogLimits.MaxDistinctValuesPerField <= 0 || got.CatalogLimits.MaxShapePlans <= 0 { + t.Fatalf("catalog limits = %#v, want finite defaults", got.CatalogLimits) + } +} + +func TestNormalizeLoadOptionsPreservesExplicitConcurrencyAndCatalogLimits(t *testing.T) { + got := normalizeLoadOptions(LoadOptions{ + WriterCount: 1, + WorkerCount: 1, + LineQueueSize: 32, + WriteQueueSize: 4, + CatalogLimits: catalog.ProfileLimits{ + MaxFields: 4, + MaxDistinctValuesPerField: 2, + MaxDistinctValueBytes: 8, + MaxPivotColumnsPerField: 2, + MaxExtensionValuesPerField: 2, + MaxShapePlans: 1, + }, + }) + if got.WorkerCount != 1 || got.LineQueueSize != 32 || got.WriteQueueSize != 4 { + t.Fatalf("normalized concurrency = %#v, want explicit values", got) + } + if got.CatalogLimits.MaxDistinctValuesPerField != 2 { + t.Fatalf("normalized catalog limits = %#v, want explicit value", got.CatalogLimits) + } +} diff --git a/internal/projectid/projectid.go b/internal/projectid/projectid.go new file mode 100644 index 00000000..207ae586 --- /dev/null +++ b/internal/projectid/projectid.go @@ -0,0 +1,76 @@ +// Package projectid defines the public project identity used by Loom's +// Explorer APIs. Existing generations and Explorer records may still be +// keyed by the historical program-project form, so callers can derive that +// storage alias without putting the legacy format back on the wire. +package projectid + +import ( + "fmt" + "net/url" + "strings" +) + +// Canonical returns the GitHub-style program/project identity. Legacy IDs are +// accepted at compatibility boundaries and split at their first hyphen so a +// project name may continue to contain additional hyphens. +func Canonical(raw string) string { + raw = strings.TrimSpace(raw) + if raw == "" { + return "" + } + if decoded, err := url.PathUnescape(raw); err == nil { + raw = strings.TrimSpace(decoded) + } + raw = strings.Trim(raw, "/") + if strings.Contains(raw, "/") { + parts := strings.SplitN(raw, "/", 2) + if parts[0] != "" && parts[1] != "" { + return parts[0] + "/" + parts[1] + } + return raw + } + if index := strings.IndexByte(raw, '-'); index > 0 && index < len(raw)-1 { + program := raw[:index] + // Keep opaque single-component test/legacy IDs such as project-a + // untouched. Real program/project IDs use the established program + // namespace (for example HTAN_INT or EllrottLab) and are converted. + if program != strings.ToLower(program) || strings.Contains(program, "_") { + return program + "/" + raw[index+1:] + } + } + return raw +} + +// Legacy returns the historical program-project storage identity for a +// canonical ID. IDs that cannot be split are returned unchanged. +func Legacy(raw string) string { + canonical := Canonical(raw) + if index := strings.IndexByte(canonical, '/'); index > 0 && index < len(canonical)-1 { + return canonical[:index] + "-" + canonical[index+1:] + } + return canonical +} + +// Aliases returns canonical first, then legacy, without duplicates. It is +// useful for compatibility reads against records written before slash IDs. +func Aliases(raw string) []string { + canonical := Canonical(raw) + legacy := Legacy(canonical) + if canonical == "" { + return nil + } + if canonical == legacy { + return []string{canonical} + } + return []string{canonical, legacy} +} + +// RequireCanonical validates a project identity at a public API boundary. +func RequireCanonical(raw string) (string, error) { + canonical := Canonical(raw) + parts := strings.SplitN(canonical, "/", 2) + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return "", fmt.Errorf("project must use program/project format") + } + return canonical, nil +} diff --git a/internal/projectid/projectid_test.go b/internal/projectid/projectid_test.go new file mode 100644 index 00000000..51f51807 --- /dev/null +++ b/internal/projectid/projectid_test.go @@ -0,0 +1,35 @@ +package projectid + +import "testing" + +func TestCanonicalAcceptsSlashAndLegacyIDs(t *testing.T) { + for _, test := range []struct { + input, want string + }{ + {"HTAN_INT/BForePC", "HTAN_INT/BForePC"}, + {"HTAN_INT-BForePC", "HTAN_INT/BForePC"}, + {"HTAN_INT-BFore-PC", "HTAN_INT/BFore-PC"}, + {"HTAN_INT%2FBForePC", "HTAN_INT/BForePC"}, + } { + if got := Canonical(test.input); got != test.want { + t.Fatalf("Canonical(%q) = %q, want %q", test.input, got, test.want) + } + } +} + +func TestAliasesPreserveLegacyStorageIdentity(t *testing.T) { + want := []string{"HTAN_INT/BForePC", "HTAN_INT-BForePC"} + got := Aliases("HTAN_INT/BForePC") + if len(got) != len(want) || got[0] != want[0] || got[1] != want[1] { + t.Fatalf("Aliases() = %#v, want %#v", got, want) + } +} + +func TestRequireCanonical(t *testing.T) { + if got, err := RequireCanonical("HTAN_INT-BForePC"); err != nil || got != "HTAN_INT/BForePC" { + t.Fatalf("RequireCanonical legacy = %q, %v", got, err) + } + if _, err := RequireCanonical("BForePC"); err == nil { + t.Fatal("RequireCanonical accepted project without program") + } +} diff --git a/internal/server/explorer_authoring_migration.go b/internal/server/explorer_authoring_migration.go new file mode 100644 index 00000000..8b4d6344 --- /dev/null +++ b/internal/server/explorer_authoring_migration.go @@ -0,0 +1,687 @@ +package server + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "sort" + "strings" + "time" + + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/explorer/bootstrap" + "github.com/calypr/loom/internal/projectid" +) + +// ExplorerAuthoringMigrationOptions describes the one-shot, server-side +// legacy cutover. It is intentionally not exposed as an HTTP operation. +type ExplorerAuthoringMigrationOptions struct { + Project string + ExplorerID string + Actor string + RequestID string + AuditOnly bool + // LegacyConfig and LegacyMapping are optional external migration inputs. + // When present they are used even if Loom has no existing Explorer record; + // the raw bytes are retained on the resulting immutable revision. + LegacyConfig []byte + LegacyMapping []byte +} + +type ExplorerAuthoringMigrationReport struct { + Mode string `json:"mode"` + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + LegacyRevisionID string `json:"legacyRevisionId,omitempty"` + SourceGeneration string `json:"sourceGeneration"` + Source string `json:"source"` + IntentDigest string `json:"intentDigest"` + ReceiptID string `json:"receiptId"` + DraftVersion int64 `json:"draftVersion"` + PublicationID string `json:"publicationId"` + DocumentCount int `json:"documentCount"` + TabCount int `json:"tabCount"` + OutputCount int `json:"outputCount"` + MaterializationID string `json:"materializationId,omitempty"` + PersistedDocument bool `json:"persistedDocument"` + PublicationPolicy string `json:"publicationPolicy"` + DraftPersisted bool `json:"draftPersisted"` + Materialized bool `json:"materialized"` + DatasetActivated bool `json:"datasetActivated"` + ExplorerActivated bool `json:"explorerActivated"` + Diagnostics []string `json:"diagnostics,omitempty"` +} + +// MigrateLegacyExplorerAuthoring converts the active legacy default, compiles +// it with the current server resolver and, unless AuditOnly is set, +// materializes it and atomically stores and activates its immutable revision. +// Any conversion/resolution failure aborts the cutover. Migration never runs a +// global draft purge; unrelated Explorer authoring state is outside its scope. +func MigrateLegacyExplorerAuthoring(ctx context.Context, service *explorer.Service, capabilities ExplorerV2LifecycleConfig, options ExplorerAuthoringMigrationOptions) (ExplorerAuthoringMigrationReport, error) { + options.Project = projectid.Canonical(options.Project) + options.ExplorerID = strings.TrimSpace(options.ExplorerID) + if options.ExplorerID == "" { + options.ExplorerID = "default" + } + if options.Actor == "" { + options.Actor = "loom-authoring-migration" + } + if options.RequestID == "" { + options.RequestID = "loom-authoring-migration-" + options.Project + "-" + options.ExplorerID + } + if service == nil || capabilities.Catalog == nil || capabilities.AuthoringCompile == nil || capabilities.Materialize == nil || capabilities.ValidateReleaseGeneration == nil || capabilities.ActivateRelease == nil { + return ExplorerAuthoringMigrationReport{}, errors.New("Explorer authoring migration requires catalog, compiler, materializer, generation validator, and release activation") + } + + mode := "apply" + if options.AuditOnly { + mode = "audit" + } + report := ExplorerAuthoringMigrationReport{Mode: mode, Project: options.Project, ExplorerID: options.ExplorerID, PublicationPolicy: "LAST_WRITE_WINS", PersistedDocument: !options.AuditOnly} + owner, legacyConfig, err := migrationSource(ctx, service, options) + if err != nil { + return report, err + } + report.LegacyRevisionID = owner.ActiveRevisionID + + snapshot, err := capabilities.Catalog(ctx, options.Project, options.ExplorerID, "") + if err != nil { + return report, fmt.Errorf("load current authoring catalog: %w", err) + } + if !snapshot.Complete { + return report, fmt.Errorf("current authoring catalog is incomplete: %v", snapshot.Diagnostics) + } + report.SourceGeneration = snapshot.Generation + + var activeBundle json.RawMessage + if owner.ActiveRevisionID != "" { + if activeRevision, revisionErr := service.Revision(ctx, owner.ActiveRevisionID); revisionErr == nil { + activeBundle = activeRevision.AuthoringBundle + } + } + var migrationDiagnostics []string + bundle, source, err := migrationBundleWithDiagnostics(legacyConfig, options.LegacyMapping, activeBundle, snapshot.Catalog, options.Project, options.ExplorerID, &migrationDiagnostics) + if err != nil { + return report, err + } + report.Source = source + report.Diagnostics = append(report.Diagnostics, migrationDiagnostics...) + report.DocumentCount = len(bundle.AuthoringDocuments()) + report.TabCount = len(bundle.AuthoringTabs()) + report.OutputCount = len(bundle.AuthoringDocuments()) + + compiled, err := capabilities.AuthoringCompile(ctx, ExplorerAuthoringV1CompileRequest{Bundle: bundle, SnapshotToken: snapshot.Token, RequestID: options.RequestID}) + if err != nil { + return report, fmt.Errorf("compile migrated Explorer authoring intent: %w", err) + } + receipt := compiled.Receipt + report.IntentDigest, report.ReceiptID = receipt.IntentDigest, receipt.ID + if options.AuditOnly { + return report, nil + } + + report.DraftVersion, report.DraftPersisted = 0, false + + revisionID := "authoring_" + strings.TrimPrefix(receipt.ID, "receipt_") + if len(options.LegacyConfig) > 0 || len(options.LegacyMapping) > 0 { + // Keep an externally seeded migration distinct from a previously + // published authoring revision with the same executable receipt. This + // preserves the old revision for rollback while making a rerun with the + // same source inputs idempotent. + revisionID = migrationRevisionID(receipt.ID, options.LegacyConfig, options.LegacyMapping) + } + if active, activeErr := service.ActiveRevision(ctx, options.Project, options.ExplorerID); activeErr == nil && active.ID == revisionID { + report.PublicationID = revisionID + report.DatasetActivated, report.ExplorerActivated, report.Materialized = true, true, true + return report, nil + } + // Dataset lifecycle storage still uses the historical project alias. The + // authoring bundle/API stays canonical, but release validation, runtime + // bindings, and activation must use the storage identity or a valid active + // generation will be reported as missing. + storageProject := projectid.Legacy(receipt.Project) + if err := capabilities.ValidateReleaseGeneration(ctx, storageProject, receipt.SourceGeneration); err != nil { + return report, fmt.Errorf("validate migrated Explorer generation: %w", err) + } + execution, err := capabilities.Materialize(ctx, receipt.Bundle, recipe.RuntimeBindings{Project: storageProject, DatasetGeneration: receipt.SourceGeneration}) + if err != nil { + return report, fmt.Errorf("materialize migrated Explorer receipt: %w", err) + } + if err := verifyQueryableOutputs(receipt.Bundle, execution); err != nil { + return report, fmt.Errorf("validate migrated Explorer materialization: %w", err) + } + report.MaterializationID, report.Materialized = execution.ID, true + materializations := explorerMaterializations(receipt.Bundle, execution) + datasetMetadata := datasetMetadataFromExecution(receipt.Bundle, receipt.SourceGeneration, execution.ResolvedSchemaDigest, execution) + publication := explorer.PublicationMetadata{State: string(explorer.RevisionReady), Generation: receipt.SourceGeneration, ExecutionID: execution.ID, UpdatedAt: time.Now().UTC()} + now := time.Now().UTC() + revision := explorer.Revision{ + ID: revisionID, Project: receipt.Project, ExplorerID: receipt.ExplorerID, + Config: receipt.CompiledConfig, ConfigDigest: receipt.IntentDigest, + AuthoringBundle: receipt.NormalizedBundle, IntentDigest: receipt.IntentDigest, + CompilationReceiptID: receipt.ID, Recipe: receipt.Bundle, RecipeDigest: receipt.RecipeDigest, + ResolvedSchemaDigest: receipt.ResolvedSchemaDigest, SourceGeneration: receipt.SourceGeneration, + Materializations: materializations, EmittedColumns: receipt.EmittedColumns, + Dataset: datasetMetadata, Publication: publication, Status: explorer.RevisionReady, + CreatedBy: options.Actor, CreatedAt: now, ReadyAt: &now, + Migration: migrationMetadata(options, legacyConfig, source), + } + if err := capabilities.ActivateRelease(ctx, storageProject, receipt.SourceGeneration, selectorsForBundle(receipt.Bundle)); err != nil { + return report, fmt.Errorf("activate migrated dataset release: %w", err) + } + report.DatasetActivated = true + published, err := service.PublishAuthoring(ctx, receipt, revision) + if err != nil { + return report, fmt.Errorf("atomically persist and activate migrated Explorer revision: %w", err) + } + report.PublicationID = published.ID + report.ExplorerActivated = true + return report, nil +} + +func migrationSource(ctx context.Context, service *explorer.Service, options ExplorerAuthoringMigrationOptions) (*explorer.Explorer, []byte, error) { + project := projectid.Canonical(options.Project) + owner, err := service.Get(ctx, project, options.ExplorerID) + if errors.Is(err, explorer.ErrNotFound) && (len(options.LegacyConfig) > 0 || len(options.LegacyMapping) > 0) { + title := migrationTitle(options.LegacyConfig, options.LegacyMapping) + owner, err = service.EnsureRepositoryExplorer(ctx, project, options.ExplorerID, title, options.Actor) + } + if err != nil { + return nil, nil, fmt.Errorf("load legacy Explorer state: %w", err) + } + legacyConfig := append([]byte(nil), options.LegacyConfig...) + if len(legacyConfig) == 0 { + legacyConfig = owner.ActiveConfig + } + if owner.ActiveRevisionID != "" { + if revision, revisionErr := service.Revision(ctx, owner.ActiveRevisionID); revisionErr == nil && len(revision.Config) > 0 { + if len(options.LegacyConfig) == 0 { + legacyConfig = revision.Config + } + } + } + if len(legacyConfig) == 0 && len(options.LegacyMapping) == 0 { + return nil, nil, errors.New("legacy Explorer has no active document") + } + return owner, legacyConfig, nil +} + +func migrationBundle(rawConfig, rawMapping, existingBundle json.RawMessage, catalog explorer.Catalog, project, explorerID string) (explorer.ExplorerAuthoringBundleV1, string, error) { + return migrationBundleWithDiagnostics(rawConfig, rawMapping, existingBundle, catalog, project, explorerID, nil) +} + +func migrationBundleWithDiagnostics(rawConfig, rawMapping, existingBundle json.RawMessage, catalog explorer.Catalog, project, explorerID string, diagnostics *[]string) (explorer.ExplorerAuthoringBundleV1, string, error) { + // Explicit migration inputs always win over whatever happens to be active + // in Loom. When both inputs are supplied, the legacy config is the source + // of field intent and the mapping is only a starting point: old mapping + // exports can contain an output with an empty candidate list even though + // the current catalog contains exact matches for its recipe fields. + if len(rawConfig) > 0 { + bundle, conversionReport, err := bootstrap.ConvertDefault(rawConfig, catalog, project) + if err == nil { + if bundle.ExplorerID != explorerID { + return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", fmt.Errorf("converted bundle explorerId %q does not match %q", bundle.ExplorerID, explorerID) + } + return bundle, "legacy-config", nil + } + if len(rawMapping) > 0 { + mapped, mappingErr := mappingAuthoringBundle(rawMapping, project, explorerID) + if mappingErr == nil { + repaired, repairDiagnostics, repairErr := repairMappedBundle(rawConfig, mapped, catalog, project, explorerID) + if repairErr == nil { + // Preserve explicit information about legacy fields that the + // current catalog does not expose. They are not guessed into a + // different field, but the migrated outputs must still contain + // every candidate that can be resolved and compiled. + if diagnostics != nil { + *diagnostics = append(*diagnostics, repairDiagnostics...) + } + return repaired, "frontend-mapping-repaired", nil + } + if conversionReportJSON, marshalErr := conversionReport.CanonicalJSON(); marshalErr == nil { + return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", fmt.Errorf("typed legacy Explorer conversion failed: %s: %w; mapping repair also failed: %v", conversionReportJSON, err, repairErr) + } + return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", fmt.Errorf("typed legacy Explorer conversion failed: %w; mapping repair also failed: %v", err, repairErr) + } + if conversionReportJSON, marshalErr := conversionReport.CanonicalJSON(); marshalErr == nil { + return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", fmt.Errorf("typed legacy Explorer conversion failed: %s: %w; decode frontend authoring mapping: %v", conversionReportJSON, err, mappingErr) + } + return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", fmt.Errorf("typed legacy Explorer conversion failed: %w; decode frontend authoring mapping: %v", err, mappingErr) + } + if conversionReportJSON, marshalErr := conversionReport.CanonicalJSON(); marshalErr == nil { + return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", fmt.Errorf("typed legacy Explorer conversion failed: %s: %w", conversionReportJSON, err) + } + return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", err + } + if len(rawMapping) > 0 { + bundle, err := mappingAuthoringBundle(rawMapping, project, explorerID) + if err != nil { + return explorer.ExplorerAuthoringBundleV1{}, "frontend-mapping", fmt.Errorf("decode frontend authoring mapping: %w", err) + } + return bundle, "frontend-mapping", nil + } + if len(existingBundle) > 0 { + bundle, err := explorer.DecodeAuthoringBundleV1ForMigration(existingBundle) + if err == nil && bundle.Project == project && bundle.ExplorerID == explorerID { + return bundle, "active-v1-bundle", nil + } + } + bundle, conversionReport, err := bootstrap.ConvertDefault(rawConfig, catalog, project) + if err != nil { + if conversionReportJSON, marshalErr := conversionReport.CanonicalJSON(); marshalErr == nil { + return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", fmt.Errorf("typed legacy Explorer conversion failed: %s: %w", conversionReportJSON, err) + } + return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", err + } + if bundle.ExplorerID != explorerID { + return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", fmt.Errorf("converted bundle explorerId %q does not match %q", bundle.ExplorerID, explorerID) + } + return bundle, "legacy-config", nil +} + +func mappingAuthoringBundle(raw []byte, project, explorerID string) (explorer.ExplorerAuthoringBundleV1, error) { + var envelope struct { + Bundle json.RawMessage `json:"bundle"` + } + if err := json.Unmarshal(raw, &envelope); err != nil { + return explorer.ExplorerAuthoringBundleV1{}, err + } + if len(envelope.Bundle) == 0 { + return explorer.ExplorerAuthoringBundleV1{}, errors.New("mapping does not contain a bundle") + } + bundle, err := explorer.DecodeAuthoringBundleV1ForMigration(envelope.Bundle) + if err != nil { + return explorer.ExplorerAuthoringBundleV1{}, err + } + if projectid.Canonical(bundle.Project) != projectid.Canonical(project) || bundle.ExplorerID != explorerID { + return explorer.ExplorerAuthoringBundleV1{}, fmt.Errorf("mapping identity %q/%q does not match %q/%q", bundle.Project, bundle.ExplorerID, project, explorerID) + } + bundle.Project = projectid.Canonical(project) + bundle.IntentDigest = "" + digest, err := bundle.DocumentDigest() + if err != nil { + return explorer.ExplorerAuthoringBundleV1{}, err + } + bundle.IntentDigest = digest + return bundle, nil +} + +// repairMappedBundle fills gaps in a frontend mapping export from the legacy +// recipe and the current Loom catalog. Mapping exports are useful migration +// hints, but they are not authoritative: older exports were able to persist a +// graph and an output while dropping all candidate IDs for that output. The +// authoring compiler cannot invent those IDs, so an empty list would compile +// into an empty column set forever. +// +// The repair deliberately resolves only explicit legacy selections. A legacy +// call such as first(root.identifier[].value) still names an exact catalog +// field and is therefore repaired from its nested select. Calls with multiple +// selections contribute each exact catalog candidate; no opaque field is +// guessed or silently replaced. +func repairMappedBundle(rawConfig []byte, bundle explorer.ExplorerAuthoringBundleV1, catalog explorer.Catalog, project, explorerID string) (explorer.ExplorerAuthoringBundleV1, []string, error) { + if len(rawConfig) == 0 { + return bundle, nil, nil + } + cfg, legacy, err := explorer.DecodeDefaultConfigV2(rawConfig, project) + if err != nil { + return explorer.ExplorerAuthoringBundleV1{}, nil, fmt.Errorf("decode legacy config for mapping repair: %w", err) + } + documents := bundle.AuthoringDocuments() + if len(documents) == 0 { + return explorer.ExplorerAuthoringBundleV1{}, nil, errors.New("mapping bundle contains no authoring documents") + } + nodeByResource := make(map[string]string, len(catalog.Nodes)) + for _, node := range catalog.Nodes { + if prior, exists := nodeByResource[node.ResourceType]; exists && prior != node.ID { + return explorer.ExplorerAuthoringBundleV1{}, nil, fmt.Errorf("catalog has multiple node IDs for resource type %q", node.ResourceType) + } + nodeByResource[node.ResourceType] = node.ID + } + selectionByID := catalog.Selections + unmapped := make([]string, 0) + for outputIndex, output := range legacy.Outputs { + documentIndex := mappedDocumentIndex(documents, output.Name) + if documentIndex < 0 { + return explorer.ExplorerAuthoringBundleV1{}, nil, fmt.Errorf("mapping bundle has no document for legacy output %q", output.Name) + } + document := &documents[documentIndex] + if strings.TrimSpace(document.BaseNodeID) == "" { + document.BaseNodeID = nodeByResource[output.RootResourceType] + } + if document.BaseNodeID == "" { + return explorer.ExplorerAuthoringBundleV1{}, nil, fmt.Errorf("legacy output %q has no catalog node for resource type %q", output.Name, output.RootResourceType) + } + if strings.TrimSpace(document.RowNodeID) == "" { + document.RowNodeID = document.BaseNodeID + } + // Preserve existing valid IDs, but remove stale IDs before adding IDs + // resolved from the current catalog. This makes reruns safe across + // catalog generations and prevents a stale mapping from poisoning the + // one-shot compile with STALE_CANDIDATE. + valid := make([]string, 0, len(document.CandidateIDs)) + seen := make(map[string]bool, len(document.CandidateIDs)) + fieldCandidates := make(map[string][]string, len(output.Fields)) + for _, candidateID := range document.CandidateIDs { + selection, ok := selectionByID[candidateID] + if !ok || selection.NodeID != document.BaseNodeID || seen[candidateID] { + continue + } + seen[candidateID] = true + valid = append(valid, candidateID) + } + for _, reference := range document.CandidateOccurrences { + if reference.OccurrenceID != "base" || seen[reference.CandidateID] { + continue + } + selection, ok := selectionByID[reference.CandidateID] + if ok && selection.NodeID == document.BaseNodeID { + seen[reference.CandidateID] = true + valid = append(valid, reference.CandidateID) + } + } + for fieldIndex, field := range output.Fields { + paths := legacySelectionPaths(field.Expr) + if len(paths) == 0 { + unmapped = append(unmapped, fmt.Sprintf("outputs[%d].fields[%d].expr", outputIndex, fieldIndex)) + continue + } + matched := false + for _, path := range paths { + candidateID, ok := catalogCandidateForPath(catalog, document.BaseNodeID, path) + if !ok { + continue + } + matched = true + if !containsString(fieldCandidates[field.Name], candidateID) { + fieldCandidates[field.Name] = append(fieldCandidates[field.Name], candidateID) + } + if !seen[candidateID] { + seen[candidateID] = true + valid = append(valid, candidateID) + } + } + if !matched { + unmapped = append(unmapped, fmt.Sprintf("outputs[%d].fields[%d].%s", outputIndex, fieldIndex, field.Name)) + } + } + if len(valid) == 0 { + return explorer.ExplorerAuthoringBundleV1{}, nil, fmt.Errorf("legacy output %q has no fields that resolve against the current catalog", output.Name) + } + sort.Strings(valid) + document.CandidateIDs = valid + // Presentation keys are emission identities and therefore change when a + // legacy candidate/node identity is rebound. Retain only bindings that + // already name a current base emission; the legacy view below restores + // labels, order, visibility, filters, and charts under canonical IDs. + canonicalPresentation := make(map[string]explorer.ExplorerPresentationBindingV1, len(valid)) + for _, candidateID := range valid { + emissionID := explorer.OpaqueID("em_", document.Output.ID+"\x00base\x00"+candidateID) + if binding, ok := document.Presentation[emissionID]; ok { + canonicalPresentation[emissionID] = binding + } + } + document.Presentation = canonicalPresentation + // The canonical authoring contract always records the exact occurrence + // for every selected candidate, including the zero-hop base occurrence. + // Legacy inference is confined to this migration and never runs while the + // Builder is reading or reconciling an already-migrated bundle. + occurrences := make([]explorer.ExplorerCandidateOccurrenceV1, 0, len(valid)) + for _, candidateID := range valid { + occurrences = append(occurrences, explorer.ExplorerCandidateOccurrenceV1{CandidateID: candidateID, OccurrenceID: "base"}) + } + document.CandidateOccurrences = occurrences + repairDocumentPresentation(cfg.Views, output, document, fieldCandidates, &unmapped) + } + bundle.Document = explorer.ExplorerBuilderDocumentV1{} + bundle.Documents = documents + bundle.Project = projectid.Canonical(project) + bundle.ExplorerID = explorerID + bundle.IntentDigest = "" + digest, err := bundle.DocumentDigest() + if err != nil { + return explorer.ExplorerAuthoringBundleV1{}, nil, fmt.Errorf("digest repaired authoring bundle: %w", err) + } + bundle.IntentDigest = digest + return bundle, unmapped, nil +} + +func repairDocumentPresentation(views []explorer.ConfigView, output recipe.Output, document *explorer.ExplorerBuilderDocumentV1, fieldCandidates map[string][]string, diagnostics *[]string) { + if document.Presentation == nil { + document.Presentation = map[string]explorer.ExplorerPresentationBindingV1{} + } + aliases := make(map[string][]string) + for fieldName, candidateIDs := range fieldCandidates { + if len(candidateIDs) != 1 { + continue + } + emissionID := explorer.OpaqueID("em_", document.Output.ID+"\x00base\x00"+candidateIDs[0]) + for _, alias := range []string{ + fieldName, + output.Name + fieldName, + output.RootResourceType + fieldName, + document.Output.Title + fieldName, + } { + key := normalizeLegacyColumnAlias(alias) + if key != "" && !containsString(aliases[key], emissionID) { + aliases[key] = append(aliases[key], emissionID) + } + } + } + resolve := func(column string) (string, bool) { + matches := aliases[normalizeLegacyColumnAlias(column)] + return firstUniqueString(matches) + } + for viewIndex, view := range views { + if !strings.EqualFold(strings.TrimSpace(view.Output), strings.TrimSpace(output.Name)) { + continue + } + for columnIndex, column := range view.Table.Columns { + emissionID, ok := resolve(column.Column) + if !ok { + if hasPresentationTableOrder(document.Presentation, columnIndex) { + continue + } + *diagnostics = append(*diagnostics, fmt.Sprintf("views[%d].table.columns[%d].%s", viewIndex, columnIndex, column.Column)) + continue + } + binding := document.Presentation[emissionID] + if strings.TrimSpace(binding.Label) == "" { + binding.Label = firstNonEmpty(column.Label, column.Column) + } + if binding.Visible == nil { + visible := column.Visible + binding.Visible = &visible + } + if binding.Order == nil { + order := columnIndex + binding.Order = &order + } + if binding.Table == nil { + binding.Table = &explorer.ExplorerTableBindingV1{} + } + document.Presentation[emissionID] = binding + } + for filterIndex, filter := range view.Filters { + emissionID, ok := resolve(filter.Column) + if !ok { + if presentationBindingCount(document.Presentation, "filter") > filterIndex { + continue + } + *diagnostics = append(*diagnostics, fmt.Sprintf("views[%d].filters[%d].%s", viewIndex, filterIndex, filter.Column)) + continue + } + binding := document.Presentation[emissionID] + if binding.Filter == nil { + binding.Filter = &explorer.ExplorerFilterBindingV1{Label: filter.Label} + } + document.Presentation[emissionID] = binding + } + for chartIndex, chart := range view.Charts { + emissionID, ok := resolve(chart.Column) + if !ok { + if presentationBindingCount(document.Presentation, "chart") > chartIndex { + continue + } + *diagnostics = append(*diagnostics, fmt.Sprintf("views[%d].charts[%d].%s", viewIndex, chartIndex, chart.Column)) + continue + } + binding := document.Presentation[emissionID] + if binding.Chart == nil { + binding.Chart = &explorer.ExplorerChartBindingV1{Type: chart.Type, Title: chart.Title} + } + document.Presentation[emissionID] = binding + } + } +} + +func hasPresentationTableOrder(presentation map[string]explorer.ExplorerPresentationBindingV1, order int) bool { + for _, binding := range presentation { + if binding.Table != nil && binding.Order != nil && *binding.Order == order { + return true + } + } + return false +} + +func presentationBindingCount(presentation map[string]explorer.ExplorerPresentationBindingV1, kind string) int { + count := 0 + for _, binding := range presentation { + if kind == "filter" && binding.Filter != nil || kind == "chart" && binding.Chart != nil { + count++ + } + } + return count +} + +func normalizeLegacyColumnAlias(value string) string { + var normalized strings.Builder + for _, character := range strings.ToLower(strings.TrimSpace(value)) { + if character >= 'a' && character <= 'z' || character >= '0' && character <= '9' { + normalized.WriteRune(character) + } + } + return normalized.String() +} + +func firstUniqueString(values []string) (string, bool) { + if len(values) != 1 { + return "", false + } + return values[0], true +} + +func mappedDocumentIndex(documents []explorer.ExplorerBuilderDocumentV1, output string) int { + stable := explorer.StableExplorerID(output) + for index, document := range documents { + if document.Output.ID == stable || strings.EqualFold(document.Output.ID, output) || strings.EqualFold(document.Output.Title, output) { + return index + } + } + return -1 +} + +func legacySelectionPaths(expression recipe.Expression) []string { + paths := make([]string, 0, 1) + var walk func(recipe.Expression) + walk = func(current recipe.Expression) { + if strings.TrimSpace(current.Select) != "" { + path := strings.TrimSpace(current.Select) + if !containsString(paths, path) { + paths = append(paths, path) + } + } + for _, argument := range current.Args { + walk(argument) + } + } + walk(expression) + return paths +} + +func catalogCandidateForPath(catalog explorer.Catalog, nodeID, path string) (string, bool) { + want := normalizeCatalogSelectionPath(path) + for candidateID, selection := range catalog.Selections { + if selection.NodeID != nodeID || normalizeCatalogSelectionPath(selection.Select) != want { + continue + } + return candidateID, true + } + return "", false +} + +func normalizeCatalogSelectionPath(path string) string { + path = strings.TrimSpace(path) + if strings.HasPrefix(path, "root.") { + path = strings.TrimPrefix(path, "root.") + } + return strings.ToLower(strings.ReplaceAll(path, "[]", "")) +} + +func containsString(values []string, value string) bool { + for _, candidate := range values { + if candidate == value { + return true + } + } + return false +} + +func migrationTitle(config, mapping []byte) string { + var mappingEnvelope struct { + Title string `json:"title"` + Bundle struct { + Title string `json:"title"` + } `json:"bundle"` + } + if len(mapping) > 0 && json.Unmarshal(mapping, &mappingEnvelope) == nil { + if strings.TrimSpace(mappingEnvelope.Title) != "" { + return mappingEnvelope.Title + } + if strings.TrimSpace(mappingEnvelope.Bundle.Title) != "" { + return mappingEnvelope.Bundle.Title + } + } + var envelope struct { + Explorer struct { + Title string `json:"title"` + } `json:"explorer"` + } + if len(config) > 0 && json.Unmarshal(config, &envelope) == nil && strings.TrimSpace(envelope.Explorer.Title) != "" { + return envelope.Explorer.Title + } + return "Explorer" +} + +func migrationMetadata(options ExplorerAuthoringMigrationOptions, originalConfig []byte, source string) *explorer.MigrationMetadata { + metadata := &explorer.MigrationMetadata{ + Kind: "ExplorerAuthoringMigration", + Source: source, + SourceProject: projectid.Canonical(options.Project), + SourceExplorerID: options.ExplorerID, + OriginalConfig: append([]byte(nil), originalConfig...), + OriginalMapping: append([]byte(nil), options.LegacyMapping...), + Actor: options.Actor, + RequestID: options.RequestID, + MigratedAt: time.Now().UTC(), + } + metadata.OriginalConfigDigest = rawDigest(originalConfig) + metadata.OriginalMappingDigest = rawDigest(options.LegacyMapping) + return metadata +} + +func rawDigest(raw []byte) string { + if len(raw) == 0 { + return "" + } + sum := sha256.Sum256(raw) + return "sha256:" + hex.EncodeToString(sum[:]) +} + +func migrationRevisionID(receiptID string, config, mapping []byte) string { + sum := sha256.Sum256([]byte(receiptID + "\x00" + rawDigest(config) + "\x00" + rawDigest(mapping))) + return "authoring_migration_" + hex.EncodeToString(sum[:]) +} diff --git a/internal/server/explorer_authoring_migration_test.go b/internal/server/explorer_authoring_migration_test.go new file mode 100644 index 00000000..8983b0a4 --- /dev/null +++ b/internal/server/explorer_authoring_migration_test.go @@ -0,0 +1,197 @@ +package server + +import ( + "context" + "encoding/json" + "testing" + + "github.com/calypr/loom/internal/explorer" +) + +func TestMappingAuthoringBundleCanonicalizesIdentityAndDigest(t *testing.T) { + input := map[string]any{ + "title": "BForePC", + "bundle": map[string]any{ + "apiVersion": explorer.ExplorerAuthoringV1APIVersion, + "kind": explorer.ExplorerAuthoringV1Kind, + "project": "HTAN_INT%2FBForePC", + "explorerId": "default", + "title": "BForePC", + "documents": []any{map[string]any{ + "kind": "ExplorerBuilderDocument", + "output": map[string]any{"id": "groupmember", "title": "GroupMember"}, + "baseNodeId": "n_group", + "rowNodeId": "n_group", + }}, + }, + } + raw, err := json.Marshal(input) + if err != nil { + t.Fatal(err) + } + bundle, err := mappingAuthoringBundle(raw, "HTAN_INT/BForePC", "default") + if err != nil { + t.Fatal(err) + } + if bundle.Project != "HTAN_INT/BForePC" || bundle.ExplorerID != "default" || bundle.IntentDigest == "" { + t.Fatalf("unexpected canonical bundle: %#v", bundle) + } + if err := bundle.Validate(); err != nil { + t.Fatalf("canonical bundle does not validate: %v", err) + } +} + +func TestMigrationSourceCreatesMissingRepositoryIdentityAndPreservesExternalConfig(t *testing.T) { + store := explorer.NewMemoryStore() + service, err := explorer.NewService(store) + if err != nil { + t.Fatal(err) + } + rawConfig := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"HTAN_INT-BForePC","explorer":{"id":"default","title":"BForePC","management":"repository"},"unknownFrontendField":{"preserve":true}}`) + owner, config, err := migrationSource(context.Background(), service, ExplorerAuthoringMigrationOptions{ + Project: "HTAN_INT%252FBForePC", ExplorerID: "default", Actor: "test", LegacyConfig: rawConfig, + }) + if err != nil { + t.Fatal(err) + } + if owner.Project != "HTAN_INT-BForePC" || owner.ExplorerID != "default" || owner.Title != "BForePC" { + t.Fatalf("unexpected seeded owner: %#v", owner) + } + if string(config) != string(rawConfig) { + t.Fatalf("migration did not preserve original config bytes") + } + if _, err := service.Get(context.Background(), "HTAN_INT/BForePC", "default"); err != nil { + t.Fatalf("seeded repository identity is not discoverable: %v", err) + } +} + +func TestMigrationSourceCanSeedFromMappingWithoutLegacyConfig(t *testing.T) { + store := explorer.NewMemoryStore() + service, err := explorer.NewService(store) + if err != nil { + t.Fatal(err) + } + rawMapping := []byte(`{"title":"BForePC","bundle":{"apiVersion":"loom.calypr.org/explorer-authoring/v1","kind":"ExplorerAuthoringBundle","project":"HTAN_INT/BForePC","explorerId":"default","title":"BForePC","documents":[]}}`) + owner, config, err := migrationSource(context.Background(), service, ExplorerAuthoringMigrationOptions{ + Project: "HTAN_INT/BForePC", ExplorerID: "default", Actor: "test", LegacyMapping: rawMapping, + }) + if err != nil { + t.Fatal(err) + } + if owner.Project != "HTAN_INT-BForePC" || owner.Title != "BForePC" { + t.Fatalf("unexpected seeded owner: %#v", owner) + } + if len(config) != 0 { + t.Fatalf("mapping-only migration unexpectedly returned a legacy config: %q", config) + } +} + +func TestMigrationBundlePrefersExplicitLegacyConfigOverActiveBundle(t *testing.T) { + rawConfig := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Default","management":"repository"},"recipe":{"recipeSchemaVersion":1,"name":"legacy","translationVersion":"v1","outputs":[{"name":"patient","rootResourceType":"Patient","rowGrain":"patient","fields":[{"name":"id","fieldRef":"Patient.id","expr":{"select":"root.id"}}]}]},"views":[]}`) + catalog := explorer.Catalog{Nodes: []explorer.CatalogNode{{ID: "n_patient", ResourceType: "Patient"}}, Selections: map[string]explorer.CatalogSelection{ + "s_patient_id": {ID: "s_patient_id", NodeID: "n_patient", FieldRef: "Patient.id", Select: "id"}, + }} + active := explorer.ExplorerAuthoringBundleV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, Project: "project-a", ExplorerID: "default", Documents: []explorer.ExplorerBuilderDocumentV1{{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "old"}, BaseNodeID: "n_patient", RowNodeID: "n_patient"}}} + bundle, source, err := migrationBundle(rawConfig, nil, mustAuthoringJSON(t, active), catalog, "project-a", "default") + if err != nil { + t.Fatal(err) + } + if source != "legacy-config" || len(bundle.AuthoringDocuments()) != 1 || bundle.AuthoringDocuments()[0].Output.ID != "patient" { + t.Fatalf("explicit config was not selected: source=%q bundle=%#v", source, bundle) + } +} + +func TestMigrationBundleRepairsEmptyMappingCandidatesFromLegacyConfig(t *testing.T) { + rawConfig := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Default","management":"repository"},"recipe":{"recipeSchemaVersion":1,"name":"legacy","translationVersion":"v1","outputs":[{"name":"DocumentReference","rootResourceType":"DocumentReference","rowGrain":"file","fields":[{"name":"id","expr":{"select":"root.id"}},{"name":"url","expr":{"call":"first","args":[{"select":"root.content[].attachment.url"}]}}]}]},"views":[{"id":"file","title":"Files","output":"DocumentReference","table":{"columns":[{"column":"document_reference_id","label":"Identifier","visible":true},{"column":"document_reference_url","label":"URL","visible":false},{"column":"project_id","label":"Project","visible":true}]}}]}`) + mappingBundle := explorer.ExplorerAuthoringBundleV1{ + APIVersion: explorer.ExplorerAuthoringV1APIVersion, + Kind: explorer.ExplorerAuthoringV1Kind, + Project: "project-a", + ExplorerID: "default", + Title: "Default", + Documents: []explorer.ExplorerBuilderDocumentV1{{ + Kind: explorer.ExplorerBuilderV1Kind, + Output: explorer.ExplorerOutputIdentityV1{ID: "file", Title: "DocumentReference"}, + BaseNodeID: "n_document", + RowNodeID: "n_document", + }}, + } + rawMapping, err := json.Marshal(map[string]any{"bundle": mappingBundle}) + if err != nil { + t.Fatal(err) + } + catalog := explorer.Catalog{ + Nodes: []explorer.CatalogNode{{ID: "n_document", ResourceType: "DocumentReference"}}, + Selections: map[string]explorer.CatalogSelection{ + "s_document_id": {ID: "s_document_id", NodeID: "n_document", FieldRef: "DocumentReference.id", Select: "id", LogicalType: "scalar", Filterable: true}, + "s_document_url": {ID: "s_document_url", NodeID: "n_document", FieldRef: "DocumentReference.content_attachment_url", Select: "content[].attachment.url", LogicalType: "scalar", Filterable: true}, + }, + } + var diagnostics []string + bundle, source, err := migrationBundleWithDiagnostics(rawConfig, rawMapping, nil, catalog, "project-a", "default", &diagnostics) + if err != nil { + t.Fatal(err) + } + if source != "frontend-mapping-repaired" { + t.Fatalf("source=%q, want frontend-mapping-repaired", source) + } + documents := bundle.AuthoringDocuments() + if len(documents) != 1 || len(documents[0].CandidateIDs) != 2 { + t.Fatalf("repaired documents=%#v", documents) + } + if documents[0].CandidateIDs[0] != "s_document_id" || documents[0].CandidateIDs[1] != "s_document_url" { + t.Fatalf("candidate IDs=%v", documents[0].CandidateIDs) + } + idEmission := explorer.OpaqueID("em_", "file\x00base\x00s_document_id") + urlEmission := explorer.OpaqueID("em_", "file\x00base\x00s_document_url") + idPresentation, ok := documents[0].Presentation[idEmission] + if !ok || idPresentation.Label != "Identifier" || idPresentation.Table == nil || idPresentation.Visible == nil || !*idPresentation.Visible || idPresentation.Order == nil || *idPresentation.Order != 0 { + t.Fatalf("identifier presentation=%#v", idPresentation) + } + urlPresentation, ok := documents[0].Presentation[urlEmission] + if !ok || urlPresentation.Label != "URL" || urlPresentation.Table == nil || urlPresentation.Visible == nil || *urlPresentation.Visible || urlPresentation.Order == nil || *urlPresentation.Order != 1 { + t.Fatalf("URL presentation=%#v", urlPresentation) + } + if len(diagnostics) != 1 || diagnostics[0] != "views[0].table.columns[2].project_id" { + t.Fatalf("repair diagnostics=%v", diagnostics) + } + snapshot, err := explorer.NewCatalogSnapshot("project-a", "generation-a", "scope-a", catalog, true, false, nil) + if err != nil { + t.Fatal(err) + } + compiled, err := ResolveAuthoringBundle(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: bundle, SnapshotToken: snapshot.Token}) + if err != nil { + t.Fatal(err) + } + if len(compiled.ResolvedBindings) != 1 || len(compiled.ResolvedBindings[0].CandidateEmissions) != 2 { + t.Fatalf("resolved bindings=%#v", compiled.ResolvedBindings) + } +} + +func TestResolvedAuthoringBindingSerializesEmptyCandidateEmissionsAsArray(t *testing.T) { + catalog := explorer.Catalog{Nodes: []explorer.CatalogNode{{ID: "n_patient", ResourceType: "Patient"}}} + binding := resolvedAuthoringBinding(explorer.ExplorerBuilderDocumentV1{ + Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_patient", RowNodeID: "n_patient", + }, catalog, nil, nil, nil) + raw, err := json.Marshal(binding) + if err != nil { + t.Fatal(err) + } + var payload map[string]any + if err := json.Unmarshal(raw, &payload); err != nil { + t.Fatal(err) + } + emissions, ok := payload["candidateEmissions"].([]any) + if !ok || len(emissions) != 0 { + t.Fatalf("candidateEmissions serialized as %s", raw) + } +} + +func mustAuthoringJSON(t *testing.T, bundle explorer.ExplorerAuthoringBundleV1) []byte { + t.Helper() + raw, err := bundle.CanonicalJSON() + if err != nil { + t.Fatal(err) + } + return raw +} diff --git a/internal/server/explorer_authoring_normalization_test.go b/internal/server/explorer_authoring_normalization_test.go new file mode 100644 index 00000000..06292477 --- /dev/null +++ b/internal/server/explorer_authoring_normalization_test.go @@ -0,0 +1,223 @@ +package server + +import ( + "context" + "errors" + "strings" + "testing" + + "github.com/calypr/loom/internal/explorer" +) + +func TestNormalizeDocumentMapsZeroHopCandidateToBase(t *testing.T) { + snapshot := authoringTestSnapshot(t) + document := explorer.ExplorerBuilderDocumentV1{ + Kind: explorer.ExplorerBuilderV1Kind, + Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, + BaseNodeID: "n_base", + RowNodeID: "n_base", + CandidateIDs: []string{ + "s_base", + }, + } + result, err := ResolveAuthoringBundle(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { + return snapshot, nil + }, ExplorerAuthoringV1CompileRequest{ + Bundle: authoringTestBundleWithoutCandidateOccurrences(document), + SnapshotToken: snapshot.Token, + }) + if err != nil { + t.Fatal(err) + } + got := result.Bundle.AuthoringDocuments()[0].CandidateOccurrences + if len(got) != 1 || got[0].CandidateID != "s_base" || got[0].OccurrenceID != "base" { + t.Fatalf("candidate occurrences=%#v", got) + } +} + +func TestNormalizeDocumentMapsOneHopCandidateToOnlyMatchingOccurrence(t *testing.T) { + snapshot := authoringTestSnapshot(t) + document := explorer.ExplorerBuilderDocumentV1{ + Kind: explorer.ExplorerBuilderV1Kind, + Output: explorer.ExplorerOutputIdentityV1{ID: "observations"}, + BaseNodeID: "n_base", + RowNodeID: "n_child", + RouteEdgeIDs: []string{"e_forward"}, + CandidateIDs: []string{"s_child"}, + } + result, err := ResolveAuthoringBundle(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { + return snapshot, nil + }, ExplorerAuthoringV1CompileRequest{ + Bundle: authoringTestBundleWithoutCandidateOccurrences(document), + SnapshotToken: snapshot.Token, + }) + if err != nil { + t.Fatal(err) + } + got := result.Bundle.AuthoringDocuments()[0] + if len(got.CandidateOccurrences) != 1 || got.CandidateOccurrences[0].CandidateID != "s_child" || got.CandidateOccurrences[0].OccurrenceID == "base" { + t.Fatalf("normalized one-hop document=%#v", got) + } + if got.CandidateOccurrences[0].OccurrenceID != got.RouteOccurrences[1].ID { + t.Fatalf("candidate occurrence=%#v route occurrences=%#v", got.CandidateOccurrences, got.RouteOccurrences) + } +} + +func TestNormalizeDocumentRequiresOccurrenceForRepeatedResource(t *testing.T) { + catalog := explorer.Catalog{ + Nodes: []explorer.CatalogNode{ + {ID: "n_base", ResourceType: "Patient"}, + {ID: "n_child", ResourceType: "Observation"}, + }, + Edges: []explorer.CatalogEdge{ + {ID: "e_forward", FromNodeID: "n_base", ToNodeID: "n_child"}, + {ID: "e_back", FromNodeID: "n_child", ToNodeID: "n_base"}, + }, + Selections: map[string]explorer.CatalogSelection{ + "s_base": {ID: "s_base", NodeID: "n_base", Select: "id"}, + }, + } + document := explorer.ExplorerBuilderDocumentV1{ + Kind: explorer.ExplorerBuilderV1Kind, + Output: explorer.ExplorerOutputIdentityV1{ID: "patients"}, + BaseNodeID: "n_base", + RowNodeID: "n_base", + RouteEdgeIDs: []string{"e_forward", "e_back"}, + CandidateIDs: []string{"s_base"}, + } + snapshot, err := explorer.NewCatalogSnapshot("project-a", "generation-a", "scope-a", catalog, true, false, nil) + if err != nil { + t.Fatal(err) + } + _, err = ResolveAuthoringBundle(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { + return snapshot, nil + }, ExplorerAuthoringV1CompileRequest{ + Bundle: authoringTestBundleWithoutCandidateOccurrences(document), + SnapshotToken: snapshot.Token, + }) + if err == nil || !strings.Contains(err.Error(), "CANDIDATE_OCCURRENCE_REQUIRED") { + t.Fatalf("ambiguous candidate error=%v", err) + } + var authoringErr *explorer.AuthoringError + if !errors.As(err, &authoringErr) || len(authoringErr.Diagnostic.Details["validOccurrences"].([]string)) != 2 { + t.Fatalf("ambiguous candidate details=%#v", err) + } +} + +func TestNormalizeDocumentRejectsStaleAndMismatchedCandidates(t *testing.T) { + snapshot := authoringTestSnapshot(t) + baseBinding := explorer.ExplorerResolvedBindingV1{ + BaseNodeID: "n_base", + RouteOccurrences: []explorer.ExplorerResolvedOccurrenceV1{ + {OccurrenceID: "base", Index: 0, NodeID: "n_base"}, + }, + } + unknown := explorer.ExplorerBuilderDocumentV1{CandidateIDs: []string{"unknown"}} + if _, err := normalizeDocument(unknown, snapshot.Catalog, baseBinding); err == nil || !strings.Contains(err.Error(), "STALE_CANDIDATE_ID") { + t.Fatalf("unknown candidate error=%v", err) + } + mismatch := explorer.ExplorerBuilderDocumentV1{CandidateIDs: []string{"s_child"}, BaseNodeID: "n_base"} + if _, err := normalizeDocument(mismatch, snapshot.Catalog, baseBinding); err == nil || !strings.Contains(err.Error(), "SELECTION_NODE_MISMATCH") { + t.Fatalf("mismatched candidate error=%v", err) + } +} + +func TestNormalizeDocumentDropsDownstreamSelectionsAfterRouteTruncation(t *testing.T) { + catalog := explorer.Catalog{ + Nodes: []explorer.CatalogNode{ + {ID: "n_base", ResourceType: "Patient"}, + {ID: "n_child", ResourceType: "Observation"}, + {ID: "n_grandchild", ResourceType: "Task"}, + }, + Edges: []explorer.CatalogEdge{{ID: "e_forward", FromNodeID: "n_base", ToNodeID: "n_child"}}, + Selections: map[string]explorer.CatalogSelection{ + "s_child": {ID: "s_child", NodeID: "n_child", Select: "status"}, + "s_grandchild": {ID: "s_grandchild", NodeID: "n_grandchild", Select: "status"}, + }, + } + document := explorer.ExplorerBuilderDocumentV1{ + Kind: explorer.ExplorerBuilderV1Kind, + Output: explorer.ExplorerOutputIdentityV1{ID: "observations"}, + BaseNodeID: "n_base", + RowNodeID: "n_child", + RouteEdgeIDs: []string{"e_forward"}, + RouteOccurrences: []explorer.ExplorerRouteOccurrenceV1{ + {ID: "base", Index: 0, NodeID: "n_base"}, + {ID: "child", Index: 1, NodeID: "n_child"}, + {ID: "grandchild", Index: 2, NodeID: "n_grandchild"}, + }, + CandidateIDs: []string{"s_child", "s_grandchild"}, + CandidateOccurrences: []explorer.ExplorerCandidateOccurrenceV1{ + {CandidateID: "s_child", OccurrenceID: "child"}, + {CandidateID: "s_grandchild", OccurrenceID: "grandchild"}, + }, + } + structural, err := normalizeStructuralAuthoringRoutes([]explorer.ExplorerBuilderDocumentV1{document}, catalog) + if err != nil { + t.Fatal(err) + } + normalized, err := normalizeAuthoringDocuments(structural, catalog) + if err != nil { + t.Fatal(err) + } + got := normalized[0] + if len(got.CandidateIDs) != 1 || got.CandidateIDs[0] != "s_child" || len(got.CandidateOccurrences) != 1 || got.CandidateOccurrences[0].OccurrenceID != "child" { + t.Fatalf("truncated route retained downstream selection: %#v", got) + } +} + +func TestNormalizeDocumentIsIdempotent(t *testing.T) { + snapshot := authoringTestSnapshot(t) + document := explorer.ExplorerBuilderDocumentV1{ + Kind: explorer.ExplorerBuilderV1Kind, + Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, + BaseNodeID: "n_base", + RowNodeID: "n_base", + CandidateIDs: []string{ + "s_base", + }, + } + firstStructural, err := normalizeStructuralAuthoringRoutes([]explorer.ExplorerBuilderDocumentV1{document}, snapshot.Catalog) + if err != nil { + t.Fatal(err) + } + first, err := normalizeAuthoringDocuments(firstStructural, snapshot.Catalog) + if err != nil { + t.Fatal(err) + } + secondStructural, err := normalizeStructuralAuthoringRoutes(first, snapshot.Catalog) + if err != nil { + t.Fatal(err) + } + second, err := normalizeAuthoringDocuments(secondStructural, snapshot.Catalog) + if err != nil { + t.Fatal(err) + } + firstBundle := authoringTestBundleWithoutCandidateOccurrences(first[0]) + firstBundle.Documents = first + firstBundle.Document = explorer.ExplorerBuilderDocumentV1{} + secondBundle := authoringTestBundleWithoutCandidateOccurrences(second[0]) + secondBundle.Documents = second + secondBundle.Document = explorer.ExplorerBuilderDocumentV1{} + firstDigest, err := firstBundle.DocumentDigest() + if err != nil { + t.Fatal(err) + } + secondDigest, err := secondBundle.DocumentDigest() + if err != nil { + t.Fatal(err) + } + if firstDigest != secondDigest { + t.Fatalf("normalization is not idempotent: first=%s second=%s", firstDigest, secondDigest) + } +} + +func authoringTestBundleWithoutCandidateOccurrences(document explorer.ExplorerBuilderDocumentV1) explorer.ExplorerAuthoringBundleV1 { + return explorer.ExplorerAuthoringBundleV1{ + APIVersion: explorer.ExplorerAuthoringV1APIVersion, + Kind: explorer.ExplorerAuthoringV1Kind, + Project: "project-a", + ExplorerID: "custom", + Documents: []explorer.ExplorerBuilderDocumentV1{document}, + } +} diff --git a/internal/server/explorer_authoring_v1.go b/internal/server/explorer_authoring_v1.go new file mode 100644 index 00000000..a91f2430 --- /dev/null +++ b/internal/server/explorer_authoring_v1.go @@ -0,0 +1,878 @@ +package server + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "regexp" + "sort" + "strconv" + "strings" + "time" + + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataframe/recipe/engine" + "github.com/calypr/loom/internal/dataframe/spec" + "github.com/calypr/loom/internal/explorer" + fhirschema "github.com/calypr/loom/internal/fhir/schema" + "github.com/calypr/loom/internal/projectid" +) + +var authoringIDPattern = regexp.MustCompile(`^[a-z][a-z0-9-]{0,63}$`) + +type ExplorerAuthoringV1CompileRequest struct { + Bundle explorer.ExplorerAuthoringBundleV1 + SnapshotToken string + RequestID string +} + +type ExplorerAuthoringV1CompileResult struct { + Bundle explorer.ExplorerAuthoringBundleV1 + CanonicalBundle []byte + Receipt explorer.CompilationReceipt + RecipeDigest string + ResolvedSchemaDigest string + SourceGeneration string + EmittedColumns []explorer.EmittedColumn + ResolvedBindings []explorer.ExplorerResolvedBindingV1 + // Snapshot is the exact catalog snapshot used for route/candidate + // resolution. Builder responses reuse it so bindings and catalog metadata + // cannot drift across two catalog reads. + Snapshot explorer.CatalogSnapshot + Diagnostics []explorer.AuthoringDiagnostic +} + +// ResolveAuthoringBundle is the single authoritative authoring phase used by +// Builder reads, preview, publication, and compilation. It resolves opaque +// intent against exactly one catalog snapshot, validates route occurrences and +// candidates, lowers the native recipe, compiles it, and returns the resolved +// Builder bindings alongside the executable receipt. +func ResolveAuthoringBundle(ctx context.Context, recipeEngine *engine.Engine, catalogReader explorerV2CatalogReader, request ExplorerAuthoringV1CompileRequest) (ExplorerAuthoringV1CompileResult, error) { + bundle := request.Bundle + // Intent digests describe the pre-resolution document. Legacy documents + // may have been persisted before candidateOccurrences became canonical, so + // validate the strict shape first and verify the digest only after the + // catalog-aware normalizer has produced the canonical document. + shape := bundle + shape.IntentDigest = "" + if err := shape.Validate(); err != nil { + return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(err, request.RequestID) + } + bundle.Project = projectid.Canonical(bundle.Project) + documents := bundle.AuthoringDocuments() + if len(documents) == 0 { + return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(authoringSemantic("intent", "$.bundle.documents", "EMPTY_AUTHORING_BUNDLE", "preview and publish require at least one output", nil), request.RequestID) + } + // Normalize compatibility single-document input before it is stored in a + // receipt or returned to the Builder. One Explorer may contain multiple + // output documents; the canonical wire form is always documents[]. + bundle.Document = explorer.ExplorerBuilderDocumentV1{} + bundle.Documents = documents + if request.SnapshotToken == "" { + return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(explorerConflict("snapshot", "SNAPSHOT_REQUIRED", "a catalog snapshot token is required", nil), request.RequestID) + } + if catalogReader == nil { + return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(explorerUnavailable("catalog", "CATALOG_UNAVAILABLE", "Explorer authoring catalog is not configured"), request.RequestID) + } + snapshot, err := catalogReader(ctx, bundle.Project, bundle.ExplorerID, "") + if err != nil { + if snapshot.Token != "" && !snapshot.Complete { + return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(explorerUnavailable("catalog", "CATALOG_INCOMPLETE", "Explorer authoring catalog is incomplete"), request.RequestID) + } + return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(explorerConflict("catalog", "CATALOG_SNAPSHOT_FAILED", err.Error(), nil), request.RequestID) + } + if err := snapshot.ValidateToken(request.SnapshotToken); err != nil { + code := "STALE_CATALOG_SNAPSHOT" + if errors.Is(err, explorer.ErrIncompleteCatalog) { + code = "CATALOG_INCOMPLETE" + } + return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(explorerConflict("catalog", code, err.Error(), map[string]any{"snapshotToken": request.SnapshotToken}), request.RequestID) + } + documents, err = normalizeStructuralAuthoringRoutes(documents, snapshot.Catalog) + if err != nil { + return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(err, request.RequestID) + } + documents, err = normalizeAuthoringDocuments(documents, snapshot.Catalog) + if err != nil { + return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(err, request.RequestID) + } + bundle.Documents = documents + digest, err := bundle.DocumentDigest() + if err != nil { + return ExplorerAuthoringV1CompileResult{}, err + } + // The compatibility normalization above changes canonical authoring intent. + // Return the matching digest with the normalized bundle so a subsequent + // preview or publish can round-trip the Builder response without a 409. + bundle.IntentDigest = digest + + var native recipe.Bundle + var emitted []explorer.EmittedColumn + var mappings []explorer.IdentityMapping + var bindings []explorer.ExplorerResolvedBindingV1 + for _, document := range documents { + path, routeErr := resolveAuthoringRoute(document, snapshot.Catalog) + if routeErr != nil { + return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(routeErr, request.RequestID) + } + assignments, candidateErr := resolveAuthoringCandidates(document, snapshot.Catalog, path) + if candidateErr != nil { + return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(candidateErr, request.RequestID) + } + documentEmitted, documentMappings := authoringEmissions(document, snapshot.Catalog, assignments) + if presentationErr := validateAuthoringPresentation(document, documentEmitted); presentationErr != nil { + return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(presentationErr, request.RequestID) + } + part, lowerErr := lowerAuthoringDocument(bundle.Project, bundle.ExplorerID, document, snapshot.Catalog, path, assignments) + if lowerErr != nil { + return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(lowerErr, request.RequestID) + } + if len(part.Outputs) != 1 { + return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(authoringSemantic("lower", "$.documents", "AUTHORING_OUTPUT_LOWERING_FAILED", "each authoring document must lower to exactly one recipe output", nil), request.RequestID) + } + if len(native.Outputs) == 0 { + native = part + } else { + native.Outputs = append(native.Outputs, part.Outputs...) + } + emitted = append(emitted, documentEmitted...) + mappings = append(mappings, documentMappings...) + bindings = append(bindings, resolvedAuthoringBinding(document, snapshot.Catalog, path, assignments, documentEmitted)) + } + if err := native.Validate(); err != nil { + return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(authoringSemanticFromRecipe(err), request.RequestID) + } + + recipeDigest, resolvedSchemaDigest := "", snapshot.ResolvedSchemaDigest + if recipeEngine != nil { + resolved, resolveErr := recipeEngine.ResolveBundle(ctx, native, recipe.RuntimeBindings{Project: projectid.Legacy(bundle.Project), DatasetGeneration: snapshot.Generation}) + if resolveErr != nil { + return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(authoringSemanticFromCompile(resolveErr), request.RequestID) + } + recipeDigest = resolved.StoredRecipeDigest + resolvedSchemaDigest = resolved.ResolvedSchemaDigest + // The lowerer is authoritative for physical public columns. Keep the + // intent-to-emission IDs stable, while using the compiler schema only to + // fill logical type metadata. + kindByColumn := map[string]string{} + for _, output := range resolved.Compiled.Outputs { + for _, column := range output.OutputSchema { + if !column.Internal { + kindByColumn[column.Name] = column.Kind + } + } + } + for i := range emitted { + if kind := kindByColumn[generatedFieldName(emitted[i].CandidateID, emitted[i].OccurrenceID)]; kind != "" { + emitted[i].LogicalType = kind + } + } + } else { + recipeDigest, _ = native.Digest() + } + if recipeDigest == "" { + recipeDigest, _ = native.Digest() + } + canonical, err := bundle.CanonicalJSON() + if err != nil { + return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(err, request.RequestID) + } + compiledConfig, err := authoringCompiledConfig(bundle, native, emitted) + if err != nil { + return ExplorerAuthoringV1CompileResult{}, err + } + receipt := explorer.CompilationReceipt{ + Project: bundle.Project, ExplorerID: bundle.ExplorerID, IntentDigest: digest, + SnapshotToken: request.SnapshotToken, SourceGeneration: snapshot.Generation, + RecipeDigest: recipeDigest, ResolvedSchemaDigest: resolvedSchemaDigest, + NormalizedBundle: append([]byte(nil), canonical...), Bundle: native, + CompiledConfig: compiledConfig, IdentityMappings: mappings, EmittedColumns: emitted, + CreatedAt: time.Now().UTC(), RequestID: request.RequestID, + } + receipt.OutputFingerprints = map[string]string{} + for _, output := range native.Outputs { + receipt.OutputFingerprints[output.Name] = outputFingerprint(native, bundle.Project, snapshot.Generation) + } + receipt.ID, err = explorer.ReceiptID(receipt) + if err != nil { + return ExplorerAuthoringV1CompileResult{}, err + } + return ExplorerAuthoringV1CompileResult{Bundle: bundle, CanonicalBundle: canonical, Receipt: receipt, RecipeDigest: recipeDigest, ResolvedSchemaDigest: resolvedSchemaDigest, SourceGeneration: snapshot.Generation, EmittedColumns: emitted, ResolvedBindings: bindings, Snapshot: snapshot, Diagnostics: []explorer.AuthoringDiagnostic{}}, nil +} + +// normalizeStructuralAuthoringRoutes lets a client append exact catalog edge +// IDs without inventing occurrence identities. Existing route prefixes retain +// their IDs; Loom deterministically owns only the newly appended occurrences. +func normalizeStructuralAuthoringRoutes(documents []explorer.ExplorerBuilderDocumentV1, catalog explorer.Catalog) ([]explorer.ExplorerBuilderDocumentV1, error) { + edges := make(map[string]explorer.CatalogEdge, len(catalog.Edges)) + for _, edge := range catalog.Edges { + edges[edge.ID] = edge + } + normalized := append([]explorer.ExplorerBuilderDocumentV1(nil), documents...) + for documentIndex := range normalized { + document := &normalized[documentIndex] + path := fmt.Sprintf("$.documents[%d]", documentIndex) + current := document.BaseNodeID + targets := make([]string, 0, len(document.RouteEdgeIDs)) + for edgeIndex, edgeID := range document.RouteEdgeIDs { + edge, ok := edges[edgeID] + if !ok { + return nil, authoringSemantic("route", fmt.Sprintf("%s.routeEdgeIds[%d]", path, edgeIndex), "STALE_ROUTE_EDGE", "route edge is not present in the catalog snapshot", map[string]any{"edgeId": edgeID}) + } + if edge.FromNodeID != current { + return nil, authoringSemantic("route", fmt.Sprintf("%s.routeEdgeIds[%d]", path, edgeIndex), "INVALID_ROUTE_CONTINUITY", "ordered route edges do not form a continuous path", map[string]any{"edgeId": edgeID, "currentNodeId": current}) + } + current = edge.ToNodeID + targets = append(targets, current) + } + provided := append([]explorer.ExplorerRouteOccurrenceV1(nil), document.RouteOccurrences...) + providedOccurrenceIDs := make(map[string]bool, len(provided)) + for _, occurrence := range provided { + providedOccurrenceIDs[occurrence.ID] = true + } + if len(provided) > 0 && (provided[0].ID == "base" || provided[0].NodeID == document.BaseNodeID && len(provided) == len(document.RouteEdgeIDs)+1) { + provided = provided[1:] + } + // A Builder can retain route/candidate state from a longer route while + // the user shortens the route. Keep the surviving prefix and let the + // candidate normalizer remove selections tied only to occurrences that + // no longer exist. + if len(provided) > len(targets) { + provided = provided[:len(targets)] + } + occurrences := []explorer.ExplorerRouteOccurrenceV1{{ID: "base", Index: 0, NodeID: document.BaseNodeID}} + for index, nodeID := range targets { + edgeID := document.RouteEdgeIDs[index] + occurrence := explorer.ExplorerRouteOccurrenceV1{} + if index < len(provided) { + occurrence = provided[index] + if occurrence.NodeID != nodeID || occurrence.IncomingEdgeID != "" && occurrence.IncomingEdgeID != edgeID { + return nil, authoringSemantic("route", fmt.Sprintf("%s.routeOccurrences[%d]", path, index), "INVALID_ROUTE_OCCURRENCE_NODE", "route occurrence does not match its exact edge target", map[string]any{"expectedNodeId": nodeID, "receivedNodeId": occurrence.NodeID}) + } + } else { + occurrence.ID = explorer.OpaqueID("occ_", document.Output.ID+"\x00"+strconv.Itoa(index+1)+"\x00"+edgeID+"\x00"+nodeID) + } + occurrence.Index = index + 1 + occurrence.NodeID = nodeID + occurrence.IncomingEdgeID = edgeID + occurrences = append(occurrences, occurrence) + } + document.RouteOccurrences = occurrences + keptOccurrenceIDs := make(map[string]bool, len(occurrences)) + for _, occurrence := range occurrences { + keptOccurrenceIDs[occurrence.ID] = true + } + candidateOccurrences := make([]explorer.ExplorerCandidateOccurrenceV1, 0, len(document.CandidateOccurrences)) + removedCandidateIDs := map[string]bool{} + for _, reference := range document.CandidateOccurrences { + if reference.OccurrenceID != "base" && providedOccurrenceIDs[reference.OccurrenceID] && !keptOccurrenceIDs[reference.OccurrenceID] { + removedCandidateIDs[reference.CandidateID] = true + continue + } + candidateOccurrences = append(candidateOccurrences, reference) + } + document.CandidateOccurrences = candidateOccurrences + if len(removedCandidateIDs) > 0 { + candidateIDs := make([]string, 0, len(document.CandidateIDs)) + for _, candidateID := range document.CandidateIDs { + if removedCandidateIDs[candidateID] && !candidateOccurrenceHasID(candidateOccurrences, candidateID) { + continue + } + candidateIDs = append(candidateIDs, candidateID) + } + document.CandidateIDs = candidateIDs + } + } + return normalized, nil +} + +func candidateOccurrenceHasID(references []explorer.ExplorerCandidateOccurrenceV1, candidateID string) bool { + for _, reference := range references { + if reference.CandidateID == candidateID { + return true + } + } + return false +} + +// normalizeAuthoringDocuments resolves every legacy candidate selection +// against the exact route occurrences that structural normalization produced. +// It is deliberately separate from recipe lowering so GET, Builder POST, +// preview, publish, and the admin migration all share the same repair rules. +func normalizeAuthoringDocuments(documents []explorer.ExplorerBuilderDocumentV1, catalog explorer.Catalog) ([]explorer.ExplorerBuilderDocumentV1, error) { + normalized := append([]explorer.ExplorerBuilderDocumentV1(nil), documents...) + for index := range normalized { + document := normalized[index] + path := fmt.Sprintf("$.documents[%d]", index) + if _, err := resolveAuthoringRoute(document, catalog); err != nil { + return nil, err + } + binding := explorer.ExplorerResolvedBindingV1{OutputID: document.Output.ID, BaseNodeID: document.BaseNodeID, RouteOccurrences: make([]explorer.ExplorerResolvedOccurrenceV1, 0, len(document.RouteOccurrences))} + for _, occurrence := range document.RouteOccurrences { + binding.RouteOccurrences = append(binding.RouteOccurrences, explorer.ExplorerResolvedOccurrenceV1{OccurrenceID: occurrence.ID, Index: occurrence.Index, NodeID: occurrence.NodeID, IncomingEdgeID: occurrence.IncomingEdgeID}) + } + var err error + normalized[index], err = normalizeDocument(document, catalog, binding) + if err != nil { + return nil, withDocumentPath(err, path) + } + } + return normalized, nil +} + +// normalizeDocument upgrades the legacy candidateIds-only representation to +// the canonical candidateIds + candidateOccurrences representation. Existing +// valid pairs are retained verbatim. A missing pair is inferred only when the +// catalog identifies exactly one route occurrence; repeated resource nodes +// remain an explicit user choice. +func normalizeDocument(document explorer.ExplorerBuilderDocumentV1, catalog explorer.Catalog, resolvedBinding explorer.ExplorerResolvedBindingV1) (explorer.ExplorerBuilderDocumentV1, error) { + selectionByID := catalog.Selections + routeOccurrences := append([]explorer.ExplorerResolvedOccurrenceV1(nil), resolvedBinding.RouteOccurrences...) + occurrenceNodes := make(map[string]string, len(routeOccurrences)+1) + for _, occurrence := range resolvedBinding.RouteOccurrences { + if strings.TrimSpace(occurrence.OccurrenceID) == "" { + continue + } + occurrenceNodes[occurrence.OccurrenceID] = occurrence.NodeID + } + baseNodeID := resolvedBinding.BaseNodeID + if baseNodeID == "" { + baseNodeID = document.BaseNodeID + } + if _, ok := occurrenceNodes["base"]; !ok { + occurrenceNodes["base"] = baseNodeID + routeOccurrences = append([]explorer.ExplorerResolvedOccurrenceV1{{OccurrenceID: "base", Index: 0, NodeID: baseNodeID}}, routeOccurrences...) + } + + byCandidate := make(map[string][]string, len(document.CandidateOccurrences)) + seenPairs := make(map[string]bool, len(document.CandidateOccurrences)) + for index, reference := range document.CandidateOccurrences { + if _, ok := selectionByID[reference.CandidateID]; !ok { + return document, authoringSemantic("candidates", fmt.Sprintf("$.document.candidateOccurrences[%d].candidateId", index), "STALE_CANDIDATE_ID", "candidate is not present in the catalog snapshot", map[string]any{"candidateId": reference.CandidateID}) + } + occurrenceNode, ok := occurrenceNodes[reference.OccurrenceID] + if !ok { + return document, authoringSemantic("candidates", fmt.Sprintf("$.document.candidateOccurrences[%d].occurrenceId", index), "STALE_ROUTE_OCCURRENCE", "candidate occurrence references an unknown route occurrence", map[string]any{"occurrenceId": reference.OccurrenceID}) + } + key := reference.CandidateID + "\x00" + reference.OccurrenceID + if seenPairs[key] { + return document, authoringSemantic("candidates", "$.document.candidateOccurrences", "DUPLICATE_CANDIDATE_OCCURRENCE", "a candidate occurrence may be listed only once", nil) + } + seenPairs[key] = true + if selectionByID[reference.CandidateID].NodeID != occurrenceNode { + return document, authoringSemantic("candidates", "$.document.candidateOccurrences", "SELECTION_NODE_MISMATCH", "candidate is not valid at the referenced route occurrence", map[string]any{"candidateId": reference.CandidateID, "occurrenceId": reference.OccurrenceID, "selectionNodeId": selectionByID[reference.CandidateID].NodeID, "occurrenceNodeId": occurrenceNode}) + } + byCandidate[reference.CandidateID] = append(byCandidate[reference.CandidateID], reference.OccurrenceID) + } + + occurrences := append([]explorer.ExplorerCandidateOccurrenceV1(nil), document.CandidateOccurrences...) + for index, candidateID := range document.CandidateIDs { + selection, ok := selectionByID[candidateID] + if !ok { + return document, authoringSemantic("candidates", fmt.Sprintf("$.document.candidateIds[%d]", index), "STALE_CANDIDATE_ID", "candidate is not present in the catalog snapshot", map[string]any{"candidateId": candidateID}) + } + if len(byCandidate[candidateID]) > 0 { + continue + } + matches := make([]string, 0, len(occurrenceNodes)) + for _, occurrence := range routeOccurrences { + if occurrence.NodeID == selection.NodeID { + matches = append(matches, occurrence.OccurrenceID) + } + } + if len(matches) == 0 { + return document, authoringSemantic("candidates", fmt.Sprintf("$.document.candidateIds[%d]", index), "SELECTION_NODE_MISMATCH", "candidate does not belong to any route occurrence in this document", map[string]any{"candidateId": candidateID, "selectionNodeId": selection.NodeID, "routeOccurrences": matches}) + } + if len(matches) > 1 { + return document, authoringSemantic("candidates", "$.document.candidateOccurrences", "CANDIDATE_OCCURRENCE_REQUIRED", "every selected candidate must identify its exact route occurrence", map[string]any{"candidateId": candidateID, "validOccurrences": matches}) + } + occurrences = append(occurrences, explorer.ExplorerCandidateOccurrenceV1{CandidateID: candidateID, OccurrenceID: matches[0]}) + byCandidate[candidateID] = append(byCandidate[candidateID], matches[0]) + } + + represented := make(map[string]bool, len(occurrences)) + for _, reference := range occurrences { + represented[reference.CandidateID] = true + } + candidateIDs := make([]string, 0, len(represented)) + for _, candidateID := range document.CandidateIDs { + if represented[candidateID] { + candidateIDs = append(candidateIDs, candidateID) + } + } + document.CandidateIDs = candidateIDs + document.CandidateOccurrences = occurrences + return document, nil +} + +func withDocumentPath(err error, path string) error { + var authoringErr *explorer.AuthoringError + if !errors.As(err, &authoringErr) || authoringErr == nil { + return err + } + if authoringErr.Diagnostic.JSONPath == "" || strings.HasPrefix(authoringErr.Diagnostic.JSONPath, "$.documents[") { + return err + } + authoringErr.Diagnostic.JSONPath = path + authoringErr.Diagnostic.JSONPath[len("$.document"):] + return err +} + +// compileExplorerAuthoringV1 remains as the internal compiler capability seam; +// all behavior is owned by ResolveAuthoringBundle. +func compileExplorerAuthoringV1(ctx context.Context, recipeEngine *engine.Engine, catalogReader explorerV2CatalogReader, request ExplorerAuthoringV1CompileRequest) (ExplorerAuthoringV1CompileResult, error) { + return ResolveAuthoringBundle(ctx, recipeEngine, catalogReader, request) +} + +type authoringRouteStep struct { + Occurrence explorer.ExplorerRouteOccurrenceV1 + Edge explorer.CatalogEdge + NodeID string +} + +func resolveAuthoringRoute(document explorer.ExplorerBuilderDocumentV1, catalog explorer.Catalog) ([]authoringRouteStep, error) { + nodes := map[string]explorer.CatalogNode{} + for _, node := range catalog.Nodes { + nodes[node.ID] = node + } + if _, ok := nodes[document.BaseNodeID]; !ok { + return nil, authoringSemantic("route", "$.document.baseNodeId", "STALE_BASE_NODE", "base node is not present in the catalog snapshot", map[string]any{"nodeId": document.BaseNodeID}) + } + if _, ok := nodes[document.RowNodeID]; !ok { + return nil, authoringSemantic("route", "$.document.rowNodeId", "STALE_ROW_NODE", "row node is not present in the catalog snapshot", map[string]any{"nodeId": document.RowNodeID}) + } + edges := map[string]explorer.CatalogEdge{} + for _, edge := range catalog.Edges { + edges[edge.ID] = edge + } + if len(document.RouteEdgeIDs) == 0 { + if document.BaseNodeID != document.RowNodeID { + return nil, authoringSemantic("route", "$.document.rowNodeId", "INVALID_ZERO_HOP_ROUTE", "a zero-hop route must end at its base node", nil) + } + if len(document.RouteOccurrences) > 1 { + return nil, authoringSemantic("route", "$.document.routeOccurrences", "INVALID_ZERO_HOP_ROUTE", "a zero-hop route has no child occurrences", nil) + } + if len(document.RouteOccurrences) == 1 && (document.RouteOccurrences[0].Index != 0 || document.RouteOccurrences[0].NodeID != document.BaseNodeID) { + return nil, authoringSemantic("route", "$.document.routeOccurrences[0]", "INVALID_ZERO_HOP_ROUTE", "the optional zero-hop occurrence must reference the base node at index zero", nil) + } + return nil, nil + } + for index, occurrence := range document.RouteOccurrences { + if _, ok := nodes[occurrence.NodeID]; !ok { + return nil, authoringSemantic("route", fmt.Sprintf("$.document.routeOccurrences[%d].nodeId", index), "STALE_ROUTE_NODE", "route occurrence node is not present in the catalog snapshot", map[string]any{"nodeId": occurrence.NodeID}) + } + } + if len(document.RouteOccurrences) != len(document.RouteEdgeIDs) && len(document.RouteOccurrences) != len(document.RouteEdgeIDs)+1 { + return nil, authoringSemantic("route", "$.document.routeOccurrences", "ROUTE_OCCURRENCES_REQUIRED", "route occurrence references must contain one target per edge, or include the base occurrence", map[string]any{"edges": len(document.RouteEdgeIDs), "occurrences": len(document.RouteOccurrences)}) + } + if len(document.RouteOccurrences) == len(document.RouteEdgeIDs)+1 && document.RouteOccurrences[0].NodeID != document.BaseNodeID { + return nil, authoringSemantic("route", "$.document.routeOccurrences[0].nodeId", "INVALID_ROUTE_ORIGIN", "the first route occurrence must reference baseNodeId", nil) + } + current := document.BaseNodeID + steps := make([]authoringRouteStep, 0, len(document.RouteEdgeIDs)) + for index, edgeID := range document.RouteEdgeIDs { + edge, ok := edges[edgeID] + if !ok { + return nil, authoringSemantic("route", fmt.Sprintf("$.document.routeEdgeIds[%d]", index), "STALE_ROUTE_EDGE", "route edge is not present in the catalog snapshot", map[string]any{"edgeId": edgeID}) + } + if edge.FromNodeID != current { + return nil, authoringSemantic("route", fmt.Sprintf("$.document.routeEdgeIds[%d]", index), "INVALID_ROUTE_CONTINUITY", "ordered route edges do not form a continuous path", map[string]any{"edgeId": edgeID, "currentNodeId": current}) + } + next := edge.ToNodeID + occurrenceIndex := index + if len(document.RouteOccurrences) == len(document.RouteEdgeIDs)+1 { + occurrenceIndex++ + } + occurrence := document.RouteOccurrences[occurrenceIndex] + if occurrence.Index != occurrenceIndex { + return nil, authoringSemantic("route", fmt.Sprintf("$.document.routeOccurrences[%d].index", occurrenceIndex), "INVALID_ROUTE_OCCURRENCE_ORDER", "route occurrence index does not match ordered route edges", nil) + } + if occurrence.NodeID != next { + return nil, authoringSemantic("route", fmt.Sprintf("$.document.routeOccurrences[%d].nodeId", occurrenceIndex), "INVALID_ROUTE_OCCURRENCE_NODE", "route occurrence does not name the edge target", map[string]any{"expectedNodeId": next, "receivedNodeId": occurrence.NodeID}) + } + if occurrence.IncomingEdgeID != "" && occurrence.IncomingEdgeID != edgeID { + return nil, authoringSemantic("route", fmt.Sprintf("$.document.routeOccurrences[%d].incomingEdgeId", occurrenceIndex), "INVALID_ROUTE_OCCURRENCE_EDGE", "route occurrence does not reference its incoming edge", nil) + } + steps = append(steps, authoringRouteStep{Occurrence: occurrence, Edge: edge, NodeID: next}) + current = next + } + if current != document.RowNodeID { + return nil, authoringSemantic("route", "$.document.rowNodeId", "INVALID_ROUTE_TERMINAL_NODE", "route does not terminate at rowNodeId", map[string]any{"terminalNodeId": current, "rowNodeId": document.RowNodeID}) + } + return steps, nil +} + +type authoringAssignment struct { + CandidateID, OccurrenceID, ProjectionMode string + Selection explorer.CatalogSelection +} + +func resolveAuthoringCandidates(document explorer.ExplorerBuilderDocumentV1, catalog explorer.Catalog, route []authoringRouteStep) ([]authoringAssignment, error) { + selections := catalog.Selections + pathNodes := map[string][]string{"base": {document.BaseNodeID}} + for _, step := range route { + pathNodes[step.Occurrence.ID] = append(pathNodes[step.Occurrence.ID], step.NodeID) + } + byCandidateOccurrence := map[string][]string{} + projectionByPair := map[string]string{} + seenAssignment := map[string]bool{} + for _, reference := range document.CandidateOccurrences { + key := reference.CandidateID + "\x00" + reference.OccurrenceID + if seenAssignment[key] { + return nil, authoringSemantic("candidates", "$.document.candidateOccurrences", "DUPLICATE_CANDIDATE_OCCURRENCE", "a candidate occurrence may be listed only once", nil) + } + seenAssignment[key] = true + byCandidateOccurrence[reference.CandidateID] = append(byCandidateOccurrence[reference.CandidateID], reference.OccurrenceID) + projectionByPair[key] = strings.TrimSpace(reference.ProjectionMode) + } + assignments := make([]authoringAssignment, 0, len(document.CandidateIDs)) + for i, candidateID := range document.CandidateIDs { + selection, ok := selections[candidateID] + if !ok { + return nil, authoringSemantic("candidates", fmt.Sprintf("$.document.candidateIds[%d]", i), "STALE_CANDIDATE_ID", "candidate is not present in the catalog snapshot", map[string]any{"candidateId": candidateID}) + } + occurrenceIDs := byCandidateOccurrence[candidateID] + matches := make([]string, 0, 2) + for id, nodeIDs := range pathNodes { + for _, nodeID := range nodeIDs { + if nodeID == selection.NodeID { + matches = append(matches, id) + break + } + } + } + if len(matches) == 0 { + return nil, authoringSemantic("candidates", fmt.Sprintf("$.document.candidateIds[%d]", i), "SELECTION_NODE_MISMATCH", "candidate does not belong to the base node or any route occurrence in this document", map[string]any{"candidateId": candidateID, "selectionNodeId": selection.NodeID, "routeNodeIds": pathNodes}) + } + if len(occurrenceIDs) == 0 { + return nil, authoringSemantic("candidates", fmt.Sprintf("$.document.candidateOccurrences"), "CANDIDATE_OCCURRENCE_REQUIRED", "every selected candidate must identify its exact route occurrence", map[string]any{"candidateId": candidateID, "validOccurrences": matches}) + } + for _, occurrenceID := range occurrenceIDs { + if occurrenceID != "base" && !containsRouteOccurrence(route, occurrenceID) { + return nil, authoringSemantic("candidates", "$.document.candidateOccurrences", "STALE_ROUTE_OCCURRENCE", "candidate references a stale route occurrence", map[string]any{"occurrenceId": occurrenceID}) + } + var occurrenceNode string + if occurrenceID == "base" { + occurrenceNode = document.BaseNodeID + } else { + for _, step := range route { + if step.Occurrence.ID == occurrenceID { + occurrenceNode = step.NodeID + break + } + } + } + if occurrenceNode != selection.NodeID { + return nil, authoringSemantic("candidates", "$.document.candidateOccurrences", "SELECTION_NODE_MISMATCH", "candidate is not valid at the referenced route occurrence", map[string]any{"candidateId": candidateID, "occurrenceId": occurrenceID}) + } + projectionMode := projectionByPair[candidateID+"\x00"+occurrenceID] + if projectionMode == "" { + projectionMode = selection.DefaultProjectionMode + } + if projectionMode != "" && !containsString(selection.ProjectionModes, projectionMode) { + return nil, authoringSemantic("candidates", "$.document.candidateOccurrences", "UNSUPPORTED_PROJECTION_MODE", "candidate projection mode is not advertised by the catalog snapshot", map[string]any{"candidateId": candidateID, "projectionMode": projectionMode, "supported": selection.ProjectionModes}) + } + assignments = append(assignments, authoringAssignment{CandidateID: candidateID, OccurrenceID: occurrenceID, ProjectionMode: projectionMode, Selection: selection}) + } + } + return assignments, nil +} + +func containsRouteOccurrence(route []authoringRouteStep, id string) bool { + for _, step := range route { + if step.Occurrence.ID == id { + return true + } + } + return false +} + +func authoringEmissions(document explorer.ExplorerBuilderDocumentV1, _ explorer.Catalog, assignments []authoringAssignment) ([]explorer.EmittedColumn, []explorer.IdentityMapping) { + byCandidateOccurrence := map[string][]string{} + emitted := make([]explorer.EmittedColumn, 0, len(assignments)) + for _, assignment := range assignments { + emissionID := explorer.OpaqueID("em_", document.Output.ID+"\x00"+assignment.OccurrenceID+"\x00"+assignment.CandidateID) + // PublicColumn must be the logical field name emitted by the native + // recipe. Publication may add the root-resource prefix, but the runtime + // projection can resolve that qualification only when the unqualified + // suffix is identical. Deriving this name from EmissionID instead gives + // it a different hash and leaves previews/runtime tables with column + // metadata that cannot address any returned row value. + publicColumn := generatedFieldName(assignment.CandidateID, assignment.OccurrenceID) + column := explorer.EmittedColumn{EmissionID: emissionID, OutputID: document.Output.ID, NodeID: assignment.Selection.NodeID, SelectionID: assignment.CandidateID, CandidateID: assignment.CandidateID, OccurrenceID: assignment.OccurrenceID, PublicColumn: publicColumn, Filterable: assignment.Selection.Filterable, Chartable: assignment.Selection.Chartable} + emitted = append(emitted, column) + key := assignment.CandidateID + "\x00" + assignment.OccurrenceID + byCandidateOccurrence[key] = append(byCandidateOccurrence[key], emissionID) + } + mappings := make([]explorer.IdentityMapping, 0, len(byCandidateOccurrence)) + for _, assignment := range assignments { + key := assignment.CandidateID + "\x00" + assignment.OccurrenceID + if ids := byCandidateOccurrence[key]; len(ids) > 0 { + mappings = append(mappings, explorer.IdentityMapping{CandidateID: assignment.CandidateID, OccurrenceID: assignment.OccurrenceID, EmissionIDs: append([]string(nil), ids...)}) + delete(byCandidateOccurrence, key) + } + } + return emitted, mappings +} + +func resolvedAuthoringBinding(document explorer.ExplorerBuilderDocumentV1, catalog explorer.Catalog, route []authoringRouteStep, assignments []authoringAssignment, emitted []explorer.EmittedColumn) explorer.ExplorerResolvedBindingV1 { + base, _ := catalogNode(catalog, document.BaseNodeID) + row, _ := catalogNode(catalog, document.RowNodeID) + rowGrain, _ := spec.InferRowGrain(base.ResourceType) + kind := "ROUTE" + if len(route) == 0 { + kind = "ZERO_HOP" + } + result := explorer.ExplorerResolvedBindingV1{ + OutputID: document.Output.ID, OutputTitle: document.Output.Title, + BaseNodeID: document.BaseNodeID, BaseResourceType: base.ResourceType, + RowNodeID: document.RowNodeID, RowResourceType: row.ResourceType, + RowGrain: string(rowGrain), RouteKind: kind, + RouteOccurrences: []explorer.ExplorerResolvedOccurrenceV1{{OccurrenceID: "base", Index: 0, NodeID: document.BaseNodeID, ResourceType: base.ResourceType}}, + CandidateEmissions: []explorer.ExplorerCandidateEmissionV1{}, + } + for i, step := range route { + result.RouteOccurrences = append(result.RouteOccurrences, explorer.ExplorerResolvedOccurrenceV1{OccurrenceID: step.Occurrence.ID, Index: i + 1, NodeID: step.NodeID, ResourceType: nodeResourceType(catalog, step.NodeID), IncomingEdgeID: step.Edge.ID}) + } + emissionByKey := map[string]explorer.EmittedColumn{} + for _, column := range emitted { + emissionByKey[column.CandidateID+"\x00"+column.OccurrenceID] = column + } + for _, assignment := range assignments { + column := emissionByKey[assignment.CandidateID+"\x00"+assignment.OccurrenceID] + label := assignment.Selection.FieldRef + if presentation, ok := document.Presentation[column.EmissionID]; ok && strings.TrimSpace(presentation.Label) != "" { + label = presentation.Label + } + result.CandidateEmissions = append(result.CandidateEmissions, explorer.ExplorerCandidateEmissionV1{CandidateID: assignment.CandidateID, OccurrenceID: assignment.OccurrenceID, EmissionID: column.EmissionID, PublicColumn: column.PublicColumn, Label: label, LogicalType: firstNonEmpty(column.LogicalType, assignment.Selection.LogicalType), Filterable: column.Filterable, Chartable: column.Chartable}) + } + return result +} + +func validateAuthoringPresentation(document explorer.ExplorerBuilderDocumentV1, emitted []explorer.EmittedColumn) error { + known := map[string]explorer.EmittedColumn{} + for _, column := range emitted { + known[column.EmissionID] = column + } + for emissionID := range document.Presentation { + column, ok := known[emissionID] + if !ok { + return authoringSemantic("presentation", "$.document.presentation."+emissionID, "STALE_EMISSION", "presentation references an emission that is not in this compilation", map[string]any{"emissionId": emissionID}) + } + binding := document.Presentation[emissionID] + if binding.Filter != nil && !column.Filterable { + return authoringSemantic("presentation", "$.document.presentation."+emissionID+".filter", "UNSUPPORTED_FILTER_PRESENTATION", "the selected emission is not filterable", map[string]any{"emissionId": emissionID}) + } + if binding.Chart != nil && !column.Chartable { + return authoringSemantic("presentation", "$.document.presentation."+emissionID+".chart", "UNSUPPORTED_CHART_PRESENTATION", "the selected emission is not chartable", map[string]any{"emissionId": emissionID}) + } + } + return nil +} + +func lowerAuthoringDocument(project, explorerID string, document explorer.ExplorerBuilderDocumentV1, catalog explorer.Catalog, route []authoringRouteStep, assignments []authoringAssignment) (recipe.Bundle, error) { + base, ok := catalogNode(catalog, document.BaseNodeID) + if !ok { + return recipe.Bundle{}, authoringSemantic("route", "$.document.baseNodeId", "STALE_BASE_NODE", "base node is not present in the catalog snapshot", nil) + } + outputID := document.Output.ID + if !authoringIDPattern.MatchString(outputID) { + return recipe.Bundle{}, authoringSemantic("intent", "$.document.output.id", "INVALID_OUTPUT_ID", "output.id must be a stable lower-case identifier", nil) + } + rootResourceType, ok := fhirschema.CanonicalResourceType(base.ResourceType) + if !ok { + return recipe.Bundle{}, authoringSemantic("lower", "$.document.baseNodeId", "UNSUPPORTED_ROW_GRAIN", "the selected base resource has no supported row grain", map[string]any{"resourceType": base.ResourceType, "nodeId": base.ID}) + } + rowGrain, ok := spec.InferRowGrain(rootResourceType) + if !ok { + return recipe.Bundle{}, authoringSemantic("lower", "$.document.baseNodeId", "UNSUPPORTED_ROW_GRAIN", "the selected base resource has no supported row grain", map[string]any{"resourceType": base.ResourceType, "nodeId": base.ID}) + } + native := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "explorer_" + safeAuthoringName(project) + "_" + safeAuthoringName(explorerID), TranslationVersion: "authoring-v1", Outputs: []recipe.Output{{Name: outputID, RootResourceType: rootResourceType, RowGrain: string(rowGrain)}}} + byOccurrence := map[string][]authoringAssignment{} + for _, assignment := range assignments { + byOccurrence[assignment.OccurrenceID] = append(byOccurrence[assignment.OccurrenceID], assignment) + } + appendFields := func(fields *[]recipe.Field, occurrenceID, alias string) { + for _, assignment := range byOccurrence[occurrenceID] { + fieldName := generatedFieldName(assignment.CandidateID, occurrenceID) + selectPath := strings.TrimSpace(assignment.Selection.Select) + selectPath = strings.TrimPrefix(selectPath, "root.") + *fields = append(*fields, recipe.Field{Name: fieldName, FieldRef: assignment.Selection.FieldRef, Expr: recipe.Expression{Select: alias + "." + selectPath}, ValueMode: authoringValueMode(assignment.ProjectionMode)}) + } + } + appendFields(&native.Outputs[0].Fields, "base", "root") + var appendTraversals func(*[]recipe.Traversal, int, string) + appendTraversals = func(target *[]recipe.Traversal, index int, parentAlias string) { + if index >= len(route) { + return + } + step := route[index] + alias := "route_" + strconv.Itoa(index) + toResourceType, _ := fhirschema.CanonicalResourceType(nodeResourceType(catalog, step.NodeID)) + traversal := recipe.Traversal{Name: step.Edge.Label, Alias: alias, ToResourceType: toResourceType, MatchMode: recipe.MatchOptional} + appendFields(&traversal.Fields, step.Occurrence.ID, alias) + appendTraversals(&traversal.Traversals, index+1, alias) + *target = append(*target, traversal) + } + appendTraversals(&native.Outputs[0].Traversals, 0, "root") + return native, nil +} + +func authoringValueMode(projectionMode string) recipe.ValueMode { + switch strings.ToUpper(strings.TrimSpace(projectionMode)) { + case "FIRST": + return recipe.ValueModeFirst + case "ARRAY": + return recipe.ValueModeAll + case "DISTINCT_ARRAY": + return recipe.ValueModeDistinct + default: + return recipe.ValueModeAuto + } +} + +func catalogNode(catalog explorer.Catalog, id string) (explorer.CatalogNode, bool) { + for _, node := range catalog.Nodes { + if node.ID == id { + return node, true + } + } + return explorer.CatalogNode{}, false +} +func nodeResourceType(catalog explorer.Catalog, id string) string { + node, _ := catalogNode(catalog, id) + return node.ResourceType +} +func safeAuthoringName(value string) string { + value = strings.ToLower(value) + var b strings.Builder + for _, r := range value { + if r >= 'a' && r <= 'z' || r >= '0' && r <= '9' || r == '_' { + b.WriteRune(r) + } else { + b.WriteByte('_') + } + } + value = strings.Trim(b.String(), "_") + if value == "" { + return "x" + } + return value +} +func generatedFieldName(candidateID, occurrenceID string) string { + sum := sha256.Sum256([]byte(candidateID + "\x00" + occurrenceID)) + return "c_" + hex.EncodeToString(sum[:]) +} +func outputFingerprint(bundle recipe.Bundle, project, generation string) string { + raw, _ := json.Marshal(struct { + Bundle recipe.Bundle + Project, Generation string + }{bundle, project, generation}) + sum := sha256.Sum256(raw) + return hex.EncodeToString(sum[:]) +} + +func authoringCompiledConfig(bundle explorer.ExplorerAuthoringBundleV1, native recipe.Bundle, emitted []explorer.EmittedColumn) ([]byte, error) { + documents := bundle.AuthoringDocuments() + documentsByOutput := make(map[string]explorer.ExplorerBuilderDocumentV1, len(documents)) + emittedByOutput := make(map[string][]explorer.EmittedColumn, len(documents)) + for _, document := range documents { + documentsByOutput[document.Output.ID] = document + } + for _, column := range emitted { + emittedByOutput[column.OutputID] = append(emittedByOutput[column.OutputID], column) + } + tabs := bundle.AuthoringTabs() + sort.SliceStable(tabs, func(i, j int) bool { return tabs[i].Order < tabs[j].Order }) + views := make([]explorer.ConfigView, 0, len(tabs)) + for _, tab := range tabs { + if tab.Visible != nil && !*tab.Visible { + continue + } + document, ok := documentsByOutput[tab.OutputID] + if !ok { + return nil, authoringSemantic("presentation", "$.tabs", "TAB_OUTPUT_MISSING", "tab references an output that is not in the authoring bundle", map[string]any{"outputId": tab.OutputID}) + } + columns := make([]explorer.ConfigColumn, 0, len(emittedByOutput[tab.OutputID])) + filters := make([]explorer.ConfigFilter, 0) + charts := make([]explorer.ConfigChart, 0) + orderByColumn := map[string]int{} + for _, column := range emittedByOutput[tab.OutputID] { + binding := document.Presentation[column.EmissionID] + visible := true + if binding.Visible != nil { + visible = *binding.Visible + } + if binding.Order != nil { + orderByColumn[column.PublicColumn] = *binding.Order + } + label := firstNonEmpty(binding.Label, column.PublicColumn) + columns = append(columns, explorer.ConfigColumn{Column: column.PublicColumn, Label: label, Visible: visible}) + if binding.Filter != nil { + filters = append(filters, explorer.ConfigFilter{Column: column.PublicColumn, Label: binding.Filter.Label}) + } + if binding.Chart != nil { + charts = append(charts, explorer.ConfigChart{Column: column.PublicColumn, Type: binding.Chart.Type, Title: binding.Chart.Title}) + } + } + sort.SliceStable(columns, func(i, j int) bool { + left, leftOK := orderByColumn[columns[i].Column] + right, rightOK := orderByColumn[columns[j].Column] + if leftOK && rightOK && left != right { + return left < right + } + if leftOK != rightOK { + return leftOK + } + return columns[i].Column < columns[j].Column + }) + sort.Slice(filters, func(i, j int) bool { return filters[i].Column < filters[j].Column }) + sort.Slice(charts, func(i, j int) bool { return charts[i].Column < charts[j].Column }) + views = append(views, explorer.ConfigView{ID: tab.ID, Title: tab.Title, Output: tab.OutputID, Table: explorer.ConfigTable{Columns: columns}, Filters: filters, Charts: charts}) + } + config := explorer.ConfigV2{APIVersion: explorer.ConfigV2APIVersion, Kind: "ExplorerConfig", Project: bundle.Project, Explorer: explorer.ConfigExplorer{ID: bundle.ExplorerID, Title: firstNonEmpty(bundle.Title, documents[0].Output.Title, documents[0].Output.ID), Management: explorer.ConfigManagementForID(bundle.ExplorerID)}, Recipe: mustJSON(native), Views: views} + return json.Marshal(config) +} +func mustJSON(value any) json.RawMessage { raw, _ := json.Marshal(value); return raw } +func firstNonEmpty(values ...string) string { + for _, value := range values { + if strings.TrimSpace(value) != "" { + return value + } + } + return "Explorer" +} + +func authoringSemantic(stage, path, code, message string, details map[string]any) error { + return &explorer.AuthoringError{Status: 422, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: code, JSONPath: path, Message: message, Details: details}} +} +func explorerConflict(stage, code, message string, details map[string]any) error { + return &explorer.AuthoringError{Status: 409, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: code, Message: message, Details: details}} +} +func explorerUnavailable(stage, code, message string) error { + return &explorer.AuthoringError{Status: 503, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: code, Message: message}} +} +func withRequestAuthoringError(err error, requestID string) error { + var authoringErr *explorer.AuthoringError + if errors.As(err, &authoringErr) { + authoringErr.Diagnostic.RequestID = requestID + } + return err +} +func authoringSemanticFromRecipe(err error) error { + var validation *recipe.ValidationError + if errors.As(err, &validation) { + return authoringSemantic("recipe", validation.Path, "INVALID_COMPILED_RECIPE", validation.Message, map[string]any{"recipeCode": validation.Code}) + } + return authoringSemanticFromCompile(err) +} +func authoringSemanticFromCompile(err error) error { + message := err.Error() + code := "INVALID_AUTHORING_INTENT" + if strings.Contains(strings.ToLower(message), "traversal") { + code = "UNSUPPORTED_NESTED_TRAVERSAL" + } + return authoringSemantic("compile", "$", code, message, nil) +} diff --git a/internal/server/explorer_authoring_v1_routes.go b/internal/server/explorer_authoring_v1_routes.go new file mode 100644 index 00000000..0b29c058 --- /dev/null +++ b/internal/server/explorer_authoring_v1_routes.go @@ -0,0 +1,503 @@ +package server + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "log/slog" + "sort" + "strings" + "time" + + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/projectid" + "github.com/gofiber/fiber/v3" +) + +// RegisterExplorerAuthoringV1Routes exposes the publish-only Builder contract. +// GET /builder hydrates active state; POST /builder resolves local intent using +// the same response model without persisting a browser draft. +func RegisterExplorerAuthoringV1Routes(app *fiber.App, authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, explorers *explorer.Service, capabilities ExplorerV2LifecycleConfig) { + if app == nil || authorizer == nil || authorizeRead == nil || explorers == nil { + return + } + prefix := "/api/v1/projects/:project/explorers/:explorerId/authoring/v1" + + app.Get(prefix+"/capabilities", func(c fiber.Ctx) error { + if err := authoringRead(c, authorizeRead); err != nil { + return err + } + return c.JSON(fiber.Map{ + "apiVersion": explorer.ExplorerAuthoringV1APIVersion, + "kind": "ExplorerAuthoringCapabilities", + "operations": []string{"builder", "preview", "publish", "active-export", "table-identity", "create"}, + "publication": "last-writer-wins", + "features": fiber.Map{ + "emissionFilters": true, "emissionCharts": true, + "sharedFilters": false, "fixedFilters": false, + "fileActions": false, "deleteExplorer": false, + }, + }) + }) + + app.Post(prefix+"/table-identity", func(c fiber.Ctx) error { + if err := authoringWrite(c, authorizer); err != nil { + return err + } + var request struct { + Title string `json:"title"` + RequestID string `json:"requestId"` + OccupiedOutputIDs []string `json:"occupiedOutputIds,omitempty"` + OccupiedTabIDs []string `json:"occupiedTabIds,omitempty"` + } + if err := decodeAuthoringStrict(c.Body(), &request); err != nil || strings.TrimSpace(request.Title) == "" || strings.TrimSpace(request.RequestID) == "" { + if err == nil { + err = fmt.Errorf("title and requestId are required") + } + return authoringHTTPError(c, &explorer.AuthoringError{Status: 400, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "decode", Code: "MALFORMED_AUTHORING_REQUEST", JSONPath: "$", Message: err.Error()}}) + } + seed := explorerProjectParam(c) + "\x00" + strings.TrimSpace(c.Params("explorerId")) + "\x00" + strings.TrimSpace(request.RequestID) + outputID := explorer.OpaqueID("out_", seed) + tabID := explorer.OpaqueID("tab_", seed) + return c.JSON(fiber.Map{ + "apiVersion": explorer.ExplorerAuthoringV1APIVersion, + "kind": "ExplorerTableIdentity", + "output": explorer.ExplorerOutputIdentityV1{ID: outputID, Title: strings.TrimSpace(request.Title)}, + "tab": fiber.Map{"id": tabID, "title": strings.TrimSpace(request.Title), "outputId": outputID}, + }) + }) + + app.Get(prefix+"/builder", func(c fiber.Ctx) error { + if err := authoringRead(c, authorizeRead); err != nil { + return err + } + state, err := loadExplorerBuilderState(c.Context(), explorers, capabilities, explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")), requestIDFromFiber(c)) + if err != nil { + return authoringHTTPError(c, err) + } + emissionCount := 0 + for _, binding := range state.Bindings { + emissionCount += len(binding.CandidateEmissions) + } + slog.Info("Explorer Builder state resolved", + "request_id", requestIDFromFiber(c), + "project", state.Project, + "explorer_id", state.ExplorerID, + "catalog_nodes", len(state.Catalog.Nodes), + "catalog_candidates", len(state.Catalog.Candidates), + "documents", len(state.Bundle.AuthoringDocuments()), + "bindings", len(state.Bindings), + "candidate_emissions", emissionCount, + ) + return c.JSON(state) + }) + + app.Post(prefix+"/builder", func(c fiber.Ctx) error { + if err := authoringWrite(c, authorizer); err != nil { + return err + } + var request struct { + Bundle explorer.ExplorerAuthoringBundleV1 `json:"bundle"` + SnapshotToken string `json:"snapshotToken"` + } + if err := decodeAuthoringStrict(c.Body(), &request); err != nil { + return authoringHTTPError(c, malformedRouteError("builder", err)) + } + logAuthoringCompatibilityRequest(c, "builder", request.Bundle) + if err := validateAuthoringRouteIdentity(c, request.Bundle); err != nil { + return authoringHTTPError(c, err) + } + if capabilities.AuthoringCompile == nil || capabilities.Catalog == nil { + return authoringHTTPError(c, explorerUnavailable("builder", "AUTHORING_COMPILER_UNAVAILABLE", "Explorer authoring resolver is not configured")) + } + project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) + if len(request.Bundle.AuthoringDocuments()) == 0 { + owner, err := explorers.Get(c.Context(), project, id) + if err != nil { + return authoringHTTPError(c, err) + } + snapshot, err := capabilities.Catalog(c.Context(), project, id, "") + if err != nil || !snapshot.Complete || snapshot.Truncated { + return authoringHTTPError(c, explorerUnavailable("catalog", "CATALOG_UNAVAILABLE", "Explorer authoring catalog is unavailable or incomplete")) + } + if err := snapshot.ValidateToken(request.SnapshotToken); err != nil { + return authoringHTTPError(c, explorerConflict("catalog", "STALE_CATALOG_SNAPSHOT", err.Error(), map[string]any{"snapshotToken": request.SnapshotToken})) + } + active, activeErr := explorers.ActiveRevision(c.Context(), project, id) + if errors.Is(activeErr, explorer.ErrNotFound) { + active = nil + } else if activeErr != nil { + return authoringHTTPError(c, activeErr) + } + state := newBuilderState(owner, request.Bundle, snapshot, nil, active) + return c.JSON(state) + } + resolved, err := capabilities.AuthoringCompile(c.Context(), ExplorerAuthoringV1CompileRequest{Bundle: request.Bundle, SnapshotToken: request.SnapshotToken, RequestID: requestIDFromFiber(c)}) + if err != nil { + return authoringHTTPError(c, err) + } + active, activeErr := explorers.ActiveRevision(c.Context(), project, id) + if errors.Is(activeErr, explorer.ErrNotFound) { + active = nil + } else if activeErr != nil { + return authoringHTTPError(c, activeErr) + } + state, err := builderStateFromResolved(c.Context(), explorers, capabilities, project, id, resolved, active) + if err != nil { + return authoringHTTPError(c, err) + } + return c.JSON(state) + }) + + app.Post(prefix+"/preview", func(c fiber.Ctx) error { + if err := authoringRead(c, authorizeRead); err != nil { + return err + } + var request struct { + Bundle explorer.ExplorerAuthoringBundleV1 `json:"bundle"` + SnapshotToken string `json:"snapshotToken"` + OutputID string `json:"outputId"` + Limit int `json:"limit"` + } + if err := decodeAuthoringStrict(c.Body(), &request); err != nil { + return authoringHTTPError(c, malformedRouteError("preview", err)) + } + logAuthoringCompatibilityRequest(c, "preview", request.Bundle) + if request.Limit == 0 { + request.Limit = 25 + } + if request.Limit < 1 || request.Limit > 1000 { + return authoringHTTPError(c, authoringSemanticRoute("preview", "$.limit", "INVALID_PREVIEW_LIMIT", "limit must be between 1 and 1000", nil)) + } + if err := validateAuthoringRouteIdentity(c, request.Bundle); err != nil { + return authoringHTTPError(c, err) + } + if capabilities.AuthoringCompile == nil || capabilities.Preview == nil { + return authoringHTTPError(c, explorerUnavailable("preview", "PREVIEW_UNAVAILABLE", "Explorer preview is not configured")) + } + resolved, err := capabilities.AuthoringCompile(c.Context(), ExplorerAuthoringV1CompileRequest{Bundle: request.Bundle, SnapshotToken: request.SnapshotToken, RequestID: requestIDFromFiber(c)}) + if err != nil { + return authoringHTTPError(c, err) + } + if !receiptHasOutput(resolved.Receipt.Bundle, request.OutputID) { + return authoringHTTPError(c, authoringSemanticRoute("preview", "$.outputId", "UNKNOWN_AUTHORING_OUTPUT", "outputId is not in the authoring bundle", nil)) + } + rows, err := capabilities.Preview(c.Context(), resolved.Receipt.Bundle, recipe.RuntimeBindings{Project: projectid.Legacy(explorerProjectParam(c)), DatasetGeneration: resolved.SourceGeneration, PreviewLimit: request.Limit, OutputNames: []string{request.OutputID}}) + if err != nil { + return authoringHTTPError(c, &explorer.AuthoringError{Status: 422, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "preview", Code: "AUTHORING_PREVIEW_FAILED", Message: "authoring bundle could not be previewed"}, Cause: err}) + } + return c.JSON(fiber.Map{"outputId": request.OutputID, "columns": previewColumnsForOutput(resolved.ResolvedBindings, request.OutputID), "rows": rows[request.OutputID], "rowCount": len(rows[request.OutputID]), "snapshotToken": request.SnapshotToken, "generation": resolved.SourceGeneration, "diagnostics": resolved.Diagnostics}) + }) + + app.Post(prefix+"/publish", func(c fiber.Ctx) error { + if err := authoringWrite(c, authorizer); err != nil { + return err + } + var request struct { + Bundle explorer.ExplorerAuthoringBundleV1 `json:"bundle"` + SnapshotToken string `json:"snapshotToken"` + } + if err := decodeAuthoringStrict(c.Body(), &request); err != nil { + return authoringHTTPError(c, malformedRouteError("publish", err)) + } + logAuthoringCompatibilityRequest(c, "publish", request.Bundle) + if err := validateAuthoringRouteIdentity(c, request.Bundle); err != nil { + return authoringHTTPError(c, err) + } + if capabilities.AuthoringCompile == nil || capabilities.Materialize == nil || capabilities.ActivateRelease == nil || capabilities.ValidateReleaseGeneration == nil { + return authoringHTTPError(c, explorerUnavailable("publish", "PUBLICATION_UNAVAILABLE", "Explorer publication is not configured")) + } + resolved, err := capabilities.AuthoringCompile(c.Context(), ExplorerAuthoringV1CompileRequest{Bundle: request.Bundle, SnapshotToken: request.SnapshotToken, RequestID: requestIDFromFiber(c)}) + if err != nil { + return authoringHTTPError(c, err) + } + receipt := resolved.Receipt + revisionID := "authoring_" + strings.TrimPrefix(receipt.ID, "receipt_") + if active, activeErr := explorers.ActiveRevision(c.Context(), receipt.Project, receipt.ExplorerID); activeErr == nil && active.ID == revisionID { + state, stateErr := builderStateFromResolved(c.Context(), explorers, capabilities, receipt.Project, receipt.ExplorerID, resolved, active) + if stateErr != nil { + return authoringHTTPError(c, stateErr) + } + return c.JSON(state) + } + if err := capabilities.ValidateReleaseGeneration(c.Context(), projectid.Legacy(receipt.Project), receipt.SourceGeneration); err != nil { + return authoringHTTPError(c, &explorer.AuthoringError{Status: 409, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "snapshot", Code: "SNAPSHOT_CONFLICT", Message: "the catalog generation is no longer active", Details: map[string]any{"generation": receipt.SourceGeneration}}, Cause: err}) + } + execution, err := capabilities.Materialize(c.Context(), receipt.Bundle, recipe.RuntimeBindings{Project: projectid.Legacy(receipt.Project), DatasetGeneration: receipt.SourceGeneration}) + if err != nil { + return authoringHTTPError(c, &explorer.AuthoringError{Status: 503, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "materialize", Code: "MATERIALIZATION_FAILED", Message: "Explorer materialization failed; the active revision was retained"}, Cause: err}) + } + if err := verifyQueryableOutputs(receipt.Bundle, execution); err != nil { + return authoringHTTPError(c, &explorer.AuthoringError{Status: 503, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "materialize", Code: "MATERIALIZATION_FAILED", Message: "materialization did not produce queryable outputs"}, Cause: err}) + } + if err := capabilities.ActivateRelease(c.Context(), projectid.Legacy(receipt.Project), receipt.SourceGeneration, selectorsForBundle(receipt.Bundle)); err != nil { + return authoringHTTPError(c, &explorer.AuthoringError{Status: 503, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "activation", Code: "MATERIALIZATION_ACTIVATION_FAILED", Message: "dataset release activation failed; the active revision was retained"}, Cause: err}) + } + now := time.Now().UTC() + _, err = explorers.PublishAuthoring(c.Context(), receipt, explorer.Revision{ID: revisionID, Project: receipt.Project, ExplorerID: receipt.ExplorerID, Config: receipt.CompiledConfig, ConfigDigest: receipt.IntentDigest, AuthoringBundle: receipt.NormalizedBundle, IntentDigest: receipt.IntentDigest, CompilationReceiptID: receipt.ID, Recipe: receipt.Bundle, RecipeDigest: receipt.RecipeDigest, ResolvedSchemaDigest: receipt.ResolvedSchemaDigest, SourceGeneration: receipt.SourceGeneration, Materializations: explorerMaterializations(receipt.Bundle, execution), EmittedColumns: receipt.EmittedColumns, Dataset: datasetMetadataFromExecution(receipt.Bundle, receipt.SourceGeneration, receipt.ResolvedSchemaDigest, execution), Publication: explorer.PublicationMetadata{State: string(explorer.RevisionReady), Generation: receipt.SourceGeneration, ExecutionID: execution.ID, UpdatedAt: now}, Status: explorer.RevisionReady, CreatedBy: subjectFromFiber(c), CreatedAt: now, ReadyAt: &now}) + if err != nil { + return authoringHTTPError(c, &explorer.AuthoringError{Status: 500, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "persist", Code: "REVISION_STORE_FAILED", Message: "could not store the immutable Explorer revision"}, Cause: err}) + } + active, err := explorers.ActiveRevision(c.Context(), receipt.Project, receipt.ExplorerID) + if err != nil { + return authoringHTTPError(c, err) + } + state, err := builderStateFromResolved(c.Context(), explorers, capabilities, receipt.Project, receipt.ExplorerID, resolved, active) + if err != nil { + return authoringHTTPError(c, err) + } + return c.JSON(state) + }) + + app.Get(prefix+"/bundle/active", func(c fiber.Ctx) error { + if err := authoringRead(c, authorizeRead); err != nil { + return err + } + revision, err := explorers.ActiveRevision(c.Context(), explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId"))) + if err != nil { + return authoringHTTPError(c, err) + } + if len(revision.AuthoringBundle) == 0 { + return authoringHTTPError(c, authoringSemanticRoute("export", "$", "ACTIVE_AUTHORING_BUNDLE_MISSING", "active Explorer has no authoring bundle", nil)) + } + bundle, err := explorer.DecodeAuthoringBundleV1ForMigration(revision.AuthoringBundle) + if err != nil { + return authoringHTTPError(c, err) + } + canonical, err := bundle.CanonicalJSON() + if err != nil { + return authoringHTTPError(c, err) + } + c.Set("Content-Type", "application/json") + return c.Send(canonical) + }) +} + +func validateAuthoringRouteIdentity(c fiber.Ctx, bundle explorer.ExplorerAuthoringBundleV1) error { + if projectid.Canonical(bundle.Project) != explorerProjectParam(c) || bundle.ExplorerID != strings.TrimSpace(c.Params("explorerId")) { + return explorerConflict("scope", "AUTHORING_IDENTITY_CONFLICT", "the authoring bundle identity does not match the route scope", nil) + } + return nil +} + +func loadExplorerBuilderState(ctx context.Context, service *explorer.Service, capabilities ExplorerV2LifecycleConfig, project, id, requestID string) (*explorer.ExplorerBuilderStateV1, error) { + owner, err := service.Get(ctx, project, id) + if err != nil { + return nil, err + } + if capabilities.Catalog == nil { + return nil, explorerUnavailable("catalog", "CATALOG_UNAVAILABLE", "Explorer authoring catalog is not configured") + } + snapshot, err := capabilities.Catalog(ctx, project, id, "") + if err != nil || !snapshot.Complete || snapshot.Truncated { + return nil, explorerUnavailable("catalog", "CATALOG_UNAVAILABLE", "Explorer authoring catalog is unavailable or incomplete") + } + active, err := service.ActiveRevision(ctx, project, id) + if errors.Is(err, explorer.ErrNotFound) { + bundle := explorer.ExplorerAuthoringBundleV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, Project: projectid.Canonical(project), ExplorerID: id, Title: owner.Title, Documents: []explorer.ExplorerBuilderDocumentV1{}} + state := newBuilderState(owner, bundle, snapshot, nil, nil) + return &state, nil + } + if err != nil { + return nil, err + } + if len(active.AuthoringBundle) == 0 { + return nil, &explorer.AuthoringError{Status: 422, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "builder", Code: "ACTIVE_AUTHORING_BUNDLE_MISSING", Message: "active Explorer cannot be edited because its authoring bundle is missing", RequestID: requestID}} + } + bundle, err := explorer.DecodeAuthoringBundleV1ForMigration(active.AuthoringBundle) + if err != nil { + return nil, &explorer.AuthoringError{Status: 422, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "builder", Code: "ACTIVE_AUTHORING_BUNDLE_INVALID", Message: "active Explorer authoring state is invalid", RequestID: requestID}, Cause: err} + } + if capabilities.AuthoringCompile == nil { + return nil, explorerUnavailable("builder", "AUTHORING_COMPILER_UNAVAILABLE", "Explorer authoring resolver is not configured") + } + resolved, err := capabilities.AuthoringCompile(ctx, ExplorerAuthoringV1CompileRequest{Bundle: bundle, SnapshotToken: snapshot.Token, RequestID: requestID}) + if err != nil { + return nil, err + } + return builderStateFromResolved(ctx, service, capabilities, project, id, resolved, active) +} + +func builderStateFromResolved(ctx context.Context, service *explorer.Service, capabilities ExplorerV2LifecycleConfig, project, id string, resolved ExplorerAuthoringV1CompileResult, active *explorer.Revision) (*explorer.ExplorerBuilderStateV1, error) { + owner, err := service.Get(ctx, project, id) + if err != nil { + return nil, err + } + // ResolveAuthoringBundle already validated and resolved this exact + // snapshot. Reuse it for the Builder response so catalog metadata and + // bindings are guaranteed to describe the same generation/token. + snapshot := resolved.Snapshot + if snapshot.Token == "" { + var snapshotErr error + snapshot, snapshotErr = capabilities.Catalog(ctx, project, id, resolved.SourceGeneration) + if snapshotErr != nil { + return nil, explorerUnavailable("catalog", "CATALOG_UNAVAILABLE", snapshotErr.Error()) + } + } + state := newBuilderState(owner, resolved.Bundle, snapshot, resolved.ResolvedBindings, active) + state.Diagnostics = append(state.Diagnostics, resolved.Diagnostics...) + return &state, nil +} + +func newBuilderState(owner *explorer.Explorer, bundle explorer.ExplorerAuthoringBundleV1, snapshot explorer.CatalogSnapshot, bindings []explorer.ExplorerResolvedBindingV1, active *explorer.Revision) explorer.ExplorerBuilderStateV1 { + state := explorer.ExplorerBuilderStateV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerBuilderStateV1Kind, Project: projectid.Canonical(owner.Project), ExplorerID: owner.ExplorerID, Title: owner.Title, Bundle: bundle, Catalog: builderCatalog(snapshot), Bindings: bindings, Diagnostics: []explorer.AuthoringDiagnostic{}} + if state.Bindings == nil { + state.Bindings = []explorer.ExplorerResolvedBindingV1{} + } + if active != nil { + state.Active = explorer.ExplorerBuilderPublicationV1{RevisionID: active.ID, State: string(active.Status), Generation: active.SourceGeneration, IntentDigest: active.IntentDigest} + if active.ActivatedAt != nil { + state.Active.PublishedAt = *active.ActivatedAt + } + if active.Migration != nil { + state.Active.Migration = &explorer.ExplorerMigrationSummaryV1{ + Kind: active.Migration.Kind, + Source: active.Migration.Source, + SourceProject: active.Migration.SourceProject, + SourceExplorerID: active.Migration.SourceExplorerID, + OriginalConfigDigest: active.Migration.OriginalConfigDigest, + OriginalMappingDigest: active.Migration.OriginalMappingDigest, + MigratedAt: active.Migration.MigratedAt, + } + } + } + return state +} + +func builderCatalog(snapshot explorer.CatalogSnapshot) explorer.ExplorerBuilderCatalogV1 { + result := explorer.ExplorerBuilderCatalogV1{SnapshotToken: snapshot.Token, Generation: snapshot.Generation, ResolvedSchemaDigest: snapshot.ResolvedSchemaDigest, AuthorizationScopeDigest: snapshot.AuthorizationScopeDigest, Nodes: []explorer.ExplorerCatalogNodeV1{}, Edges: []explorer.ExplorerCatalogEdgeV1{}, Candidates: []explorer.ExplorerCandidateV1{}} + for _, node := range snapshot.Catalog.Nodes { + result.Nodes = append(result.Nodes, explorer.ExplorerCatalogNodeV1{NodeID: node.ID, ResourceType: node.ResourceType}) + } + for _, edge := range snapshot.Catalog.Edges { + result.Edges = append(result.Edges, explorer.ExplorerCatalogEdgeV1{EdgeID: edge.ID, FromNodeID: edge.FromNodeID, ToNodeID: edge.ToNodeID, Label: edge.Label}) + } + ids := make([]string, 0, len(snapshot.Catalog.Selections)) + for id := range snapshot.Catalog.Selections { + ids = append(ids, id) + } + sort.Strings(ids) + for _, id := range ids { + candidate := snapshot.Catalog.Selections[id] + result.Candidates = append(result.Candidates, explorer.ExplorerCandidateV1{CandidateID: candidate.ID, NodeID: candidate.NodeID, Label: candidate.FieldRef, LogicalType: candidate.LogicalType, Filterable: candidate.Filterable, Chartable: candidate.Chartable}) + } + return result +} + +// Retained for migration and contract tests; no standalone catalog route uses it. +func authoringCatalogResponse(snapshot explorer.CatalogSnapshot) fiber.Map { + catalog := builderCatalog(snapshot) + candidates := make([]fiber.Map, 0, len(catalog.Candidates)) + for _, candidate := range catalog.Candidates { + candidates = append(candidates, fiber.Map{"candidateId": candidate.CandidateID, "nodeId": candidate.NodeID, "label": candidate.Label, "path": candidate.Label, "fieldRef": candidate.Label, "logicalType": candidate.LogicalType, "filterable": candidate.Filterable, "chartable": candidate.Chartable}) + } + return fiber.Map{"apiVersion": explorer.ExplorerAuthoringV1APIVersion, "kind": "ExplorerAuthoringCatalog", "snapshotToken": snapshot.Token, "project": snapshot.Project, "sourceGeneration": snapshot.Generation, "authorizationScopeDigest": snapshot.AuthorizationScopeDigest, "resolvedSchemaDigest": snapshot.ResolvedSchemaDigest, "nodes": catalog.Nodes, "routeEdges": catalog.Edges, "candidates": candidates, "diagnostics": snapshot.Diagnostics} +} + +func decodeAuthoringStrict(raw []byte, value any) error { + if err := explorer.RejectDuplicateJSONKeys(raw); err != nil { + return err + } + decoder := json.NewDecoder(bytes.NewReader(raw)) + decoder.DisallowUnknownFields() + if err := decoder.Decode(value); err != nil { + return err + } + var trailing any + if err := decoder.Decode(&trailing); err != io.EOF { + if err == nil { + return fmt.Errorf("multiple JSON values") + } + return err + } + return nil +} + +func authoringRead(c fiber.Ctx, authorizeRead explorerConfigReadAuthorizer) error { + if err := authorizeRead(c.Context(), principalFromFiber(c), explorerProjectParam(c)); err != nil { + return authoringHTTPError(c, &explorer.AuthoringError{Status: 403, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "authorization", Code: "FORBIDDEN", Message: "forbidden"}, Cause: err}) + } + return nil +} +func authoringWrite(c fiber.Ctx, authorizer authscope.Authorizer) error { + project := explorerProjectParam(c) + path := authscope.NormalizeAuthResourcePath(strings.TrimSpace(c.Query("auth_resource_path"))) + if err := authorizer.AuthorizeWrite(c.Context(), principalFromFiber(c), project, path); err != nil { + return authoringHTTPError(c, &explorer.AuthoringError{Status: 403, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "authorization", Code: "FORBIDDEN", Message: "forbidden"}, Cause: err}) + } + return nil +} +func requestIDFromFiber(c fiber.Ctx) string { + value, _ := c.Locals("request_id").(string) + return value +} + +// logAuthoringCompatibilityRequest is intentionally scoped to the incident +// request so normal Builder traffic never writes full authoring documents to +// logs. It records the raw envelope plus the three fields needed to determine +// whether the frontend or Loom dropped candidate occurrence mappings. +func logAuthoringCompatibilityRequest(c fiber.Ctx, operation string, bundle explorer.ExplorerAuthoringBundleV1) { + if requestIDFromFiber(c) != "f9131e28d8e058da07145008a1e93970" { + return + } + for index, document := range bundle.AuthoringDocuments() { + slog.Info("Explorer authoring compatibility request", + "request_id", requestIDFromFiber(c), + "operation", operation, + "document_index", index, + "document_candidate_ids", document.CandidateIDs, + "document_candidate_occurrences", document.CandidateOccurrences, + "document_route_occurrences", document.RouteOccurrences, + "raw_body", string(c.Body()), + ) + } +} + +func malformedRouteError(stage string, err error) error { + return &explorer.AuthoringError{Status: 400, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: "MALFORMED_AUTHORING_REQUEST", JSONPath: "$", Message: err.Error()}, Cause: err} +} +func authoringSemanticRoute(stage, path, code, message string, details map[string]any) error { + return &explorer.AuthoringError{Status: 422, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: code, JSONPath: path, Message: message, Details: details}} +} +func receiptHasOutput(bundle recipe.Bundle, id string) bool { + for _, output := range bundle.Outputs { + if output.Name == id { + return true + } + } + return false +} +func previewColumnsForOutput(bindings []explorer.ExplorerResolvedBindingV1, output string) []explorer.ExplorerPreviewColumnV1 { + columns := []explorer.ExplorerPreviewColumnV1{} + for _, binding := range bindings { + if binding.OutputID != output { + continue + } + for _, emission := range binding.CandidateEmissions { + columns = append(columns, explorer.ExplorerPreviewColumnV1{ + OutputID: output, CandidateID: emission.CandidateID, OccurrenceID: emission.OccurrenceID, + EmissionID: emission.EmissionID, PublicColumn: emission.PublicColumn, Label: emission.Label, + LogicalType: emission.LogicalType, Filterable: emission.Filterable, Chartable: emission.Chartable, + }) + } + } + return columns +} +func authoringHTTPError(c fiber.Ctx, err error) error { + requestID := requestIDFromFiber(c) + var value *explorer.AuthoringError + if errors.As(err, &value) { + value.Diagnostic.RequestID = requestID + slog.Error("Explorer authoring request failed", "request_id", requestID, "project", explorerProjectParam(c), "explorer_id", strings.TrimSpace(c.Params("explorerId")), "stage", value.Diagnostic.Stage, "code", value.Diagnostic.Code, "json_path", value.Diagnostic.JSONPath, "message", value.Diagnostic.Message, "details", value.Diagnostic.Details, "cause", value.Cause) + return c.Status(value.Status).JSON(fiber.Map{"error": fiber.Map{"code": value.Diagnostic.Code, "message": value.Diagnostic.Message, "requestId": requestID, "diagnostic": value.Diagnostic}, "diagnostics": []explorer.AuthoringDiagnostic{value.Diagnostic}}) + } + if errors.Is(err, explorer.ErrNotFound) { + return c.Status(404).JSON(fiber.Map{"error": fiber.Map{"code": "NOT_FOUND", "message": "Explorer resource not found", "requestId": requestID}}) + } + return c.Status(500).JSON(fiber.Map{"error": fiber.Map{"code": "INTERNAL_ERROR", "message": "internal server error", "requestId": requestID}}) +} diff --git a/internal/server/explorer_authoring_v1_test.go b/internal/server/explorer_authoring_v1_test.go new file mode 100644 index 00000000..2258875a --- /dev/null +++ b/internal/server/explorer_authoring_v1_test.go @@ -0,0 +1,440 @@ +package server + +import ( + "context" + "encoding/json" + "errors" + "net/http" + "strings" + "testing" + + graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataset" + "github.com/calypr/loom/internal/explorer" + "github.com/gofiber/fiber/v3" +) + +func authoringTestSnapshot(t *testing.T) explorer.CatalogSnapshot { + t.Helper() + catalog := explorer.Catalog{ + Nodes: []explorer.CatalogNode{{ID: "n_base", ResourceType: "Patient"}, {ID: "n_child", ResourceType: "Observation"}}, + Edges: []explorer.CatalogEdge{{ID: "e_forward", FromNodeID: "n_base", ToNodeID: "n_child", Label: "observation"}}, + Selections: map[string]explorer.CatalogSelection{ + "s_base": {ID: "s_base", NodeID: "n_base", FieldRef: "Patient.id", Select: "id", LogicalType: "string", Filterable: true, Chartable: true}, + "s_child": {ID: "s_child", NodeID: "n_child", FieldRef: "Observation.status", Select: "status", LogicalType: "string", Filterable: true, Chartable: true}, + }, + } + snapshot, err := explorer.NewCatalogSnapshot("project-a", "generation-a", "scope-a", catalog, true, false, nil) + if err != nil { + t.Fatal(err) + } + return snapshot +} + +func authoringTestBundle(document explorer.ExplorerBuilderDocumentV1) explorer.ExplorerAuthoringBundleV1 { + if len(document.CandidateOccurrences) == 0 { + for _, candidateID := range document.CandidateIDs { + document.CandidateOccurrences = append(document.CandidateOccurrences, explorer.ExplorerCandidateOccurrenceV1{CandidateID: candidateID, OccurrenceID: "base"}) + } + } + return explorer.ExplorerAuthoringBundleV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, Project: "project-a", ExplorerID: "custom", Document: document} +} + +func TestAuthoringCatalogResponseIncludesCandidatePath(t *testing.T) { + response := authoringCatalogResponse(authoringTestSnapshot(t)) + candidates, ok := response["candidates"].([]fiber.Map) + if !ok || len(candidates) != 2 { + t.Fatalf("candidates=%#v", response["candidates"]) + } + for _, candidate := range candidates { + if candidate["path"] == "" || candidate["path"] != candidate["fieldRef"] { + t.Fatalf("candidate path compatibility alias is missing: %#v", candidate) + } + } +} + +func TestCompileAuthoringV1ZeroHopAndPresentationByEmission(t *testing.T) { + snapshot := authoringTestSnapshot(t) + visible := false + document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"s_base"}} + emission := explorer.OpaqueID("em_", "patient\x00base\x00s_base") + document.Presentation = map[string]explorer.ExplorerPresentationBindingV1{emission: {Label: "Patient ID", Visible: &visible, Filter: &explorer.ExplorerFilterBindingV1{Label: "Filter ID"}, Chart: &explorer.ExplorerChartBindingV1{Type: "bar", Title: "ID chart"}}} + result, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) + if err != nil { + t.Fatal(err) + } + if len(result.Receipt.EmittedColumns) != 1 || result.Receipt.EmittedColumns[0].EmissionID != emission { + t.Fatalf("emissions=%#v", result.Receipt.EmittedColumns) + } + publicColumn := result.Receipt.EmittedColumns[0].PublicColumn + if want := generatedFieldName("s_base", "base"); publicColumn != want { + t.Fatalf("public column=%q, want lowered recipe field %q", publicColumn, want) + } + if got := result.Receipt.Bundle.Outputs[0].Fields[0].Name; got != publicColumn { + t.Fatalf("lowered recipe field=%q, want emitted public column %q", got, publicColumn) + } + repeated, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) + if err != nil || repeated.Receipt.ID != result.Receipt.ID { + t.Fatalf("compilation is not deterministic: first=%q second=%q err=%v", result.Receipt.ID, repeated.Receipt.ID, err) + } + if strings.Contains(string(result.Receipt.NormalizedBundle), "select") || strings.Contains(string(result.Receipt.NormalizedBundle), "expr") || strings.Contains(string(result.Receipt.NormalizedBundle), "children") { + t.Fatalf("intent leaked recipe syntax: %s", result.Receipt.NormalizedBundle) + } + var config explorer.ConfigV2 + if err := json.Unmarshal(result.Receipt.CompiledConfig, &config); err != nil { + t.Fatal(err) + } + if len(config.Views) != 1 || len(config.Views[0].Table.Columns) != 1 || config.Views[0].Table.Columns[0].Column != publicColumn || config.Views[0].Table.Columns[0].Label != "Patient ID" || config.Views[0].Table.Columns[0].Visible || len(config.Views[0].Filters) != 1 || config.Views[0].Filters[0].Column != publicColumn || len(config.Views[0].Charts) != 1 || config.Views[0].Charts[0].Column != publicColumn { + t.Fatalf("presentation was not lowered by emission ID: %#v", config.Views) + } +} + +func TestCompileAuthoringV1UsesCatalogRowGrain(t *testing.T) { + snapshot := authoringTestSnapshot(t) + snapshot.Catalog.Nodes = append(snapshot.Catalog.Nodes, explorer.CatalogNode{ID: "n_file", ResourceType: "DocumentReference"}) + snapshot.Catalog.Selections["s_file"] = explorer.CatalogSelection{ID: "s_file", NodeID: "n_file", FieldRef: "DocumentReference.id", Select: "id"} + document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "files"}, BaseNodeID: "n_file", RowNodeID: "n_file", CandidateIDs: []string{"s_file"}} + result, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) + if err != nil { + t.Fatal(err) + } + if got := result.Receipt.Bundle.Outputs[0].RowGrain; got != "file" { + t.Fatalf("row grain=%q, want file", got) + } +} + +func TestCompileAuthoringV1CanonicalizesLowercaseCatalogResourceType(t *testing.T) { + snapshot := authoringTestSnapshot(t) + snapshot.Catalog.Nodes = []explorer.CatalogNode{{ID: "n_specimen", ResourceType: "specimen"}} + snapshot.Catalog.Edges = nil + snapshot.Catalog.Selections = map[string]explorer.CatalogSelection{} + document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "specimens"}, BaseNodeID: "n_specimen", RowNodeID: "n_specimen"} + result, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) + if err != nil { + t.Fatal(err) + } + output := result.Receipt.Bundle.Outputs[0] + if output.RootResourceType != "Specimen" || output.RowGrain != "specimen" { + t.Fatalf("lowered output root=%q grain=%q, want Specimen/specimen", output.RootResourceType, output.RowGrain) + } +} + +func TestCompileAuthoringV1RejectsLegacyLowercaseNodeID(t *testing.T) { + snapshot := authoringTestSnapshot(t) + canonicalNodeID := explorer.OpaqueID("n_", "Specimen") + legacyNodeID := explorer.OpaqueID("n_", "specimen") + snapshot.Catalog.Nodes = []explorer.CatalogNode{{ID: canonicalNodeID, ResourceType: "Specimen"}} + snapshot.Catalog.Edges = nil + snapshot.Catalog.Selections = map[string]explorer.CatalogSelection{} + document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "specimen"}, BaseNodeID: legacyNodeID, RowNodeID: legacyNodeID} + _, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) + if err == nil || !strings.Contains(err.Error(), "STALE_BASE_NODE") { + t.Fatalf("legacy node identity was accepted: %v", err) + } +} + +func TestCompileAuthoringV1NormalizesLegacyCandidateOccurrence(t *testing.T) { + snapshot := authoringTestSnapshot(t) + document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"s_base"}} + bundle := explorer.ExplorerAuthoringBundleV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, Project: "project-a", ExplorerID: "custom", Documents: []explorer.ExplorerBuilderDocumentV1{document}} + result, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: bundle, SnapshotToken: snapshot.Token}) + if err != nil { + t.Fatal(err) + } + documents := result.Bundle.AuthoringDocuments() + if len(documents) != 1 || len(documents[0].CandidateOccurrences) != 1 || documents[0].CandidateOccurrences[0].CandidateID != "s_base" || documents[0].CandidateOccurrences[0].OccurrenceID != "base" { + t.Fatalf("legacy candidate was not normalized: %#v", documents) + } +} + +func TestResolveAuthoringBundleUsesBaseNodeResourceTypesForGroupMemberAndFile(t *testing.T) { + snapshot := authoringTestSnapshot(t) + snapshot.Catalog.Nodes = []explorer.CatalogNode{{ID: "n_group", ResourceType: "Group"}, {ID: "n_file", ResourceType: "DocumentReference"}} + snapshot.Catalog.Edges = nil + snapshot.Catalog.Selections = map[string]explorer.CatalogSelection{} + bundle := authoringTestBundle(explorer.ExplorerBuilderDocumentV1{}) + bundle.Document = explorer.ExplorerBuilderDocumentV1{} + bundle.Documents = []explorer.ExplorerBuilderDocumentV1{ + {Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "groupmember", Title: "Members"}, BaseNodeID: "n_group", RowNodeID: "n_group"}, + {Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "file", Title: "Files"}, BaseNodeID: "n_file", RowNodeID: "n_file"}, + } + result, err := ResolveAuthoringBundle(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: bundle, SnapshotToken: snapshot.Token}) + if err != nil { + t.Fatal(err) + } + if len(result.ResolvedBindings) != 2 || result.ResolvedBindings[0].BaseResourceType != "Group" || result.ResolvedBindings[0].RouteKind != "ZERO_HOP" || result.ResolvedBindings[1].BaseResourceType != "DocumentReference" { + t.Fatalf("resolved bindings=%#v", result.ResolvedBindings) + } +} + +func TestCompileAuthoringV1PreservesMultipleOutputsAndTabs(t *testing.T) { + snapshot := authoringTestSnapshot(t) + patient := explorer.ExplorerBuilderDocumentV1{ + Kind: explorer.ExplorerBuilderV1Kind, + Output: explorer.ExplorerOutputIdentityV1{ID: "patient", Title: "Patients"}, + BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"s_base"}, + CandidateOccurrences: []explorer.ExplorerCandidateOccurrenceV1{{CandidateID: "s_base", OccurrenceID: "base"}}, + } + observations := explorer.ExplorerBuilderDocumentV1{ + Kind: explorer.ExplorerBuilderV1Kind, + Output: explorer.ExplorerOutputIdentityV1{ID: "observations", Title: "Observations"}, + BaseNodeID: "n_child", RowNodeID: "n_child", CandidateIDs: []string{"s_child"}, + CandidateOccurrences: []explorer.ExplorerCandidateOccurrenceV1{{CandidateID: "s_child", OccurrenceID: "base"}}, + } + bundle := authoringTestBundle(patient) + bundle.Document = explorer.ExplorerBuilderDocumentV1{} + bundle.Documents = []explorer.ExplorerBuilderDocumentV1{patient, observations} + bundle.Tabs = []explorer.ExplorerTabV1{ + {ID: "observations", Title: "Observations", OutputID: "observations", Order: 1}, + {ID: "patient", Title: "Patients", OutputID: "patient", Order: 0}, + } + result, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: bundle, SnapshotToken: snapshot.Token}) + if err != nil { + t.Fatal(err) + } + if len(result.Receipt.Bundle.Outputs) != 2 || len(result.Receipt.OutputFingerprints) != 2 { + t.Fatalf("compiled outputs=%#v fingerprints=%#v", result.Receipt.Bundle.Outputs, result.Receipt.OutputFingerprints) + } + var config explorer.ConfigV2 + if err := json.Unmarshal(result.Receipt.CompiledConfig, &config); err != nil { + t.Fatal(err) + } + if len(config.Views) != 2 || config.Views[0].ID != "patient" || config.Views[1].ID != "observations" || config.Views[0].Output != "patient" || config.Views[1].Output != "observations" { + t.Fatalf("tabs were not preserved: %#v", config.Views) + } + if strings.Contains(string(result.Receipt.NormalizedBundle), `"document"`) || !strings.Contains(string(result.Receipt.NormalizedBundle), `"documents"`) { + t.Fatalf("multi-output bundle was not canonicalized: %s", result.Receipt.NormalizedBundle) + } +} + +func TestCompileAuthoringV1MultiHopInboundAndRepeatedCandidateEmissions(t *testing.T) { + snapshot := authoringTestSnapshot(t) + // Catalog edges are already normalized into Builder direction. The + // compiler preserves the target occurrence while the lowerer independently + // proves that this Builder edge uses an inbound stored traversal. + snapshot.Catalog.Edges = []explorer.CatalogEdge{{ID: "e_inbound", FromNodeID: "n_base", ToNodeID: "n_child", Label: "subject"}} + document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_child", RouteEdgeIDs: []string{"e_inbound"}, RouteOccurrences: []explorer.ExplorerRouteOccurrenceV1{{ID: "child-1", Index: 0, NodeID: "n_child"}}, CandidateIDs: []string{"s_base", "s_child"}, CandidateOccurrences: []explorer.ExplorerCandidateOccurrenceV1{{CandidateID: "s_base", OccurrenceID: "base"}, {CandidateID: "s_child", OccurrenceID: "child-1"}, {CandidateID: "s_child", OccurrenceID: "child-1"}}} + if _, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}); err == nil || !strings.Contains(err.Error(), "DUPLICATE_CANDIDATE_OCCURRENCE") { + t.Fatalf("duplicate candidate occurrence error=%v", err) + } + document.CandidateOccurrences = document.CandidateOccurrences[:2] + result, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) + if err != nil { + t.Fatal(err) + } + if len(result.Receipt.Bundle.Outputs[0].Traversals) != 1 || result.Receipt.Bundle.Outputs[0].Traversals[0].ToResourceType != "Observation" { + t.Fatalf("bundle=%#v", result.Receipt.Bundle) + } + // The same candidate can intentionally emit once at two exact route + // occurrences when a resource type repeats. + snapshot.Catalog.Edges = append(snapshot.Catalog.Edges, explorer.CatalogEdge{ID: "e_back", FromNodeID: "n_child", ToNodeID: "n_base", Label: "patient"}) + repeated := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base", RouteEdgeIDs: []string{"e_inbound", "e_back"}, RouteOccurrences: []explorer.ExplorerRouteOccurrenceV1{{ID: "child-1", Index: 0, NodeID: "n_child"}, {ID: "base-2", Index: 1, NodeID: "n_base"}}, CandidateIDs: []string{"s_base"}, CandidateOccurrences: []explorer.ExplorerCandidateOccurrenceV1{{CandidateID: "s_base", OccurrenceID: "base"}, {CandidateID: "s_base", OccurrenceID: "base-2"}}} + repeatedResult, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(repeated), SnapshotToken: snapshot.Token}) + if err != nil { + t.Fatal(err) + } + count := 0 + for _, mapping := range repeatedResult.Receipt.IdentityMappings { + if mapping.CandidateID == "s_base" { + count += len(mapping.EmissionIDs) + } + } + if count != 2 { + t.Fatalf("candidate-to-emission mapping=%#v", repeatedResult.Receipt.IdentityMappings) + } +} + +func TestCompileAuthoringV1ReportsStaleCandidateBeforeRecipeValidation(t *testing.T) { + snapshot := authoringTestSnapshot(t) + document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"stale"}} + _, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) + if err == nil || !strings.Contains(err.Error(), "STALE_CANDIDATE_ID") { + t.Fatalf("error=%v", err) + } +} + +func TestCompileAuthoringV1ReportsCandidateNotOnRoute(t *testing.T) { + snapshot := authoringTestSnapshot(t) + document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"s_child"}} + _, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) + if err == nil || !strings.Contains(err.Error(), "SELECTION_NODE_MISMATCH") { + t.Fatalf("error=%v", err) + } +} + +func TestCompileAuthoringV1ReportsStaleRouteIdentities(t *testing.T) { + snapshot := authoringTestSnapshot(t) + baseStale := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "stale", RowNodeID: "stale"} + if _, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(baseStale), SnapshotToken: snapshot.Token}); err == nil || !strings.Contains(err.Error(), "STALE_BASE_NODE") { + t.Fatalf("stale base node error=%v", err) + } + staleEdge := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_child", RouteEdgeIDs: []string{"stale-edge"}, RouteOccurrences: []explorer.ExplorerRouteOccurrenceV1{{ID: "child", Index: 0, NodeID: "n_child"}}} + if _, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(staleEdge), SnapshotToken: snapshot.Token}); err == nil || !strings.Contains(err.Error(), "STALE_ROUTE_EDGE") { + t.Fatalf("stale route edge error=%v", err) + } +} + +func TestCompileAuthoringV1ReportsSnapshotConflict(t *testing.T) { + snapshot := authoringTestSnapshot(t) + document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base"} + _, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: "sha256:stale"}) + if err == nil || !strings.Contains(err.Error(), "STALE_CATALOG_SNAPSHOT") { + t.Fatalf("snapshot conflict error=%v", err) + } +} + +func TestCompileAuthoringV1RejectsStaleEmissionBeforeRecipeValidation(t *testing.T) { + snapshot := authoringTestSnapshot(t) + document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"s_base"}, Presentation: map[string]explorer.ExplorerPresentationBindingV1{"em_missing": {Label: "bad"}}} + _, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) + if err == nil || !strings.Contains(err.Error(), "STALE_EMISSION") { + t.Fatalf("error=%v", err) + } +} + +func TestAuthoringV1ReceiptBoundLifecycleAndExport(t *testing.T) { + t.Skip("receipt/draft lifecycle removed by publish-only Builder cutover") + store := explorer.NewMemoryStore() + service, err := explorer.NewService(store) + if err != nil { + t.Fatal(err) + } + if _, err := store.CreateInteractive(context.Background(), explorer.Explorer{Project: "project-a", ExplorerID: "custom", ManagementMode: explorer.ManagementInteractive, DraftVersion: 1}); err != nil { + t.Fatal(err) + } + snapshot := authoringTestSnapshot(t) + compilerCalls := 0 + compiler := func(ctx context.Context, request ExplorerAuthoringV1CompileRequest) (ExplorerAuthoringV1CompileResult, error) { + compilerCalls++ + return compileExplorerAuthoringV1(ctx, nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, request) + } + previewCalls := 0 + materializeCalls := 0 + preview := func(_ context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (map[string][]map[string]any, error) { + previewCalls++ + if bindings.OutputNames[0] != bundle.Outputs[0].Name { + t.Fatalf("preview output=%v", bindings.OutputNames) + } + return map[string][]map[string]any{"patient": {{"id": "p1"}}}, nil + } + materialize := func(_ context.Context, bundle recipe.Bundle, _ recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { + materializeCalls++ + return graphresolver.RecipeExecution{ID: "execution-a", SourceGeneration: "generation-a", Outputs: []graphresolver.RecipeExecutionOutput{{Name: bundle.Outputs[0].Name, State: "PUBLISHED", Columns: nil}}}, nil + } + app := fiber.New() + RegisterExplorerAuthoringV1Routes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{AuthoringCompile: compiler, Catalog: func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, Preview: preview, Materialize: materialize, ValidateReleaseGeneration: func(context.Context, string, string) error { return nil }, ActivateRelease: func(context.Context, string, string, []dataset.DataframeSelector) error { return nil }}) + document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"s_base"}} + bundle := authoringTestBundle(document) + legacyCompileRequest := map[string]any{"apiVersion": bundle.APIVersion, "kind": bundle.Kind, "project": bundle.Project, "explorerId": bundle.ExplorerID, "document": bundle.Document, "snapshotToken": snapshot.Token} + legacyCompileRaw, _ := json.Marshal(legacyCompileRequest) + legacyCompile := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/compile", string(legacyCompileRaw)) + if legacyCompile.StatusCode != http.StatusNotFound { + t.Fatalf("legacy compile route status=%d body=%s", legacyCompile.StatusCode, legacyCompile.Body) + } + var compiledBody struct { + ReceiptID string `json:"receiptId"` + IntentDigest string `json:"intentDigest"` + } + directDraftRaw, _ := json.Marshal(map[string]any{"apiVersion": bundle.APIVersion, "kind": bundle.Kind, "project": bundle.Project, "explorerId": bundle.ExplorerID, "document": bundle.Document, "snapshotToken": snapshot.Token, "expectedDraftVersion": 1}) + saved := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/custom/authoring/v1/draft", string(directDraftRaw)) + if saved.StatusCode != http.StatusOK { + t.Fatalf("save=%d %s", saved.StatusCode, saved.Body) + } + decodeBody(t, saved.Body, &compiledBody) + saveRaw, _ := json.Marshal(map[string]any{"receiptId": compiledBody.ReceiptID, "expectedDraftVersion": 1}) + staleSave := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/custom/authoring/v1/draft", string(saveRaw)) + if staleSave.StatusCode != http.StatusConflict || !strings.Contains(staleSave.Body, "DRAFT_CONFLICT") { + t.Fatalf("stale save=%d %s", staleSave.StatusCode, staleSave.Body) + } + draftExport := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v1/bundle/draft", "") + if draftExport.StatusCode != http.StatusOK || !strings.Contains(draftExport.Body, compiledBody.IntentDigest) { + t.Fatalf("draft export=%d body=%s", draftExport.StatusCode, draftExport.Body) + } + previewRaw := `{"receiptId":"` + compiledBody.ReceiptID + `","outputId":"patient","limit":1}` + previewResponse := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/preview", previewRaw) + if previewResponse.StatusCode != http.StatusOK || previewCalls != 1 { + t.Fatalf("preview=%d calls=%d %s", previewResponse.StatusCode, previewCalls, previewResponse.Body) + } + directPreviewRequest := map[string]any{"apiVersion": bundle.APIVersion, "kind": bundle.Kind, "project": bundle.Project, "explorerId": bundle.ExplorerID, "document": bundle.Document, "snapshotToken": snapshot.Token, "outputId": "patient", "limit": 1} + directPreviewRaw, _ := json.Marshal(directPreviewRequest) + directPreview := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/preview", string(directPreviewRaw)) + if directPreview.StatusCode != http.StatusOK || previewCalls != 2 || compilerCalls != 2 || !strings.Contains(directPreview.Body, "candidateId") { + t.Fatalf("direct preview=%d previewCalls=%d compilerCalls=%d %s", directPreview.StatusCode, previewCalls, compilerCalls, directPreview.Body) + } + directDraftRequest := map[string]any{"apiVersion": bundle.APIVersion, "kind": bundle.Kind, "project": bundle.Project, "explorerId": bundle.ExplorerID, "document": bundle.Document, "snapshotToken": snapshot.Token, "expectedDraftVersion": 2} + directDraftRaw, _ = json.Marshal(directDraftRequest) + directDraft := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/custom/authoring/v1/draft", string(directDraftRaw)) + if directDraft.StatusCode != http.StatusOK || compilerCalls != 3 { + t.Fatalf("direct draft=%d compilerCalls=%d %s", directDraft.StatusCode, compilerCalls, directDraft.Body) + } + directPublished := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/publish", `{"expectedDraftVersion":3}`) + if directPublished.StatusCode != http.StatusOK || materializeCalls != 1 { + t.Fatalf("direct publish=%d materializeCalls=%d %s", directPublished.StatusCode, materializeCalls, directPublished.Body) + } + if got := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/preview", `{"receiptId":"`+compiledBody.ReceiptID+`","outputId":"patient","bundle":{}}`); got.StatusCode != http.StatusBadRequest { + t.Fatalf("browser recipe packet status=%d body=%s", got.StatusCode, got.Body) + } + published := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/publish", `{"receiptId":"`+compiledBody.ReceiptID+`","requestId":"retry-a"}`) + if published.StatusCode != http.StatusOK { + t.Fatalf("publish=%d %s", published.StatusCode, published.Body) + } + retried := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/publish", `{"receiptId":"`+compiledBody.ReceiptID+`","requestId":"retry-a"}`) + if retried.StatusCode != http.StatusOK || materializeCalls != 1 { + t.Fatalf("idempotent publish=%d %s", retried.StatusCode, retried.Body) + } + exported := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v1/bundle/active", "") + if exported.StatusCode != http.StatusOK || exported.Body == "" || !strings.Contains(exported.Body, compiledBody.IntentDigest) { + t.Fatalf("export=%d body=%s", exported.StatusCode, exported.Body) + } +} + +func TestAuthoringV1MaterializationFailureRetainsActiveRevision(t *testing.T) { + t.Skip("receipt-based publish request removed by publish-only Builder cutover") + ctx := context.Background() + store := explorer.NewMemoryStore() + service, err := explorer.NewService(store) + if err != nil { + t.Fatal(err) + } + if _, err := store.CreateInteractive(ctx, explorer.Explorer{Project: "project-a", ExplorerID: "custom", ManagementMode: explorer.ManagementInteractive}); err != nil { + t.Fatal(err) + } + if _, err := store.InsertRevision(ctx, explorer.Revision{ID: "prior", Project: "project-a", ExplorerID: "custom", Status: explorer.RevisionReady}); err != nil { + t.Fatal(err) + } + if err := store.ActivateInteractive(ctx, "project-a", "custom", "prior"); err != nil { + t.Fatal(err) + } + snapshot := authoringTestSnapshot(t) + document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base"} + compiled, err := compileExplorerAuthoringV1(ctx, nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) + if err != nil { + t.Fatal(err) + } + if _, err := service.StoreCompilationReceipt(ctx, compiled.Receipt); err != nil { + t.Fatal(err) + } + releaseCalls := 0 + app := fiber.New() + RegisterExplorerAuthoringV1Routes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{ + Materialize: func(context.Context, recipe.Bundle, recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { + return graphresolver.RecipeExecution{}, errors.New("materialization unavailable") + }, + ValidateReleaseGeneration: func(context.Context, string, string) error { return nil }, + ActivateRelease: func(context.Context, string, string, []dataset.DataframeSelector) error { releaseCalls++; return nil }, + }) + request := `{"receiptId":"` + compiled.Receipt.ID + `","requestId":"materialize-failure"}` + response := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/publish", request) + if response.StatusCode != http.StatusConflict || !strings.Contains(response.Body, "MATERIALIZATION_FAILED") { + t.Fatalf("publish failure=%d %s", response.StatusCode, response.Body) + } + if releaseCalls != 0 { + t.Fatalf("release activation happened after materialization failure") + } + active, err := service.ActiveRevision(ctx, "project-a", "custom") + if err != nil || active.ID != "prior" { + t.Fatalf("active revision changed after failed materialization: %#v err=%v", active, err) + } +} diff --git a/internal/server/explorer_authoring_v2_routes.go b/internal/server/explorer_authoring_v2_routes.go new file mode 100644 index 00000000..a213fc7d --- /dev/null +++ b/internal/server/explorer_authoring_v2_routes.go @@ -0,0 +1,524 @@ +package server + +import ( + "context" + "errors" + "fmt" + "net/http" + "strings" + "time" + + graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataframe/recipe/engine" + "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/explorer/authoringv2" + "github.com/calypr/loom/internal/explorer/capability" + "github.com/calypr/loom/internal/projectid" + "github.com/gofiber/fiber/v3" +) + +// RegisterExplorerAuthoringV2Routes is the hard-cut traversal Builder +// contract. V1 remains an internal stored-document migration format and is +// deliberately not registered as an HTTP surface. +func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, explorers *explorer.Service, capabilities ExplorerV2LifecycleConfig) { + if app == nil || authorizer == nil || authorizeRead == nil || explorers == nil { + return + } + prefix := "/api/v1/projects/:project/explorers/:explorerId/authoring/v2" + + readCapability := func(c fiber.Ctx) (capability.Snapshot, authoringv2.CatalogSnapshot, error) { + if capabilities.Capability == nil { + return capability.Snapshot{}, authoringv2.CatalogSnapshot{}, explorerUnavailable("capability", "CAPABILITY_UNAVAILABLE", "Explorer capability compiler is not configured") + } + project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) + snapshot, err := capabilities.Capability(c.Context(), project, id, "") + if err != nil || !snapshot.Usable() { + if err == nil { + err = capability.ErrSnapshotUnavailable + } + return capability.Snapshot{}, authoringv2.CatalogSnapshot{}, explorerUnavailable("capability", "CAPABILITY_UNAVAILABLE", err.Error()) + } + return snapshot, authoringV2Catalog(snapshot, id), nil + } + + app.Get(prefix+"/capability", func(c fiber.Ctx) error { + if err := authoringRead(c, authorizeRead); err != nil { + return err + } + _, wire, err := readCapability(c) + if err != nil { + return authoringHTTPError(c, err) + } + return c.JSON(wire) + }) + + // Suggested values stay out of the main capability document. They are + // bounded during capability construction and fetched only when a user opens + // a field control, while retaining the exact snapshot-token semantics used + // by compilation. + app.Get(prefix+"/capabilities/:snapshotToken/candidates/:candidateId/suggestions", func(c fiber.Ctx) error { + if err := authoringRead(c, authorizeRead); err != nil { + return err + } + if capabilities.CapabilityToken == nil { + return authoringHTTPError(c, explorerUnavailable("capability", "CAPABILITY_UNAVAILABLE", "Explorer capability lookup is not configured")) + } + project := explorerProjectParam(c) + token, candidateID := strings.TrimSpace(c.Params("snapshotToken")), strings.TrimSpace(c.Params("candidateId")) + if token == "" || candidateID == "" { + return authoringHTTPError(c, malformedRouteError("capability", fmt.Errorf("snapshotToken and candidateId are required"))) + } + snapshot, err := capabilities.CapabilityToken(c.Context(), project, token) + if err != nil { + return authoringHTTPError(c, explorerConflict("capability", "STALE_CAPABILITY_SNAPSHOT", "the capability snapshot is stale or unavailable", map[string]any{"snapshotToken": token})) + } + for _, candidate := range snapshot.Candidates { + if candidate.ID != candidateID { + continue + } + return c.JSON(fiber.Map{ + "apiVersion": authoringv2.APIVersion, "kind": "ExplorerCandidateSuggestions", + "snapshotToken": token, "candidateId": candidateID, + "values": append([]string(nil), candidate.SuggestedValues...), + "complete": candidate.SuggestionsComplete, "truncated": candidate.SuggestionsTruncated, + }) + } + return authoringHTTPError(c, &explorer.AuthoringError{Status: http.StatusNotFound, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "capability", Code: "CANDIDATE_NOT_FOUND", Message: "candidate is not present in the capability snapshot"}}) + }) + + app.Get(prefix+"/builder", func(c fiber.Ctx) error { + if err := authoringRead(c, authorizeRead); err != nil { + return err + } + snapshot, wire, err := readCapability(c) + if err != nil { + return authoringHTTPError(c, err) + } + project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) + owner, err := explorers.Get(c.Context(), project, id) + if err != nil { + return authoringHTTPError(c, err) + } + _ = owner + state := authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, Catalog: wire} + if active, activeErr := explorers.ActiveRevision(c.Context(), project, id); activeErr == nil && len(active.AuthoringBundle) != 0 { + if document, decodeErr := authoringv2.DecodeDocument(active.AuthoringBundle); decodeErr == nil { + state.Document = &document + } else if bundle, decodeErr := explorer.DecodeAuthoringBundleV1ForMigration(active.AuthoringBundle); decodeErr == nil { + if documents := bundle.AuthoringDocuments(); len(documents) > 0 { + if document, migrateErr := migrateV1DocumentToCapability(documents[0], snapshot, wire); migrateErr == nil { + state.Document = &document + } + } + } + } else if activeErr != nil && !errors.Is(activeErr, explorer.ErrNotFound) { + return authoringHTTPError(c, activeErr) + } + if err := state.Validate(); err != nil { + return authoringHTTPError(c, explorerUnavailable("capability", "CAPABILITY_UNAVAILABLE", err.Error())) + } + return c.JSON(state) + }) + + compileHandler := func(c fiber.Ctx) error { + if err := authoringWrite(c, authorizer); err != nil { + return err + } + var request struct { + Document authoringv2.Document `json:"document"` + SnapshotToken string `json:"snapshotToken"` + } + if err := decodeAuthoringStrict(c.Body(), &request); err != nil { + return authoringHTTPError(c, malformedRouteError("intent", err)) + } + if (capabilities.CapabilityToken == nil && capabilities.AuthorizedCapabilityCompile == nil) || (capabilities.CompileReceipt == nil && capabilities.AuthoringCompile == nil) { + return authoringHTTPError(c, explorerUnavailable("compile", "CAPABILITY_UNAVAILABLE", "Explorer V2 compiler is not configured")) + } + project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) + var err error + var snapshot capability.Snapshot + var authorized AuthorizedCapability + if capabilities.AuthorizedCapabilityCompile != nil { + authorized, err = capabilities.AuthorizedCapabilityCompile(c.Context(), project, request.SnapshotToken) + snapshot = authorized.Snapshot + } else { + snapshot, err = capabilities.CapabilityToken(c.Context(), project, request.SnapshotToken) + } + if err != nil { + return authoringHTTPError(c, explorerConflict("capability", "STALE_CAPABILITY_SNAPSHOT", "the capability snapshot is stale or unavailable", map[string]any{"snapshotToken": request.SnapshotToken})) + } + wire := authoringV2Catalog(snapshot, id) + state := authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, Document: &request.Document, Catalog: wire} + if err := state.Validate(); err != nil { + return authoringHTTPError(c, authoringSemanticRoute("intent", "$", "INVALID_AUTHORING_INTENT", err.Error(), nil)) + } + var stored *explorer.CompilationReceipt + nativeReceipt := capabilities.CompileReceipt != nil + if nativeReceipt { + stored, err = capabilities.CompileReceipt(c.Context(), ExplorerV2ReceiptCompileRequest{Project: project, ExplorerID: id, Document: request.Document, SnapshotToken: snapshot.Token, RequestID: requestIDFromFiber(c), Authorized: authorized}) + } else { + // Compatibility path for migration-only callers. Production wiring + // supplies CompileReceipt and never enters this V1 adapter. + bundle, bundleErr := authoringV2Bundle(project, id, request.Document, wire) + if bundleErr != nil { + return authoringHTTPError(c, authoringSemanticRoute("intent", "$", "INVALID_AUTHORING_INTENT", bundleErr.Error(), nil)) + } + resolved, compileErr := capabilities.AuthoringCompile(c.Context(), ExplorerAuthoringV1CompileRequest{Bundle: bundle, SnapshotToken: snapshot.Token, RequestID: requestIDFromFiber(c)}) + if compileErr == nil { + stored = &resolved.Receipt + } + err = compileErr + } + if err != nil { + return authoringHTTPError(c, err) + } + if stored == nil || strings.TrimSpace(stored.ID) == "" { + return authoringHTTPError(c, explorerUnavailable("compile", "COMPILATION_RECEIPT_STORE_FAILED", "compiled authoring receipt was not persisted")) + } + // The native compiler owns durable insert/readback so an idempotent hit is + // one tenant-scoped lookup. The V1 migration adapter still needs the route + // to persist its legacy receipt. + if !nativeReceipt { + stored, err = explorers.StoreCompilationReceipt(c.Context(), *stored) + if err != nil { + return authoringHTTPError(c, explorerUnavailable("compile", "COMPILATION_RECEIPT_STORE_FAILED", "compiled authoring receipt could not be persisted")) + } + } + return c.JSON(fiber.Map{ + "apiVersion": authoringv2.APIVersion, "kind": "ExplorerCompileResult", + "builder": state, "receiptId": stored.ID, "snapshotToken": snapshot.Token, + "sourceGeneration": stored.SourceGeneration, "resolvedSchemaDigest": stored.ResolvedSchemaDigest, + "emittedColumns": stored.EmittedColumns, + }) + } + app.Post(prefix+"/builder", compileHandler) + app.Post(prefix+"/compile", compileHandler) + + app.Post(prefix+"/preview", func(c fiber.Ctx) error { + started := time.Now() + previewCtx, cancel := context.WithTimeout(c.Context(), explorerPreviewTimeout) + defer cancel() + responseBytes, responseRows := 0, 0 + logReceiptID, logOutputID := "", "" + lookupDuration, authorizationDuration := time.Duration(0), time.Duration(0) + previewSummary := engine.PreviewSummary{} + outcome := "failure" + defer func() { + if capabilities.Logger != nil { + capabilities.Logger.Info("Explorer receipt preview", "operation", "receipt_preview", "project", explorerProjectParam(c), "explorer_id", strings.TrimSpace(c.Params("explorerId")), "receipt_id", logReceiptID, "output_id", logOutputID, "outcome", outcome, "duration_ms", time.Since(started).Milliseconds(), "lookup_ms", lookupDuration.Milliseconds(), "authorization_ms", authorizationDuration.Milliseconds(), "lowering_ms", previewSummary.LoweringDuration.Milliseconds(), "query_ms", previewSummary.QueryDuration.Milliseconds(), "plan_mode", previewSummary.PlanMode, "plan_profile", previewSummary.PlanProfile, "plan_fingerprint", previewSummary.PlanFingerprint, "traversal_count", previewSummary.TraversalCount, "rows", responseRows, "bytes", responseBytes) + } + }() + if err := authoringRead(c, authorizeRead); err != nil { + return err + } + var request struct { + ReceiptID string `json:"receiptId"` + OutputID string `json:"outputId"` + Limit int `json:"limit,omitempty"` + } + if err := decodeAuthoringStrict(c.Body(), &request); err != nil || strings.TrimSpace(request.ReceiptID) == "" || strings.TrimSpace(request.OutputID) == "" { + if err == nil { + err = fmt.Errorf("receiptId and outputId are required") + } + return authoringHTTPError(c, malformedRouteError("preview", err)) + } + logReceiptID, logOutputID = request.ReceiptID, request.OutputID + if request.Limit == 0 { + request.Limit = engine.DefaultPreviewLimit + } + if request.Limit < 1 || request.Limit > engine.MaxPreviewLimit { + return authoringHTTPError(c, authoringSemanticRoute("preview", "$.limit", "INVALID_PREVIEW_LIMIT", "limit must be between 1 and 1000", nil)) + } + nativeReceiptPreview := capabilities.PreviewReceipt != nil + if capabilities.AuthorizedCapabilityExecution == nil { + return authoringHTTPError(c, explorerUnavailable("preview", "PREVIEW_UNAVAILABLE", "authorized receipt execution is not configured")) + } + if capabilities.Preview == nil && capabilities.PreviewReceipt == nil { + return authoringHTTPError(c, explorerUnavailable("preview", "PREVIEW_UNAVAILABLE", "Explorer preview is not configured")) + } + lookupStarted := time.Now() + receipt, err := lookupV2Receipt(previewCtx, explorers, capabilities, explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")), request.ReceiptID) + lookupDuration = time.Since(lookupStarted) + if err != nil { + return authoringHTTPError(c, receiptRouteError("preview", err)) + } + if err := validateV2ReceiptRoute(c, receipt, capabilities); err != nil { + return authoringHTTPError(c, err) + } + authorizationStarted := time.Now() + authorized, err := capabilities.AuthorizedCapabilityExecution(previewCtx, receipt.Project, receipt.SnapshotToken) + authorizationDuration = time.Since(authorizationStarted) + snapshot := authorized.Snapshot + if err != nil || snapshot.ValidateToken(receipt.SnapshotToken) != nil || strings.TrimSpace(snapshot.Identity.Generation) != strings.TrimSpace(receipt.SourceGeneration) { + return authoringHTTPError(c, explorerConflict("preview", "RECEIPT_INPUT_UNAVAILABLE", "the receipt's capability snapshot is no longer authorized or retained", nil)) + } + if capabilities.PreviewReceipt != nil { + if err := validateAuthorizedReceiptExecution(receipt, authorized); err != nil { + return authoringHTTPError(c, explorerConflict("preview", "RECEIPT_INPUT_UNAVAILABLE", "the receipt's capability snapshot is no longer authorized or retained", nil)) + } + } + if nativeReceiptPreview { + if !receiptHasOutput(receipt.Bundle, request.OutputID) { + return authoringHTTPError(c, authoringSemanticRoute("preview", "$.outputId", "UNKNOWN_AUTHORING_OUTPUT", "outputId is not in the receipt", nil)) + } + if err := validateReceiptOutputContract(receipt, request.OutputID); err != nil { + return authoringHTTPError(c, authoringSemanticRoute("preview", "$.outputId", "UNKNOWN_AUTHORING_OUTPUT", "outputId is not in the receipt", nil)) + } + } else if !receiptHasOutput(receipt.Bundle, request.OutputID) { + return authoringHTTPError(c, authoringSemanticRoute("preview", "$.outputId", "UNKNOWN_AUTHORING_OUTPUT", "outputId is not in the receipt", nil)) + } + bindings := recipe.RuntimeBindings{Project: projectid.Legacy(receipt.Project), DatasetGeneration: receipt.SourceGeneration, PreviewLimit: request.Limit, OutputNames: []string{request.OutputID}} + applyAuthorizedScope(&bindings, authorized, false) + columns := make([]explorer.EmittedColumn, 0) + for _, column := range receipt.EmittedColumns { + if column.OutputID == request.OutputID { + columns = append(columns, column) + } + } + var encoded []byte + if capabilities.PreviewReceipt != nil { + encoder, encoderErr := newPreviewResponseEncoder(receipt, request.OutputID, columns, maxExplorerPreviewResponseBytes) + if encoderErr != nil { + return previewRouteFailure(c, encoderErr) + } + var streamErr error + previewSummary, streamErr = capabilities.PreviewReceipt(previewCtx, receipt, bindings, encoder.Visit) + err = streamErr + responseRows = previewSummary.RowCount + if err == nil { + encoded, err = encoder.Finish() + } + } else { + var rows map[string][]map[string]any + rows, err = capabilities.Preview(previewCtx, receipt.Bundle, bindings) + if err == nil { + responseRows = len(rows[request.OutputID]) + encoded, err = encodeExplorerPreviewResponse(receipt, request.OutputID, columns, rows[request.OutputID], maxExplorerPreviewResponseBytes) + } + } + if err != nil { + return previewRouteFailure(c, err) + } + responseBytes = len(encoded) + outcome = "success" + c.Set(fiber.HeaderContentType, fiber.MIMEApplicationJSON) + return c.Send(encoded) + }) + + app.Post(prefix+"/publish", func(c fiber.Ctx) error { + if err := authoringWrite(c, authorizer); err != nil { + return err + } + var request struct { + ReceiptID string `json:"receiptId"` + } + if err := decodeAuthoringStrict(c.Body(), &request); err != nil || strings.TrimSpace(request.ReceiptID) == "" { + if err == nil { + err = fmt.Errorf("receiptId is required") + } + return authoringHTTPError(c, malformedRouteError("publish", err)) + } + if (capabilities.Materialize == nil && capabilities.MaterializeReceipt == nil) || capabilities.ActivateRelease == nil || capabilities.ValidateReleaseGeneration == nil || (capabilities.CapabilityToken == nil && capabilities.AuthorizedCapabilityExecution == nil) { + return authoringHTTPError(c, explorerUnavailable("publish", "PUBLICATION_UNAVAILABLE", "Explorer publication is not configured")) + } + receipt, err := lookupV2Receipt(c.Context(), explorers, capabilities, explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")), request.ReceiptID) + if err != nil { + return authoringHTTPError(c, receiptRouteError("publish", err)) + } + if err := validateV2ReceiptRoute(c, receipt, capabilities); err != nil { + return authoringHTTPError(c, err) + } + var snapshot capability.Snapshot + var authorized AuthorizedCapability + if capabilities.AuthorizedCapabilityExecution != nil { + authorized, err = capabilities.AuthorizedCapabilityExecution(c.Context(), receipt.Project, receipt.SnapshotToken) + snapshot = authorized.Snapshot + } else { + snapshot, err = capabilities.CapabilityToken(c.Context(), receipt.Project, receipt.SnapshotToken) + } + if err != nil || strings.TrimSpace(snapshot.Identity.Generation) != strings.TrimSpace(receipt.SourceGeneration) { + return authoringHTTPError(c, explorerConflict("publish", "RECEIPT_INPUT_UNAVAILABLE", "the receipt's capability snapshot is no longer authorized or retained", nil)) + } + if capabilities.CompileReceipt != nil { + if err := validateReceiptCapability(receipt, snapshot); err != nil { + return authoringHTTPError(c, explorerConflict("publish", "RECEIPT_INPUT_UNAVAILABLE", err.Error(), nil)) + } + } + if len(receipt.EmittedColumns) == 0 || len(receipt.CompiledConfig) == 0 { + return authoringHTTPError(c, authoringSemanticRoute("publish", "$.receiptId", "NO_SELECTED_COLUMNS", "select at least one output column before publishing", nil)) + } + if err := capabilities.ValidateReleaseGeneration(c.Context(), projectid.Legacy(receipt.Project), receipt.SourceGeneration); err != nil { + return authoringHTTPError(c, explorerConflict("publish", "RECEIPT_INPUT_UNAVAILABLE", "the receipt generation is no longer active", map[string]any{"generation": receipt.SourceGeneration})) + } + bindings := recipe.RuntimeBindings{Project: projectid.Legacy(receipt.Project), DatasetGeneration: receipt.SourceGeneration} + applyAuthorizedScope(&bindings, authorized, true) + var execution graphresolver.RecipeExecution + if capabilities.MaterializeReceipt != nil { + execution, err = capabilities.MaterializeReceipt(c.Context(), receipt, bindings) + } else { + execution, err = capabilities.Materialize(c.Context(), receipt.Bundle, bindings) + } + if err != nil { + return authoringHTTPError(c, &explorer.AuthoringError{Status: 503, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "materialize", Code: "MATERIALIZATION_FAILED", Message: "Explorer materialization failed; the active revision was retained"}, Cause: err}) + } + if err := verifyQueryableOutputs(receipt.Bundle, execution); err != nil { + return authoringHTTPError(c, &explorer.AuthoringError{Status: 503, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "materialize", Code: "MATERIALIZATION_FAILED", Message: "materialization did not produce queryable outputs"}, Cause: err}) + } + if err := capabilities.ActivateRelease(c.Context(), projectid.Legacy(receipt.Project), receipt.SourceGeneration, selectorsForBundle(receipt.Bundle)); err != nil { + return authoringHTTPError(c, &explorer.AuthoringError{Status: 503, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "activation", Code: "MATERIALIZATION_ACTIVATION_FAILED", Message: "dataset release activation failed; the prior Explorer revision was retained"}, Cause: err}) + } + now := time.Now().UTC() + revisionID := "authoring_" + strings.TrimPrefix(receipt.ID, "receipt_") + revision, err := explorers.PublishAuthoring(c.Context(), *receipt, explorer.Revision{ID: revisionID, Project: receipt.Project, ExplorerID: receipt.ExplorerID, Config: receipt.CompiledConfig, ConfigDigest: receipt.IntentDigest, AuthoringBundle: receipt.NormalizedBundle, IntentDigest: receipt.IntentDigest, CompilationReceiptID: receipt.ID, Recipe: receipt.Bundle, RecipeDigest: receipt.RecipeDigest, ResolvedSchemaDigest: receipt.ResolvedSchemaDigest, SourceGeneration: receipt.SourceGeneration, Materializations: explorerMaterializations(receipt.Bundle, execution), EmittedColumns: receipt.EmittedColumns, Dataset: datasetMetadataFromExecution(receipt.Bundle, receipt.SourceGeneration, receipt.ResolvedSchemaDigest, execution), Publication: explorer.PublicationMetadata{State: string(explorer.RevisionReady), Generation: receipt.SourceGeneration, ExecutionID: execution.ID, UpdatedAt: now}, Status: explorer.RevisionReady, CreatedBy: subjectFromFiber(c), CreatedAt: now, ReadyAt: &now}) + if err != nil { + return authoringHTTPError(c, err) + } + return c.JSON(fiber.Map{"apiVersion": authoringv2.APIVersion, "kind": "ExplorerPublishResult", "receiptId": receipt.ID, "revisionId": revision.ID, "state": revision.Status, "sourceGeneration": revision.SourceGeneration}) + }) +} + +func validateV2ReceiptRoute(c fiber.Ctx, receipt *explorer.CompilationReceipt, capabilities ExplorerV2LifecycleConfig) error { + if receipt == nil || receipt.Project != explorerProjectParam(c) || receipt.ExplorerID != strings.TrimSpace(c.Params("explorerId")) { + return &explorer.AuthoringError{Status: http.StatusNotFound, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "receipt", Code: "RECEIPT_NOT_FOUND", Message: "compilation receipt was not found"}} + } + if strings.TrimSpace(receipt.ID) == "" || strings.TrimSpace(receipt.RecipeDigest) == "" || len(receipt.Bundle.Outputs) == 0 { + return explorerConflict("receipt", "RECEIPT_RECOMPILE_REQUIRED", "the compilation receipt is from an unsupported or incomplete compiler contract", nil) + } + nativeReceiptContract := capabilities.CompileReceipt != nil || capabilities.PreviewReceipt != nil || capabilities.MaterializeReceipt != nil + if nativeReceiptContract && (receipt.ReceiptFormatVersion != explorer.CurrentReceiptFormatVersion || receipt.CompilerContractVersion != explorer.CurrentCompilerContractVersion) { + return explorerConflict("receipt", "RECEIPT_RECOMPILE_REQUIRED", "the compilation receipt is from an unsupported compiler contract", nil) + } + if nativeReceiptContract { + if err := receipt.Validate(); err != nil { + return explorerConflict("receipt", "RECEIPT_RECOMPILE_REQUIRED", "the compilation receipt failed integrity validation and must be recompiled", nil) + } + } + return nil +} + +func lookupV2Receipt(ctx context.Context, explorers *explorer.Service, capabilities ExplorerV2LifecycleConfig, project, explorerID, receiptID string) (*explorer.CompilationReceipt, error) { + if capabilities.ReceiptLookup != nil { + return capabilities.ReceiptLookup(ctx, project, explorerID, receiptID) + } + if explorers == nil { + return nil, explorer.ErrNotFound + } + return explorers.CompilationReceiptForExplorer(ctx, project, explorerID, receiptID) +} + +func receiptRouteError(stage string, err error) error { + if errors.Is(err, explorer.ErrNotFound) { + return &explorer.AuthoringError{Status: http.StatusNotFound, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: "RECEIPT_NOT_FOUND", Message: "compilation receipt was not found"}} + } + if errors.Is(err, explorer.ErrReceiptRecompileRequired) { + return explorerConflict(stage, "RECEIPT_RECOMPILE_REQUIRED", "the compilation receipt is from an unsupported compiler contract", nil) + } + return explorerUnavailable(stage, "RECEIPT_STORE_UNAVAILABLE", "the compilation receipt store is unavailable") +} + +func applyAuthorizedScope(bindings *recipe.RuntimeBindings, authorized AuthorizedCapability, includeAuthResourcePath bool) { + if bindings == nil { + return + } + bindings.AuthResourcePaths = append([]string(nil), authorized.Scope.AuthResourcePaths...) + bindings.AuthScopeMode = authorized.Scope.Mode + bindings.IncludeAuthResourcePath = includeAuthResourcePath +} + +func authoringV2Bundle(project, explorerID string, document authoringv2.Document, catalog authoringv2.CatalogSnapshot) (explorer.ExplorerAuthoringBundleV1, error) { + occurrences, err := document.Occurrences(catalog) + if err != nil { + return explorer.ExplorerAuthoringBundleV1{}, err + } + v1 := explorer.ExplorerBuilderDocumentV1{ + Kind: explorer.ExplorerBuilderV1Kind, + Output: explorer.ExplorerOutputIdentityV1{ID: document.Output.ID, Title: document.Output.Title}, + BaseNodeID: document.RootNodeID, RowNodeID: occurrences[len(occurrences)-1].NodeID, + Presentation: map[string]explorer.ExplorerPresentationBindingV1{}, + } + for _, step := range document.RouteSteps { + v1.RouteEdgeIDs = append(v1.RouteEdgeIDs, step.EdgeID) + } + for i, occurrence := range occurrences { + v1.RouteOccurrences = append(v1.RouteOccurrences, explorer.ExplorerRouteOccurrenceV1{ID: occurrence.ID, Index: i, NodeID: occurrence.NodeID, IncomingEdgeID: occurrence.IncomingEdgeID}) + } + seenCandidates := map[string]bool{} + for _, selection := range document.Selections { + if !seenCandidates[selection.CandidateID] { + v1.CandidateIDs = append(v1.CandidateIDs, selection.CandidateID) + seenCandidates[selection.CandidateID] = true + } + occurrenceID := selection.OccurrenceID + if occurrenceID == "" { + occurrenceID = occurrences[len(occurrences)-1].ID + } + v1.CandidateOccurrences = append(v1.CandidateOccurrences, explorer.ExplorerCandidateOccurrenceV1{CandidateID: selection.CandidateID, OccurrenceID: occurrenceID, ProjectionMode: selection.ProjectionMode}) + } + for key, presentation := range document.Presentation { + v1.Presentation[key] = explorer.ExplorerPresentationBindingV1{Label: presentation.Label, Visible: presentation.Visible, Order: presentation.Order} + } + return explorer.ExplorerAuthoringBundleV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, Project: projectid.Canonical(project), ExplorerID: explorerID, Title: document.Output.Title, Documents: []explorer.ExplorerBuilderDocumentV1{v1}, Tabs: []explorer.ExplorerTabV1{}}, nil +} + +func migrateV1DocumentToCapability(input explorer.ExplorerBuilderDocumentV1, snapshot capability.Snapshot, wire authoringv2.CatalogSnapshot) (authoringv2.Document, error) { + nodeIDs := map[string]string{} + for _, node := range snapshot.Nodes { + nodeIDs[node.ID] = node.ID + nodeIDs[explorer.OpaqueID("n_", node.ResourceType)] = node.ID + } + edgeIDs := map[string]string{} + for _, edge := range snapshot.Edges { + edgeIDs[edge.ID] = edge.ID + edgeIDs[explorer.OpaqueID("e_", edge.SourceResourceType+"\x00"+edge.Label+"\x00"+edge.TargetResourceType)] = edge.ID + } + candidateIDs := map[string]string{} + for _, candidate := range snapshot.Candidates { + candidateIDs[candidate.ID] = candidate.ID + candidateIDs[explorer.OpaqueID("s_", candidate.ResourceType+"\x00"+candidate.FieldPath)] = candidate.ID + } + root := nodeIDs[input.BaseNodeID] + if root == "" { + return authoringv2.Document{}, fmt.Errorf("stored root node is not present in the current capability snapshot") + } + title := input.Output.Title + if strings.TrimSpace(title) == "" { + title = input.Output.ID + } + document := authoringv2.Document{APIVersion: authoringv2.APIVersion, Kind: authoringv2.Kind, Output: authoringv2.Output{ID: input.Output.ID, Title: title}, RootNodeID: root, RouteSteps: []authoringv2.RouteStep{}, Selections: []authoringv2.Selection{}, Presentation: map[string]authoringv2.Presentation{}} + for i, oldEdgeID := range input.RouteEdgeIDs { + edgeID := edgeIDs[oldEdgeID] + if edgeID == "" { + return authoringv2.Document{}, fmt.Errorf("stored route edge is not present in the current capability snapshot") + } + occurrenceID := "" + occurrenceIndex := i + if len(input.RouteOccurrences) == len(input.RouteEdgeIDs)+1 { + occurrenceIndex++ + } + if occurrenceIndex < len(input.RouteOccurrences) { + occurrenceID = input.RouteOccurrences[occurrenceIndex].ID + } + document.RouteSteps = append(document.RouteSteps, authoringv2.RouteStep{EdgeID: edgeID, OccurrenceID: occurrenceID}) + } + candidates := map[string]authoringv2.CatalogCandidate{} + for _, candidate := range wire.Candidates { + candidates[candidate.ID] = candidate + } + for _, reference := range input.CandidateOccurrences { + candidateID := candidateIDs[reference.CandidateID] + if candidateID == "" { + continue + } + mode := reference.ProjectionMode + if mode == "" || !containsString(candidates[candidateID].ProjectionModes, mode) { + mode = candidates[candidateID].DefaultProjectionMode + } + document.Selections = append(document.Selections, authoringv2.Selection{CandidateID: candidateID, OccurrenceID: reference.OccurrenceID, ProjectionMode: mode}) + } + if err := (authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, Document: &document, Catalog: wire}).Validate(); err != nil { + return authoringv2.Document{}, err + } + return document, nil +} diff --git a/internal/server/explorer_builder_lifecycle.go b/internal/server/explorer_builder_lifecycle.go new file mode 100644 index 00000000..64f4f7c2 --- /dev/null +++ b/internal/server/explorer_builder_lifecycle.go @@ -0,0 +1,167 @@ +package server + +import ( + "context" + "errors" + "fmt" + "net/http" + "strings" + + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/projectid" + "github.com/gofiber/fiber/v3" +) + +// RegisterExplorerLifecycleRoutes exposes only collection summaries, creation, +// and the active runtime projection. All browser editing uses authoring/v2. +func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, explorers *explorer.Service, capabilities ExplorerV2LifecycleConfig) { + if app == nil || authorizer == nil || authorizeRead == nil || explorers == nil { + return + } + app.Get("/api/v1/projects/:project/explorers", func(c fiber.Ctx) error { + project := explorerProjectParam(c) + if err := authorizeRead(c.Context(), principalFromFiber(c), project); err != nil { + return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") + } + values, err := explorers.List(c.Context(), project) + if err != nil { + return explorerV2Error(c, 500, "EXPLORER_READ_FAILED", err.Error()) + } + summaries := make([]explorer.ExplorerSummaryV1, 0, len(values)) + for _, value := range values { + summaries = append(summaries, explorer.ExplorerSummaryV1{Project: project, ExplorerID: value.ExplorerID, Title: value.Title, Management: value.ManagementMode, ActiveRevisionID: value.ActiveRevisionID, UpdatedAt: value.UpdatedAt}) + } + return c.JSON(summaries) + }) + + app.Get("/api/v1/projects/:project/explorers/:explorerId", func(c fiber.Ctx) error { + project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) + if err := authorizeRead(c.Context(), principalFromFiber(c), project); err != nil { + return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") + } + state, err := loadExplorerRuntimeState(c.Context(), explorers, project, id) + if errors.Is(err, explorer.ErrNotFound) { + return explorerV2Error(c, 404, "EXPLORER_NOT_FOUND", "Explorer not found") + } + if err != nil { + return explorerV2Error(c, 500, "EXPLORER_READ_FAILED", err.Error()) + } + return c.JSON(state) + }) + + app.Post("/api/v1/projects/:project/explorers", func(c fiber.Ctx) error { + project := explorerProjectParam(c) + if err := authorizeExplorerWrite(c, authorizer, project); err != nil { + return err + } + var request struct { + Name string `json:"name"` + Title string `json:"title,omitempty"` + } + if err := decodeStrict(c.Body(), &request); err != nil || strings.TrimSpace(request.Name) == "" { + return explorerV2Error(c, 400, "MALFORMED_REQUEST", "name is required") + } + id := explorer.StableExplorerID(request.Name) + if id == "default" { + return explorerV2Error(c, 409, "EXPLORER_EXISTS", "the repository default already exists") + } + title := strings.TrimSpace(request.Title) + if title == "" { + title = strings.TrimSpace(request.Name) + } + value, err := explorers.CreateEmptyInteractive(c.Context(), project, id, title, subjectFromFiber(c)) + if errors.Is(err, explorer.ErrDraftConflict) { + return explorerV2Error(c, 409, "EXPLORER_EXISTS", "an Explorer with this name already exists") + } + if err != nil { + return explorerV2Error(c, 422, "INVALID_EXPLORER", err.Error()) + } + return c.Status(http.StatusCreated).JSON(explorer.ExplorerSummaryV1{Project: project, ExplorerID: value.ExplorerID, Title: value.Title, Management: value.ManagementMode, UpdatedAt: value.UpdatedAt}) + }) +} + +// loadExplorerRuntimeState reads the Explorer identity and its immutable active +// revision directly. The selected runtime endpoint must not pass through the +// retired ExplorerConfigV2 reconciliation state: the revision is the sole +// source of published configuration, materializations, and diagnostics. +func loadExplorerRuntimeState(ctx context.Context, service *explorer.Service, project, id string) (explorer.ExplorerStateV1, error) { + project = projectid.Canonical(project) + id = strings.TrimSpace(id) + owner, err := service.Get(ctx, project, id) + if errors.Is(err, explorer.ErrNotFound) && id == "default" { + // Repository bootstrap can briefly expose its repository record before + // the Explorer identity is created. Preserve the read contract for that + // window without manufacturing editable authoring state. + repository, repositoryErr := service.RepositoryConfig(ctx, project) + if repositoryErr != nil { + return explorer.ExplorerStateV1{}, err + } + owner = &explorer.Explorer{ + Project: projectid.Legacy(project), + ExplorerID: "default", + Title: configV2Title(repository.Config), + ManagementMode: explorer.ManagementRepository, + ActiveRevisionID: repository.ActiveRevisionID, + Publication: repository.Publication, + UpdatedAt: repository.UpdatedAt, + } + err = nil + } + if err != nil { + return explorer.ExplorerStateV1{}, err + } + if owner == nil { + return explorer.ExplorerStateV1{}, fmt.Errorf("Explorer %s/%s resolved to an empty identity", project, id) + } + + state := explorerStateV1FromIdentity(owner) + if owner.ActiveRevisionID == "" { + return state, nil + } + revision, err := service.Revision(ctx, owner.ActiveRevisionID) + if err != nil { + return explorer.ExplorerStateV1{}, fmt.Errorf("load active Explorer revision %q: %w", owner.ActiveRevisionID, err) + } + state.Active.RevisionID = revision.ID + state.Active.IntentDigest = revision.IntentDigest + state.Active.Status = string(revision.Status) + state.Generated.RecipeDigest = revision.RecipeDigest + state.Generated.ResolvedSchemaDigest = revision.ResolvedSchemaDigest + state.Generated.SourceGeneration = revision.SourceGeneration + state.Generated.EmittedColumns = append([]explorer.EmittedColumn(nil), revision.EmittedColumns...) + state.Generated.Materializations, state.Generated.Dataset = explorer.WithDataframeSelectors(revision.Recipe, revision.Materializations, revision.Dataset) + state.Generated.Publication = revision.Publication + state.Generated.Publication.State = string(revision.Status) + state.Generated.Publication.RevisionID = revision.ID + state.Generated.Diagnostics = append([]explorer.Diagnostic(nil), revision.Diagnostics...) + state.Runtime = runtimeV1FromPublishedRevision(revision) + return state, nil +} + +func explorerStateV1FromIdentity(owner *explorer.Explorer) explorer.ExplorerStateV1 { + project := projectid.Canonical(owner.Project) + return explorer.ExplorerStateV1{ + APIVersion: explorer.ExplorerStateV1APIVersion, + Kind: explorer.ExplorerStateV1Kind, + Project: project, + ExplorerID: owner.ExplorerID, + Title: owner.Title, + Management: owner.ManagementMode, + Draft: explorer.ExplorerStateV1Draft{}, + Active: explorer.ExplorerStateV1Active{}, + Generated: explorer.ExplorerStateV1Generated{ + RecipeDigest: owner.RecipeDigest, + ResolvedSchemaDigest: owner.ResolvedSchemaDigest, + SourceGeneration: owner.SourceGeneration, + EmittedColumns: append([]explorer.EmittedColumn(nil), owner.EmittedColumns...), + Materializations: append([]explorer.Materialization(nil), owner.Materializations...), + Dataset: owner.Dataset, + Publication: owner.Publication, + Diagnostics: append([]explorer.Diagnostic(nil), owner.Diagnostics...), + }, + ActiveURL: explorerURL(project, owner.ExplorerID), + UpdatedBy: owner.UpdatedBy, + UpdatedAt: owner.UpdatedAt, + } +} diff --git a/internal/server/explorer_builder_routes_test.go b/internal/server/explorer_builder_routes_test.go new file mode 100644 index 00000000..89cfe0b0 --- /dev/null +++ b/internal/server/explorer_builder_routes_test.go @@ -0,0 +1,429 @@ +package server + +import ( + "context" + "encoding/json" + "errors" + "net/http" + "strings" + "testing" + + graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/dataframe/publication" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataset" + "github.com/calypr/loom/internal/explorer" + "github.com/gofiber/fiber/v3" +) + +func publishOnlyAuthoringApp(t *testing.T, store *explorer.MemoryStore, snapshot explorer.CatalogSnapshot, preview ExplorerV2Previewer, materialize ExplorerV2Materializer) (*fiber.App, *explorer.Service) { + t.Helper() + service, err := explorer.NewService(store) + if err != nil { + t.Fatal(err) + } + compiler := func(ctx context.Context, request ExplorerAuthoringV1CompileRequest) (ExplorerAuthoringV1CompileResult, error) { + return ResolveAuthoringBundle(ctx, nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, request) + } + app := fiber.New() + RegisterExplorerAuthoringV1Routes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{ + AuthoringCompile: compiler, + Catalog: func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, + Preview: preview, Materialize: materialize, + ValidateReleaseGeneration: func(context.Context, string, string) error { return nil }, + ActivateRelease: func(context.Context, string, string, []dataset.DataframeSelector) error { return nil }, + }) + return app, service +} + +func TestBuilderReadReturnsCombinedEmptyModel(t *testing.T) { + store := explorer.NewMemoryStore() + if _, err := store.CreateInteractive(context.Background(), explorer.Explorer{Project: "project-a", ExplorerID: "custom", Title: "Custom", ManagementMode: explorer.ManagementInteractive}); err != nil { + t.Fatal(err) + } + app, _ := publishOnlyAuthoringApp(t, store, authoringTestSnapshot(t), nil, nil) + response := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v1/builder", "") + if response.StatusCode != http.StatusOK { + t.Fatalf("builder=%d %s", response.StatusCode, response.Body) + } + var state explorer.ExplorerBuilderStateV1 + decodeBody(t, response.Body, &state) + if state.Kind != explorer.ExplorerBuilderStateV1Kind || state.Bundle.ExplorerID != "custom" || len(state.Bundle.AuthoringDocuments()) != 0 || len(state.Catalog.Nodes) == 0 || state.Catalog.SnapshotToken == "" || len(state.Bindings) != 0 { + t.Fatalf("unexpected empty Builder state: %#v", state) + } + for _, removed := range []string{"draftVersion", "draftDigest", "receiptId"} { + if strings.Contains(response.Body, removed) { + t.Fatalf("Builder response leaked removed field %q: %s", removed, response.Body) + } + } + for _, route := range []struct{ method, path string }{ + {http.MethodPut, "/api/v1/projects/project-a/explorers/custom/authoring/v1/draft"}, + {http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v1/bundle/draft"}, + {http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v1/catalog"}, + {http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/compile"}, + } { + response := requestJSON(t, app, route.method, route.path, `{}`) + if response.StatusCode != http.StatusNotFound { + t.Fatalf("removed authoring route %s %s returned %d", route.method, route.path, response.StatusCode) + } + } +} + +func TestBuilderReadRejectsUnmigratedLegacyAuthoring(t *testing.T) { + ctx := context.Background() + store := explorer.NewMemoryStore() + owner, err := store.CreateInteractive(ctx, explorer.Explorer{Project: "project-a", ExplorerID: "default", Title: "Biospecimens", ManagementMode: explorer.ManagementInteractive}) + if err != nil { + t.Fatal(err) + } + canonicalNodeID := explorer.OpaqueID("n_", "Specimen") + legacyNodeID := explorer.OpaqueID("n_", "specimen") + candidateID := explorer.OpaqueID("s_", "Specimen\x00id") + catalog := explorer.Catalog{ + Nodes: []explorer.CatalogNode{{ID: canonicalNodeID, ResourceType: "Specimen"}}, + Selections: map[string]explorer.CatalogSelection{ + candidateID: {ID: candidateID, NodeID: canonicalNodeID, FieldRef: "Specimen.id", Select: "id", LogicalType: "scalar", Filterable: true}, + }, + } + snapshot, err := explorer.NewCatalogSnapshot("project-a", "generation-a", "scope-a", catalog, true, false, nil) + if err != nil { + t.Fatal(err) + } + broken := authoringTestBundle(explorer.ExplorerBuilderDocumentV1{ + Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "specimen", Title: "Biospecimens"}, + BaseNodeID: legacyNodeID, RowNodeID: legacyNodeID, + Presentation: map[string]explorer.ExplorerPresentationBindingV1{ + explorer.OpaqueID("em_", "specimen\x00base\x00legacy-candidate"): {Label: "stale"}, + }, + }) + broken.Project, broken.ExplorerID, broken.Title = "project-a", "default", "Biospecimens" + brokenJSON, err := broken.CanonicalJSON() + if err != nil { + t.Fatal(err) + } + legacyConfig := json.RawMessage(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Biospecimens","management":"repository"},"recipe":{"recipeSchemaVersion":1,"name":"legacy","translationVersion":"v1","outputs":[{"name":"specimen","rootResourceType":"Specimen","rowGrain":"specimen","fields":[{"name":"id","fieldRef":"Specimen.id","expr":{"select":"root.id"}}]}]},"views":[{"id":"specimen","title":"Biospecimens","output":"specimen","table":{"columns":[{"column":"id","label":"Identifier","visible":true}]}}]}`) + revision := explorer.Revision{ + ID: "legacy-specimen", Project: owner.Project, ExplorerID: owner.ExplorerID, + AuthoringBundle: brokenJSON, SourceGeneration: snapshot.Generation, Status: explorer.RevisionReady, + Migration: &explorer.MigrationMetadata{Kind: "ExplorerAuthoringMigration", Source: "frontend-mapping", OriginalConfig: legacyConfig}, + } + if _, err := store.InsertRevision(ctx, revision); err != nil { + t.Fatal(err) + } + if err := store.ActivateInteractive(ctx, owner.Project, owner.ExplorerID, revision.ID); err != nil { + t.Fatal(err) + } + + app, _ := publishOnlyAuthoringApp(t, store, snapshot, nil, nil) + response := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/default/authoring/v1/builder", "") + if response.StatusCode != http.StatusUnprocessableEntity || !strings.Contains(response.Body, "STALE_BASE_NODE") { + t.Fatalf("unmigrated authoring was accepted: status=%d body=%s", response.StatusCode, response.Body) + } +} + +func TestBuilderReadReturnsCanonicalCandidateOccurrences(t *testing.T) { + ctx := context.Background() + store := explorer.NewMemoryStore() + owner, err := store.CreateInteractive(ctx, explorer.Explorer{Project: "project-a", ExplorerID: "custom", Title: "Custom", ManagementMode: explorer.ManagementInteractive}) + if err != nil { + t.Fatal(err) + } + snapshot := authoringTestSnapshot(t) + legacy := authoringTestBundleWithoutCandidateOccurrences(explorer.ExplorerBuilderDocumentV1{ + Kind: explorer.ExplorerBuilderV1Kind, + Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, + BaseNodeID: "n_base", + RowNodeID: "n_base", + CandidateIDs: []string{ + "s_base", + }, + }) + legacy.IntentDigest = "sha256:legacy-before-candidate-occurrences" + raw, err := json.Marshal(legacy) + if err != nil { + t.Fatal(err) + } + if _, err := store.InsertRevision(ctx, explorer.Revision{ID: "legacy", Project: owner.Project, ExplorerID: owner.ExplorerID, AuthoringBundle: raw, SourceGeneration: snapshot.Generation, Status: explorer.RevisionReady}); err != nil { + t.Fatal(err) + } + if err := store.ActivateInteractive(ctx, owner.Project, owner.ExplorerID, "legacy"); err != nil { + t.Fatal(err) + } + app, _ := publishOnlyAuthoringApp(t, store, snapshot, nil, nil) + response := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v1/builder", "") + if response.StatusCode != http.StatusOK { + t.Fatalf("builder=%d %s", response.StatusCode, response.Body) + } + var state explorer.ExplorerBuilderStateV1 + decodeBody(t, response.Body, &state) + documents := state.Bundle.AuthoringDocuments() + if len(documents) != 1 || len(documents[0].CandidateOccurrences) != 1 || documents[0].CandidateOccurrences[0].CandidateID != "s_base" || documents[0].CandidateOccurrences[0].OccurrenceID != "base" { + t.Fatalf("Builder did not return canonical candidate occurrences: %#v", state.Bundle) + } +} + +func TestExplorerCollectionIsSummaryOnlyAndLegacyMutationsAreAbsent(t *testing.T) { + store := explorer.NewMemoryStore() + if _, err := store.CreateInteractive(context.Background(), explorer.Explorer{Project: "project-a", ExplorerID: "custom", Title: "Custom", ManagementMode: explorer.ManagementInteractive, DraftConfig: json.RawMessage(`{"legacy":true}`), DraftVersion: 7, DraftDigest: "draft"}); err != nil { + t.Fatal(err) + } + service, err := explorer.NewService(store) + if err != nil { + t.Fatal(err) + } + app := fiber.New() + RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{}) + list := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers", "") + if list.StatusCode != http.StatusOK || strings.Contains(list.Body, "draft") || strings.Contains(list.Body, "bundle") || strings.Contains(list.Body, "runtime") { + t.Fatalf("collection is not summary-only: %d %s", list.StatusCode, list.Body) + } + for _, route := range []struct{ method, path string }{ + {http.MethodPut, "/api/v1/projects/project-a/explorers/custom/draft"}, + {http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/compile"}, + {http.MethodPost, "/api/v1/projects/project-a/explorers/custom/preview"}, + {http.MethodPost, "/api/v1/projects/project-a/explorers/custom/publish"}, + {http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/catalog"}, + } { + response := requestJSON(t, app, route.method, route.path, `{}`) + if response.StatusCode != http.StatusNotFound { + t.Fatalf("legacy route %s %s remains registered: %d %s", route.method, route.path, response.StatusCode, response.Body) + } + } +} + +func TestSelectedRuntimeReadProjectsActiveRevisionDirectly(t *testing.T) { + ctx := context.Background() + store := explorer.NewMemoryStore() + owner, err := store.CreateInteractive(ctx, explorer.Explorer{Project: "project-a", ExplorerID: "custom", Title: "Custom", ManagementMode: explorer.ManagementInteractive}) + if err != nil { + t.Fatal(err) + } + selector := dataset.DataframeSelector{Recipe: "recipe", TranslationVersion: "authoring-v1", Output: "patient"} + bundle := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "recipe", TranslationVersion: "authoring-v1", Outputs: []recipe.Output{{Name: "patient", RootResourceType: "Patient", RowGrain: "resource", Fields: []recipe.Field{{Name: "c_id", FieldRef: "Patient.id", Expr: recipe.Expression{Select: "root.id"}}}}}} + config, err := json.Marshal(explorer.ConfigV2{ + APIVersion: explorer.ConfigV2APIVersion, + Kind: "ExplorerConfig", + Project: "project-a", + Explorer: explorer.ConfigExplorer{ID: "custom", Title: "Custom", Management: "interactive"}, + Recipe: mustJSON(bundle), + Views: []explorer.ConfigView{{ + ID: "patient", Title: "Patients", Output: "patient", + Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "c_id", Visible: true}}}, + }}, + }) + if err != nil { + t.Fatal(err) + } + revision := explorer.Revision{ + ID: "revision-1", Project: owner.Project, ExplorerID: owner.ExplorerID, Config: config, + Recipe: bundle, RecipeDigest: "recipe-digest", ResolvedSchemaDigest: "schema-digest", SourceGeneration: "generation-a", + Materializations: []explorer.Materialization{{OutputID: "patient", Output: "patient", MaterializationID: "execution-a", Selector: &selector, Columns: []publication.PhysicalColumn{{Name: "patient_c_id", LogicalType: "String"}}}}, + EmittedColumns: []explorer.EmittedColumn{{EmissionID: "em_id", OutputID: "patient", PublicColumn: "c_id", LogicalType: "string"}}, + Dataset: explorer.DatasetMetadata{Generation: "generation-a", Outputs: []explorer.DatasetOutput{{Name: "patient", State: "PUBLISHED", Queryable: true, Selector: &selector, Columns: []publication.PhysicalColumn{{Name: "patient_c_id", LogicalType: "String"}}}}}, + Publication: explorer.PublicationMetadata{State: string(explorer.RevisionReady), Generation: "generation-a"}, Status: explorer.RevisionReady, + } + if _, err := store.InsertRevision(ctx, revision); err != nil { + t.Fatal(err) + } + if err := store.ActivateInteractive(ctx, owner.Project, owner.ExplorerID, revision.ID); err != nil { + t.Fatal(err) + } + + service, err := explorer.NewService(store) + if err != nil { + t.Fatal(err) + } + app := fiber.New() + RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{}) + response := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom", "") + if response.StatusCode != http.StatusOK { + t.Fatalf("runtime read status=%d body=%s", response.StatusCode, response.Body) + } + var state explorer.ExplorerStateV1 + decodeBody(t, response.Body, &state) + if state.Active.RevisionID != revision.ID || state.Runtime == nil || len(state.Runtime.Outputs) != 1 || state.Runtime.Outputs[0].OutputID != "patient" { + t.Fatalf("runtime state=%#v body=%s", state, response.Body) + } + if strings.Contains(response.Body, "draftConfig") || strings.Contains(response.Body, "activeConfig") { + t.Fatalf("runtime response leaked legacy state: %s", response.Body) + } +} + +func TestPreviewUsesIntentAndSnapshotWithoutWrites(t *testing.T) { + ctx := context.Background() + store := explorer.NewMemoryStore() + if _, err := store.CreateInteractive(ctx, explorer.Explorer{Project: "project-a", ExplorerID: "custom", ManagementMode: explorer.ManagementInteractive}); err != nil { + t.Fatal(err) + } + snapshot := authoringTestSnapshot(t) + previewCalls := 0 + app, service := publishOnlyAuthoringApp(t, store, snapshot, func(_ context.Context, _ recipe.Bundle, _ recipe.RuntimeBindings) (map[string][]map[string]any, error) { + previewCalls++ + return map[string][]map[string]any{"patient": {{"id": "p1"}}}, nil + }, nil) + document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"s_base"}} + bundle := authoringTestBundle(document) + resolved, err := ResolveAuthoringBundle(ctx, nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: bundle, SnapshotToken: snapshot.Token}) + if err != nil { + t.Fatal(err) + } + raw, _ := json.Marshal(map[string]any{"bundle": bundle, "snapshotToken": snapshot.Token, "outputId": "patient", "limit": 25}) + response := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/preview", string(raw)) + if response.StatusCode != http.StatusOK || previewCalls != 1 { + t.Fatalf("preview=%d calls=%d %s", response.StatusCode, previewCalls, response.Body) + } + if _, err := service.CompilationReceipt(ctx, resolved.Receipt.ID); !errors.Is(err, explorer.ErrNotFound) { + t.Fatalf("preview persisted receipt: %v", err) + } + if _, err := service.ActiveRevision(ctx, "project-a", "custom"); !errors.Is(err, explorer.ErrNotFound) { + t.Fatalf("preview changed active revision: %v", err) + } +} + +func TestPreviewAndPublishNormalizeLegacyCandidateSelection(t *testing.T) { + ctx := context.Background() + store := explorer.NewMemoryStore() + if _, err := store.CreateInteractive(ctx, explorer.Explorer{Project: "project-a", ExplorerID: "custom", Title: "Custom", ManagementMode: explorer.ManagementInteractive}); err != nil { + t.Fatal(err) + } + snapshot := authoringTestSnapshot(t) + app, _ := publishOnlyAuthoringApp(t, store, snapshot, + func(context.Context, recipe.Bundle, recipe.RuntimeBindings) (map[string][]map[string]any, error) { + return map[string][]map[string]any{"patient": {{"id": "p1"}}}, nil + }, + func(_ context.Context, bundle recipe.Bundle, _ recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { + return graphresolver.RecipeExecution{ID: "execution-a", SourceGeneration: snapshot.Generation, Outputs: []graphresolver.RecipeExecutionOutput{{Name: bundle.Outputs[0].Name, State: "PUBLISHED"}}}, nil + }, + ) + bundle := authoringTestBundleWithoutCandidateOccurrences(explorer.ExplorerBuilderDocumentV1{ + Kind: explorer.ExplorerBuilderV1Kind, + Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, + BaseNodeID: "n_base", + RowNodeID: "n_base", + CandidateIDs: []string{ + "s_base", + }, + }) + raw, err := json.Marshal(map[string]any{"bundle": bundle, "snapshotToken": snapshot.Token, "outputId": "patient", "limit": 25}) + if err != nil { + t.Fatal(err) + } + preview := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/preview", string(raw)) + if preview.StatusCode != http.StatusOK { + t.Fatalf("preview=%d %s", preview.StatusCode, preview.Body) + } + publishRaw, err := json.Marshal(map[string]any{"bundle": bundle, "snapshotToken": snapshot.Token}) + if err != nil { + t.Fatal(err) + } + publish := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/publish", string(publishRaw)) + if publish.StatusCode != http.StatusOK { + t.Fatalf("publish=%d %s", publish.StatusCode, publish.Body) + } +} + +func TestPublishReturnsReloadableResolvedBuilderState(t *testing.T) { + store := explorer.NewMemoryStore() + if _, err := store.CreateInteractive(context.Background(), explorer.Explorer{Project: "project-a", ExplorerID: "custom", Title: "Custom", ManagementMode: explorer.ManagementInteractive}); err != nil { + t.Fatal(err) + } + snapshot := authoringTestSnapshot(t) + materializeCalls := 0 + app, _ := publishOnlyAuthoringApp(t, store, snapshot, nil, func(_ context.Context, bundle recipe.Bundle, _ recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { + materializeCalls++ + return graphresolver.RecipeExecution{ID: "execution-a", SourceGeneration: snapshot.Generation, Outputs: []graphresolver.RecipeExecutionOutput{{Name: bundle.Outputs[0].Name, State: "PUBLISHED"}}}, nil + }) + document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient", Title: "Patients"}, BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"s_base"}} + bundle := authoringTestBundle(document) + raw, _ := json.Marshal(map[string]any{"bundle": bundle, "snapshotToken": snapshot.Token}) + published := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/publish", string(raw)) + if published.StatusCode != http.StatusOK || materializeCalls != 1 { + t.Fatalf("publish=%d calls=%d %s", published.StatusCode, materializeCalls, published.Body) + } + var first explorer.ExplorerBuilderStateV1 + decodeBody(t, published.Body, &first) + if first.Active.RevisionID == "" || len(first.Bindings) != 1 || first.Bindings[0].BaseResourceType != "Patient" || first.Bindings[0].RouteKind != "ZERO_HOP" { + t.Fatalf("published Builder state=%#v", first) + } + reloaded := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v1/builder", "") + if reloaded.StatusCode != http.StatusOK { + t.Fatalf("reload=%d %s", reloaded.StatusCode, reloaded.Body) + } + var second explorer.ExplorerBuilderStateV1 + decodeBody(t, reloaded.Body, &second) + if second.Active.RevisionID != first.Active.RevisionID || len(second.Bindings) != 1 || second.Bindings[0].CandidateEmissions[0].EmissionID != first.Bindings[0].CandidateEmissions[0].EmissionID { + t.Fatalf("reload did not preserve authoritative bindings: first=%#v second=%#v", first, second) + } +} + +func TestFailedPublishPreservesActiveRevision(t *testing.T) { + ctx := context.Background() + store := explorer.NewMemoryStore() + if _, err := store.CreateInteractive(ctx, explorer.Explorer{Project: "project-a", ExplorerID: "custom", ManagementMode: explorer.ManagementInteractive}); err != nil { + t.Fatal(err) + } + if _, err := store.InsertRevision(ctx, explorer.Revision{ID: "prior", Project: "project-a", ExplorerID: "custom", Status: explorer.RevisionReady}); err != nil { + t.Fatal(err) + } + if err := store.ActivateInteractive(ctx, "project-a", "custom", "prior"); err != nil { + t.Fatal(err) + } + snapshot := authoringTestSnapshot(t) + app, service := publishOnlyAuthoringApp(t, store, snapshot, nil, func(context.Context, recipe.Bundle, recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { + return graphresolver.RecipeExecution{}, errors.New("offline") + }) + bundle := authoringTestBundle(explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base"}) + raw, _ := json.Marshal(map[string]any{"bundle": bundle, "snapshotToken": snapshot.Token}) + response := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/publish", string(raw)) + if response.StatusCode != http.StatusServiceUnavailable || !strings.Contains(response.Body, "MATERIALIZATION_FAILED") { + t.Fatalf("publish=%d %s", response.StatusCode, response.Body) + } + active, err := service.ActiveRevision(ctx, "project-a", "custom") + if err != nil || active.ID != "prior" { + t.Fatalf("active revision changed: %#v err=%v", active, err) + } +} + +func TestPostBuilderReconcilesIntentWithoutWrites(t *testing.T) { + ctx := context.Background() + store := explorer.NewMemoryStore() + if _, err := store.CreateInteractive(ctx, explorer.Explorer{Project: "project-a", ExplorerID: "custom", Title: "Custom", ManagementMode: explorer.ManagementInteractive}); err != nil { + t.Fatal(err) + } + snapshot := authoringTestSnapshot(t) + app, service := publishOnlyAuthoringApp(t, store, snapshot, nil, nil) + document := explorer.ExplorerBuilderDocumentV1{ + Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient", Title: "Patients"}, + BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"s_base"}, + CandidateOccurrences: []explorer.ExplorerCandidateOccurrenceV1{{CandidateID: "s_base", OccurrenceID: "base"}}, + } + bundle := authoringTestBundle(document) + raw, _ := json.Marshal(map[string]any{"bundle": bundle, "snapshotToken": snapshot.Token}) + response := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/builder", string(raw)) + if response.StatusCode != http.StatusOK { + t.Fatalf("builder reconcile=%d %s", response.StatusCode, response.Body) + } + var state explorer.ExplorerBuilderStateV1 + decodeBody(t, response.Body, &state) + if len(state.Bindings) != 1 || len(state.Bindings[0].CandidateEmissions) != 1 || state.Bindings[0].CandidateEmissions[0].PublicColumn == "" { + t.Fatalf("resolved builder binding=%#v", state.Bindings) + } + if _, err := service.ActiveRevision(ctx, "project-a", "custom"); !errors.Is(err, explorer.ErrNotFound) { + t.Fatalf("POST Builder changed active revision: %v", err) + } +} + +func TestTableIdentityIsServerAllocatedAndIdempotent(t *testing.T) { + store := explorer.NewMemoryStore() + if _, err := store.CreateInteractive(context.Background(), explorer.Explorer{Project: "project-a", ExplorerID: "custom", Title: "Custom", ManagementMode: explorer.ManagementInteractive}); err != nil { + t.Fatal(err) + } + app, _ := publishOnlyAuthoringApp(t, store, authoringTestSnapshot(t), nil, nil) + body := `{"title":"Biospecimens","requestId":"new-table-1","occupiedOutputIds":["biospecimens"],"occupiedTabIds":["biospecimens"]}` + response := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/table-identity", body) + repeated := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/table-identity", body) + if response.StatusCode != http.StatusOK || response.Body != repeated.Body || !strings.Contains(response.Body, `"kind":"ExplorerTableIdentity"`) || strings.Contains(response.Body, `"id":"biospecimens`) { + t.Fatalf("table identity=%d %s", response.StatusCode, response.Body) + } +} diff --git a/internal/server/explorer_capability.go b/internal/server/explorer_capability.go new file mode 100644 index 00000000..850aee58 --- /dev/null +++ b/internal/server/explorer_capability.go @@ -0,0 +1,555 @@ +package server + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "sort" + "strings" + + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/catalog" + compilerprobe "github.com/calypr/loom/internal/dataframe/compiler/capability" + "github.com/calypr/loom/internal/dataframe/spec" + "github.com/calypr/loom/internal/dataset" + "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/explorer/authoringv2" + "github.com/calypr/loom/internal/explorer/capability" + "github.com/calypr/loom/internal/explorer/capabilitystore" + "github.com/calypr/loom/internal/projectid" + "golang.org/x/sync/singleflight" +) + +const ( + explorerCapabilityCompilerVersion = "loom-dataframe-compiler-v2" + explorerCapabilityProtocolVersion = "loom.calypr.org/explorer-authoring/v2" + explorerTraversalPolicyVersion = "finite-unbounded-v1" + explorerProjectionPolicyVersion = "compiler-probed-v1" +) + +// explorerCapabilityResolver is the one construction boundary for Builder +// capabilities. Catalog observations are evidence only; every public item is +// intersected with the real dataframe compiler before the immutable snapshot +// is persisted or returned. +type explorerCapabilityResolver struct { + evidence catalog.CapabilityEvidenceReader + scopes *authscope.ScopeResolver + manifests dataset.ActiveResolver + snapshots capabilitystore.Repository + builds singleflight.Group +} + +type ExplorerCapabilityReader func(context.Context, string, string, string) (capability.Snapshot, error) +type ExplorerCapabilityTokenReader func(context.Context, string, string) (capability.Snapshot, error) + +// AuthorizedCapability is the capability contract handed to compilation and +// execution. The scope is part of the contract: callers must not derive it +// again from a token or accidentally turn a restricted-empty scope into an +// unrestricted one. Both values are copied before they cross this boundary. +type AuthorizedCapability struct { + Snapshot capability.Snapshot + Scope authscope.ReadScope +} + +// Clone returns an independent authorized capability. Snapshot.Clone also +// copies nested diagnostic values through the capability package's immutable +// accessor, while ReadScope.Clone protects the authorization path slice. +func (a AuthorizedCapability) Clone() AuthorizedCapability { + return AuthorizedCapability{Snapshot: a.Snapshot.Clone(), Scope: a.Scope.Clone()} +} + +// ExplorerAuthorizedCapabilityCompilationReader accepts an opaque snapshot +// token for a new compile. Implementations must require that token to belong +// to the currently active dataset generation. +type ExplorerAuthorizedCapabilityCompilationReader func(context.Context, string, string) (AuthorizedCapability, error) + +// ExplorerAuthorizedCapabilityExecutionReader loads an exact retained token +// for preview/materialization. Implementations may accept inactive generations +// while retained, but must re-authorize the caller against the token's exact +// generation and scope digest. +type ExplorerAuthorizedCapabilityExecutionReader func(context.Context, string, string) (AuthorizedCapability, error) + +// ExplorerCapabilityCompilationResolver documents the compile authorization +// seam for callers that want a resolver object rather than a function field. +type ExplorerCapabilityCompilationResolver interface { + ResolveForCompilation(context.Context, string, string) (AuthorizedCapability, error) +} + +// ExplorerCapabilityExecutionResolver documents the execution authorization +// seam for callers that want a resolver object rather than a function field. +type ExplorerCapabilityExecutionResolver interface { + ResolveForExecution(context.Context, string, string) (AuthorizedCapability, error) +} + +func newExplorerCapabilityResolver(evidence catalog.CapabilityEvidenceReader, scopes *authscope.ScopeResolver, manifests dataset.ActiveResolver, snapshots capabilitystore.Repository) (*explorerCapabilityResolver, error) { + if evidence == nil || manifests == nil || snapshots == nil { + return nil, fmt.Errorf("Explorer capability evidence, manifest resolver, and snapshot repository are required") + } + return &explorerCapabilityResolver{evidence: evidence, scopes: scopes, manifests: manifests, snapshots: snapshots}, nil +} + +func (r *explorerCapabilityResolver) Resolve(ctx context.Context, project, requestedGeneration string) (capability.Snapshot, error) { + project = projectid.Canonical(project) + storageProject := projectid.Legacy(project) + principal, _ := authscope.PrincipalFromContext(ctx) + // Project membership is independent of whether generation-level Fence + // scopes are configured. A nil ScopeResolver means unrestricted dataframe + // reads, not that a principal's explicit project allowlist is ignored. + if err := authscope.AuthorizeProject(principal, project, false); err != nil { + return capability.Snapshot{}, err + } + manifest, err := dataset.ResolveActive(ctx, r.manifests, storageProject) + if err != nil { + return capability.Snapshot{}, fmt.Errorf("resolve capability generation: %w", err) + } + generation := manifest.Dataset.Generation + if requestedGeneration = strings.TrimSpace(requestedGeneration); requestedGeneration != "" && requestedGeneration != generation { + return capability.Snapshot{}, fmt.Errorf("requested generation %q is not the active immutable generation %q", requestedGeneration, generation) + } + scope, err := r.resolveScope(ctx, principal, storageProject, generation) + if err != nil { + return capability.Snapshot{}, err + } + unrestricted := scope.Unrestricted() + evidence, err := catalog.ReadCapabilityEvidence(ctx, r.evidence, catalog.CapabilityEvidenceOptions{ + Project: storageProject, DatasetGeneration: generation, + AuthResourcePaths: append([]string(nil), scope.AuthResourcePaths...), + AuthResourcePathsUnrestricted: &unrestricted, + }) + if err != nil { + return capability.Snapshot{}, fmt.Errorf("read capability evidence: %w", err) + } + if err := requireCompleteCapabilityEvidence(evidence); err != nil { + return capability.Snapshot{}, err + } + identity := capability.SnapshotIdentity{ + Project: project, Generation: generation, + AuthorizationScopeDigest: explorerScopeDigest(scope), + SchemaDigest: manifest.SchemaIdentity.SchemaSHA256, + ResourceInventoryDigest: evidence.ResourceInventory.Digest, + RelationshipDigest: evidence.Relationships.Digest, + FieldDigest: evidence.FieldEnrichment.Digest, + ProtocolVersion: explorerCapabilityProtocolVersion, + CompilerVersion: explorerCapabilityCompilerVersion, + TraversalPolicyVersion: explorerTraversalPolicyVersion, + ProjectionPolicyVersion: explorerProjectionPolicyVersion, + } + key, err := capabilityIdentityKey(identity) + if err != nil { + return capability.Snapshot{}, err + } + value, err, _ := r.builds.Do(key, func() (any, error) { + if existing, getErr := r.snapshots.GetByIdentity(ctx, identity); getErr == nil && existing.Usable() { + return existing.Clone(), nil + } else if getErr != nil && !errors.Is(getErr, capabilitystore.ErrNotFound) { + return nil, getErr + } + observer := capabilityObserverFromEvidence(evidence) + builder := capability.NewBuilder(identity, observer, observer, observer, explorerCapabilityCompiler{scope: compilerprobe.Scope{ + Project: storageProject, DatasetGeneration: generation, + AuthResourcePaths: append([]string(nil), scope.AuthResourcePaths...), AuthScopeMode: scope.Mode, + }}) + builder.Policy = capability.Policy{ + Route: capability.RoutePolicy{Version: explorerTraversalPolicyVersion, MaxHops: 0, AllowsRepeatedEdges: true, AllowsSelfLoops: true}, + Projection: capability.ProjectionPolicy{Version: explorerProjectionPolicyVersion, SuggestionLimit: capability.DefaultSuggestionLimit}, + } + built, buildErr := builder.Build(ctx) + if buildErr != nil { + _, _ = r.snapshots.Put(ctx, built) + return nil, buildErr + } + if !built.Usable() { + _, _ = r.snapshots.Put(ctx, built) + return nil, capability.ErrSnapshotUnavailable + } + stored, putErr := r.snapshots.Put(ctx, built) + if putErr != nil { + return nil, putErr + } + return stored.Clone(), nil + }) + if err != nil { + return capability.Snapshot{}, err + } + return value.(capability.Snapshot).Clone(), nil +} + +// ResolveActiveAuthorized is the scope-preserving form of Resolve. It is used +// by capability/catalog reads that select the active generation directly. The +// legacy Resolve method remains available for adapters that only need the +// public snapshot projection. +func (r *explorerCapabilityResolver) ResolveActiveAuthorized(ctx context.Context, project, requestedGeneration string) (AuthorizedCapability, error) { + snapshot, err := r.Resolve(ctx, project, requestedGeneration) + if err != nil { + return AuthorizedCapability{}, err + } + canonicalProject := projectid.Canonical(project) + principal, _ := authscope.PrincipalFromContext(ctx) + scope, err := r.resolveScope(ctx, principal, projectid.Legacy(canonicalProject), snapshot.Identity.Generation) + if err != nil { + return AuthorizedCapability{}, err + } + if explorerScopeDigest(scope) != snapshot.Identity.AuthorizationScopeDigest { + return AuthorizedCapability{}, capability.ErrStaleSnapshot + } + return AuthorizedCapability{Snapshot: snapshot.Clone(), Scope: scope.Clone()}, nil +} + +// ResolveToken loads an exact retained snapshot. It never substitutes the +// current active generation, and it re-authorizes the caller against the +// snapshot's generation and exact authorization-scope digest. +func (r *explorerCapabilityResolver) ResolveToken(ctx context.Context, project, token string) (capability.Snapshot, error) { + authorized, err := r.ResolveForExecution(ctx, project, token) + if err != nil { + return capability.Snapshot{}, err + } + return authorized.Snapshot.Clone(), nil +} + +// ResolveForExecution loads an exact retained snapshot and its effective +// generation-scoped read authorization. Retention is intentional here: +// preview and other execution paths may use an inactive generation while its +// immutable capability remains available. The caller's current effective +// scope must still match the scope digest captured by the snapshot. +func (r *explorerCapabilityResolver) ResolveForExecution(ctx context.Context, project, token string) (AuthorizedCapability, error) { + project = projectid.Canonical(project) + token = strings.TrimSpace(token) + snapshot, err := r.snapshots.GetByToken(ctx, token) + if err != nil { + return AuthorizedCapability{}, err + } + if snapshot.Identity.Project != project { + return AuthorizedCapability{}, capability.ErrStaleSnapshot + } + principal, _ := authscope.PrincipalFromContext(ctx) + if err := authscope.AuthorizeProject(principal, project, false); err != nil { + return AuthorizedCapability{}, err + } + scope, err := r.resolveScope(ctx, principal, projectid.Legacy(project), snapshot.Identity.Generation) + if err != nil { + return AuthorizedCapability{}, err + } + if explorerScopeDigest(scope) != snapshot.Identity.AuthorizationScopeDigest { + return AuthorizedCapability{}, capability.ErrStaleSnapshot + } + if err := snapshot.ValidateToken(token); err != nil { + return AuthorizedCapability{}, err + } + return AuthorizedCapability{Snapshot: snapshot.Clone(), Scope: scope.Clone()}, nil +} + +// ResolveForCompilation loads an exact token for a new compile. Unlike +// execution, compilation is only valid against the currently active immutable +// dataset generation; a retained inactive token is rejected even when its +// scope is otherwise still authorized. +func (r *explorerCapabilityResolver) ResolveForCompilation(ctx context.Context, project, token string) (AuthorizedCapability, error) { + project = projectid.Canonical(project) + authorized, err := r.ResolveForExecution(ctx, project, token) + if err != nil { + return AuthorizedCapability{}, err + } + manifest, err := dataset.ResolveActive(ctx, r.manifests, projectid.Legacy(project)) + if err != nil { + return AuthorizedCapability{}, fmt.Errorf("resolve current capability generation: %w", err) + } + if authorized.Snapshot.Identity.Generation != manifest.Dataset.Generation { + return AuthorizedCapability{}, capability.ErrStaleSnapshot + } + return authorized.Clone(), nil +} + +func (r *explorerCapabilityResolver) resolveScope(ctx context.Context, principal *authscope.Principal, project, generation string) (authscope.ReadScope, error) { + if r.scopes == nil { + return authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}, nil + } + return r.scopes.ResolveReadScopeForGeneration(ctx, principal, project, generation, nil) +} + +func requireCompleteCapabilityEvidence(value catalog.CapabilityEvidence) error { + checks := []struct { + name string + available bool + complete bool + truncated bool + }{ + {"resource inventory", value.ResourceInventory.Available, value.ResourceInventory.Complete, value.ResourceInventory.Truncated}, + {"relationship evidence", value.Relationships.Available, value.Relationships.Complete, value.Relationships.Truncated}, + {"field enrichment", value.FieldEnrichment.Available, value.FieldEnrichment.Complete, value.FieldEnrichment.Truncated}, + } + for _, check := range checks { + if !check.available || !check.complete || check.truncated { + return fmt.Errorf("%w: %s is unavailable, incomplete, or truncated", capability.ErrSnapshotUnavailable, check.name) + } + } + var documents int64 + for _, item := range value.ResourceInventory.Values { + documents += item.DocumentCount + } + // A staged generation proves the catalog write phase completed, and every + // non-empty FHIR resource necessarily profiles at least its identity fields. + // Therefore a populated inventory with zero enrichment rows is a missing + // artifact, not a legitimate empty catalog (notably for older generations + // created before capability evidence existed). + if documents > 0 && len(value.FieldEnrichment.Values) == 0 { + return fmt.Errorf("%w: field enrichment artifact is empty for a populated generation", capability.ErrSnapshotUnavailable) + } + return nil +} + +func capabilityIdentityKey(identity capability.SnapshotIdentity) (string, error) { + raw, err := json.Marshal(identity) + if err != nil { + return "", err + } + sum := sha256.Sum256(raw) + return hex.EncodeToString(sum[:]), nil +} + +type capabilityEvidenceObserver struct { + resources []capability.ResourceObservation + relationships []capability.RelationshipObservation + fields []capability.FieldObservation +} + +func (o capabilityEvidenceObserver) ListResources(context.Context) ([]capability.ResourceObservation, error) { + return append([]capability.ResourceObservation(nil), o.resources...), nil +} +func (o capabilityEvidenceObserver) ListRelationships(context.Context) ([]capability.RelationshipObservation, error) { + return append([]capability.RelationshipObservation(nil), o.relationships...), nil +} +func (o capabilityEvidenceObserver) ListFields(context.Context) ([]capability.FieldObservation, error) { + out := append([]capability.FieldObservation(nil), o.fields...) + for i := range out { + out[i].SuggestedValues = append([]string(nil), out[i].SuggestedValues...) + } + return out, nil +} + +func capabilityObserverFromEvidence(value catalog.CapabilityEvidence) capabilityEvidenceObserver { + out := capabilityEvidenceObserver{} + for _, item := range value.ResourceInventory.Values { + out.resources = append(out.resources, capability.ResourceObservation{ResourceType: item.ResourceType, Populated: item.DocumentCount > 0, DocumentCount: item.DocumentCount}) + } + relationships := map[string]capability.RelationshipObservation{} + for _, item := range value.Relationships.Values { + key := strings.Join([]string{item.BuilderFromType, item.Label, item.BuilderToType, item.BuilderDirection}, "\x00") + observation := relationships[key] + observation.SourceResourceType = item.BuilderFromType + observation.TargetResourceType = item.BuilderToType + observation.Label = item.Label + observation.StorageDirection = item.BuilderDirection + observation.ObservedEdgeCount += item.EdgeCount + observation.AllowsRepeatedTarget = true + relationships[key] = observation + } + for _, item := range relationships { + out.relationships = append(out.relationships, item) + } + sort.Slice(out.relationships, func(i, j int) bool { + a, b := out.relationships[i], out.relationships[j] + return strings.Join([]string{a.SourceResourceType, a.Label, a.TargetResourceType, a.StorageDirection}, "\x00") < strings.Join([]string{b.SourceResourceType, b.Label, b.TargetResourceType, b.StorageDirection}, "\x00") + }) + type fieldAggregate struct { + observation capability.FieldObservation + values map[string]struct{} + } + fields := map[string]*fieldAggregate{} + for _, item := range value.FieldEnrichment.Values { + key := item.ResourceType + "\x00" + item.Path + aggregate := fields[key] + if aggregate == nil { + aggregate = &fieldAggregate{observation: capability.FieldObservation{ResourceType: item.ResourceType, Path: item.Path, Label: item.Path, LogicalType: item.Kind, Observed: true, Populated: item.DocCount > 0, SuggestionsComplete: true}, values: map[string]struct{}{}} + fields[key] = aggregate + } + aggregate.observation.ObservedDocumentCount += item.DocCount + aggregate.observation.Populated = aggregate.observation.Populated || item.DocCount > 0 + if item.DistinctTruncated { + aggregate.observation.SuggestionsComplete = false + aggregate.observation.SuggestionsTruncated = true + } + for _, suggestion := range item.DistinctValues { + aggregate.values[suggestion] = struct{}{} + } + } + for _, aggregate := range fields { + for suggestion := range aggregate.values { + aggregate.observation.SuggestedValues = append(aggregate.observation.SuggestedValues, suggestion) + } + sort.Strings(aggregate.observation.SuggestedValues) + out.fields = append(out.fields, aggregate.observation) + } + sort.Slice(out.fields, func(i, j int) bool { + return out.fields[i].ResourceType+"\x00"+out.fields[i].Path < out.fields[j].ResourceType+"\x00"+out.fields[j].Path + }) + return out +} + +type explorerCapabilityCompiler struct{ scope compilerprobe.Scope } + +func (c explorerCapabilityCompiler) ProbeNode(ctx context.Context, node capability.Node) (capability.NodeProof, error) { + result, err := compilerprobe.ProbeRoot(ctx, compilerprobe.RootRequest{Scope: c.scope, ResourceType: node.ResourceType}) + if err != nil { + return capability.NodeProof{}, err + } + return capability.NodeProof{Allowed: true, RowRootEligible: result.Root.RowRootEligible, RowGrain: string(result.Root.RowGrain), SupportedOperations: []capability.Operation{capability.OperationSelect}}, nil +} + +func (c explorerCapabilityCompiler) ProbeEdge(ctx context.Context, edge capability.Edge) (capability.EdgeProof, error) { + result, err := compilerprobe.ProbeTraversal(ctx, compilerprobe.TraversalRequest{Scope: c.scope, RootResourceType: edge.SourceResourceType, Traversal: compilerprobe.Traversal{FromResourceType: edge.SourceResourceType, EdgeLabel: edge.Label, ToResourceType: edge.TargetResourceType, MatchMode: spec.TraversalMatchOptional}}) + if err != nil { + return capability.EdgeProof{}, err + } + if result.Traversal == nil || string(result.Traversal.StorageDirection) != strings.ToUpper(edge.StorageDirection) { + return capability.EdgeProof{Reason: "catalog storage direction does not match compiler lowering"}, nil + } + return capability.EdgeProof{Allowed: true}, nil +} + +func (c explorerCapabilityCompiler) ProbeCandidate(ctx context.Context, candidate capability.Candidate) (capability.CandidateProof, error) { + result, err := compilerprobe.ProbeCandidate(ctx, compilerprobe.CandidateRequest{Scope: c.scope, RootResourceType: candidate.ResourceType, ResourceType: candidate.ResourceType, Selector: candidate.FieldPath}) + if err != nil { + return capability.CandidateProof{}, err + } + if result.Candidate == nil { + return capability.CandidateProof{}, fmt.Errorf("compiler returned no candidate proof") + } + proof := capability.CandidateProof{Allowed: true, LogicalType: string(result.Candidate.Primitive), Cardinality: string(result.Candidate.Cardinality), SupportedOperations: []capability.Operation{capability.OperationSelect}} + for _, mode := range result.Candidate.ProjectionModes { + proof.ProjectionModes = append(proof.ProjectionModes, capability.ProjectionMode(strings.ToUpper(string(mode)))) + } + for _, operator := range result.Candidate.FilterOperators { + proof.FilterOperators = append(proof.FilterOperators, capability.FilterOperator(operator)) + } + if len(proof.FilterOperators) > 0 { + proof.SupportedOperations = append(proof.SupportedOperations, capability.OperationFilter) + } + for _, operation := range result.Candidate.ChartOperations { + proof.ChartAggregations = append(proof.ChartAggregations, capability.ChartAggregation(operation)) + } + if len(proof.ChartAggregations) > 0 { + proof.SupportedOperations = append(proof.SupportedOperations, capability.OperationChart, capability.OperationAggregate) + } + return proof, nil +} + +func legacyCatalogSnapshot(snapshot capability.Snapshot) explorer.CatalogSnapshot { + catalogValue := explorer.Catalog{Selections: map[string]explorer.CatalogSelection{}} + for _, node := range snapshot.Nodes { + catalogValue.Nodes = append(catalogValue.Nodes, explorer.CatalogNode{ID: node.ID, ResourceType: node.ResourceType}) + } + for _, edge := range snapshot.Edges { + catalogValue.Edges = append(catalogValue.Edges, explorer.CatalogEdge{ID: edge.ID, FromNodeID: edge.FromNodeID, ToNodeID: edge.ToNodeID, Label: edge.Label}) + } + for _, candidate := range snapshot.Candidates { + catalogValue.Selections[candidate.ID] = explorer.CatalogSelection{ + ID: candidate.ID, NodeID: candidate.NodeID, + FieldRef: explorerFieldRef(candidate.ResourceType, candidate.FieldPath), Select: candidate.FieldPath, + LogicalType: candidate.LogicalType, + Cardinality: candidate.Cardinality, + ProjectionModes: stringProjectionModes(candidate.ProjectionModes), + DefaultProjectionMode: defaultProjectionMode(stringProjectionModes(candidate.ProjectionModes)), + FilterOperators: stringFilterOperators(candidate.FilterOperators), + ChartOperations: stringChartOperations(candidate.ChartAggregations), + Filterable: len(candidate.FilterOperators) > 0, + Chartable: len(candidate.ChartAggregations) > 0, + } + } + diagnostics := make([]explorer.Diagnostic, 0, len(snapshot.Diagnostics)) + for _, diagnostic := range snapshot.Diagnostics { + diagnostics = append(diagnostics, explorer.Diagnostic{Severity: diagnostic.Severity, Code: diagnostic.Code, Message: diagnostic.Message, Retryable: diagnostic.Retryable}) + } + return explorer.CatalogSnapshot{ + Project: snapshot.Identity.Project, Generation: snapshot.Identity.Generation, + AuthorizationScopeDigest: snapshot.Identity.AuthorizationScopeDigest, + ResolvedSchemaDigest: snapshot.Identity.SchemaDigest, + Catalog: catalogValue, Complete: snapshot.Complete, Truncated: snapshot.Truncated, + Diagnostics: diagnostics, Token: snapshot.Token, + } +} + +func authoringV2Catalog(snapshot capability.Snapshot, explorerID string) authoringv2.CatalogSnapshot { + result := authoringv2.CatalogSnapshot{ + APIVersion: authoringv2.APIVersion, Kind: authoringv2.CatalogKind, + Project: snapshot.Identity.Project, ExplorerID: explorerID, + SourceGeneration: snapshot.Identity.Generation, + AuthorizationScopeDigest: snapshot.Identity.AuthorizationScopeDigest, + ResolvedSchemaDigest: snapshot.Identity.SchemaDigest, + SnapshotToken: snapshot.Token, Complete: snapshot.Complete, Truncated: snapshot.Truncated, + Nodes: []authoringv2.CatalogNode{}, Edges: []authoringv2.CatalogEdge{}, Candidates: []authoringv2.CatalogCandidate{}, Diagnostics: []authoringv2.CatalogDiagnostic{}, + RoutePolicy: authoringv2.RoutePolicy{Unbounded: snapshot.Policy.Route.MaxHops == 0, AllowRepeatedEdges: snapshot.Policy.Route.AllowsRepeatedEdges, AllowSelfLoops: snapshot.Policy.Route.AllowsSelfLoops}, + } + if snapshot.Policy.Route.MaxHops > 0 { + maxHops := snapshot.Policy.Route.MaxHops + result.RoutePolicy.MaxHops = &maxHops + } + for _, node := range snapshot.Nodes { + count := node.DocumentCount + result.Nodes = append(result.Nodes, authoringv2.CatalogNode{ + ID: node.ID, ResourceType: node.ResourceType, RowRootEligible: node.RowRootEligible, + RowGrain: node.RowGrain, Populated: node.Populated, DocumentCount: &count, + }) + } + for _, edge := range snapshot.Edges { + result.Edges = append(result.Edges, authoringv2.CatalogEdge{ID: edge.ID, FromNodeID: edge.FromNodeID, ToNodeID: edge.ToNodeID, Label: edge.Label}) + } + for _, candidate := range snapshot.Candidates { + projectionModes := stringProjectionModes(candidate.ProjectionModes) + count := candidate.ObservedDocumentCount + wire := authoringv2.CatalogCandidate{ + ID: candidate.ID, NodeID: candidate.NodeID, Label: candidate.Label, + LogicalType: candidate.LogicalType, Cardinality: candidate.Cardinality, + Filterable: len(candidate.FilterOperators) > 0, Chartable: len(candidate.ChartAggregations) > 0, + ProjectionModes: projectionModes, DefaultProjectionMode: defaultProjectionMode(projectionModes), + FilterOperators: stringFilterOperators(candidate.FilterOperators), ChartOperations: stringChartOperations(candidate.ChartAggregations), + Populated: candidate.Populated, Count: &count, + SuggestionsAvailable: len(candidate.SuggestedValues) > 0, + SuggestionsComplete: candidate.SuggestionsComplete, + SuggestionsTruncated: candidate.SuggestionsTruncated, + SuggestionCount: len(candidate.SuggestedValues), + } + result.Candidates = append(result.Candidates, wire) + } + for _, diagnostic := range snapshot.Diagnostics { + severity := diagnostic.Severity + if snapshot.Usable() && strings.EqualFold(severity, "ERROR") { + severity = "WARNING" + } + result.Diagnostics = append(result.Diagnostics, authoringv2.CatalogDiagnostic{Severity: severity, Code: diagnostic.Code, Message: diagnostic.Message}) + } + return result +} + +func stringProjectionModes(values []capability.ProjectionMode) []string { + out := make([]string, len(values)) + for i, value := range values { + out[i] = string(value) + } + return out +} +func stringFilterOperators(values []capability.FilterOperator) []string { + out := make([]string, len(values)) + for i, value := range values { + out[i] = string(value) + } + return out +} +func stringChartOperations(values []capability.ChartAggregation) []string { + out := make([]string, len(values)) + for i, value := range values { + out[i] = string(value) + } + return out +} +func defaultProjectionMode(values []string) string { + for _, preferred := range []string{string(capability.ProjectionScalar), string(capability.ProjectionFirst), string(capability.ProjectionArray), string(capability.ProjectionDistinctArray)} { + for _, value := range values { + if value == preferred { + return value + } + } + } + return "" +} diff --git a/internal/server/explorer_capability_test.go b/internal/server/explorer_capability_test.go new file mode 100644 index 00000000..2ccffd02 --- /dev/null +++ b/internal/server/explorer_capability_test.go @@ -0,0 +1,343 @@ +package server + +import ( + "context" + "encoding/json" + "errors" + "net/http" + "strings" + "testing" + + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/catalog" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataset" + "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/explorer/authoringv2" + "github.com/calypr/loom/internal/explorer/capability" + "github.com/calypr/loom/internal/explorer/capabilitystore" + "github.com/gofiber/fiber/v3" +) + +type staticCapabilityEvidence struct { + inventory catalog.ResourceInventoryResult + relationships catalog.RelationshipObservationResult + fields catalog.FieldEnrichmentResult +} + +func (s staticCapabilityEvidence) DiscoverResourceInventory(context.Context, catalog.ResourceInventoryOptions) (catalog.ResourceInventoryResult, error) { + return s.inventory, nil +} +func (s staticCapabilityEvidence) DiscoverRelationshipObservations(context.Context, catalog.RelationshipObservationOptions) (catalog.RelationshipObservationResult, error) { + return s.relationships, nil +} +func (s staticCapabilityEvidence) DiscoverFieldEnrichment(context.Context, catalog.FieldEnrichmentOptions) (catalog.FieldEnrichmentResult, error) { + return s.fields, nil +} + +type staticActiveManifest struct{ manifest dataset.Manifest } + +func (s staticActiveManifest) ResolveActiveManifest(context.Context, string) (dataset.Manifest, error) { + return s.manifest, nil +} + +type capabilityTestResourceAccess struct{ resources []string } + +func (c capabilityTestResourceAccess) GetAllowedResources(context.Context, string, string, string) ([]string, error) { + return append([]string(nil), c.resources...), nil +} + +func testAuthorizedCapabilitySnapshot(t *testing.T, generation string, scope authscope.ReadScope) capability.Snapshot { + t.Helper() + return capability.NewSnapshot( + capability.SnapshotIdentity{ + Project: "project-a", Generation: generation, AuthorizationScopeDigest: explorerScopeDigest(scope), + SchemaDigest: strings.Repeat("a", 64), ResourceInventoryDigest: "inventory", RelationshipDigest: "relationships", FieldDigest: "fields", + ProtocolVersion: explorerCapabilityProtocolVersion, CompilerVersion: explorerCapabilityCompilerVersion, + TraversalPolicyVersion: explorerTraversalPolicyVersion, ProjectionPolicyVersion: explorerProjectionPolicyVersion, + }, + capability.Policy{Route: capability.RoutePolicy{Version: explorerTraversalPolicyVersion, AllowsRepeatedEdges: true, AllowsSelfLoops: true}, Projection: capability.ProjectionPolicy{Version: explorerProjectionPolicyVersion}}, + capability.StatusReady, true, false, + []capability.Node{{ID: "n_patient", ResourceType: "Patient", RowRootEligible: true, RowGrain: "RESOURCE", Populated: true, SupportedOperations: []capability.Operation{capability.OperationSelect}}}, + nil, nil, nil, + ) +} + +func testCapabilityScopeResolver(paths []string) *authscope.ScopeResolver { + return authscope.NewScopeResolver(authscope.ScopeResolverConfig{ + ResourceAccess: capabilityTestResourceAccess{resources: []string{"/programs/example/projects/allowed"}}, + ListExistingAuthResourcePaths: func(context.Context, catalog.AuthResourcePathOptions) ([]string, error) { + return append([]string(nil), paths...), nil + }, + }) +} + +func TestExplorerCapabilityResolverAuthorizedCompilationRequiresActiveGeneration(t *testing.T) { + manifest := testCapabilityManifest(t) + store := capabilitystore.NewMemoryStore() + snapshot := testAuthorizedCapabilitySnapshot(t, "generation-a", authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}) + if _, err := store.Put(context.Background(), snapshot); err != nil { + t.Fatal(err) + } + resolver, err := newExplorerCapabilityResolver(staticCapabilityEvidence{}, nil, staticActiveManifest{manifest: manifest}, store) + if err != nil { + t.Fatal(err) + } + authorized, err := resolver.ResolveForCompilation(context.Background(), "project-a", snapshot.Token) + if err != nil { + t.Fatal(err) + } + if authorized.Snapshot.Token != snapshot.Token || authorized.Scope.Mode != authscope.ReadScopeUnrestricted { + t.Fatalf("authorized compilation capability = %#v", authorized) + } + + inactive := testAuthorizedCapabilitySnapshot(t, "generation-old", authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}) + if _, err := store.Put(context.Background(), inactive); err != nil { + t.Fatal(err) + } + if _, err := resolver.ResolveForCompilation(context.Background(), "project-a", inactive.Token); !errors.Is(err, capability.ErrStaleSnapshot) { + t.Fatalf("inactive compilation token error = %v, want stale snapshot", err) + } +} + +func TestExplorerCapabilityResolverAuthorizedExecutionRetainsInactiveGeneration(t *testing.T) { + manifest := testCapabilityManifest(t) + store := capabilitystore.NewMemoryStore() + snapshot := testAuthorizedCapabilitySnapshot(t, "generation-old", authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}) + if _, err := store.Put(context.Background(), snapshot); err != nil { + t.Fatal(err) + } + resolver, err := newExplorerCapabilityResolver(staticCapabilityEvidence{}, nil, staticActiveManifest{manifest: manifest}, store) + if err != nil { + t.Fatal(err) + } + authorized, err := resolver.ResolveForExecution(context.Background(), "project-a", snapshot.Token) + if err != nil { + t.Fatal(err) + } + if authorized.Snapshot.Identity.Generation != "generation-old" { + t.Fatalf("execution generation = %q", authorized.Snapshot.Identity.Generation) + } +} + +func TestExplorerCapabilityResolverEnforcesProjectAuthorizationWithoutScopeResolver(t *testing.T) { + manifest := testCapabilityManifest(t) + store := capabilitystore.NewMemoryStore() + snapshot := testAuthorizedCapabilitySnapshot(t, "generation-a", authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}) + if _, err := store.Put(context.Background(), snapshot); err != nil { + t.Fatal(err) + } + resolver, err := newExplorerCapabilityResolver(staticCapabilityEvidence{}, nil, staticActiveManifest{manifest: manifest}, store) + if err != nil { + t.Fatal(err) + } + ctx := authscope.ContextWithPrincipal(context.Background(), &authscope.Principal{Projects: []string{"another-project"}}) + if _, err := resolver.ResolveForExecution(ctx, "project-a", snapshot.Token); !errors.Is(err, authscope.ErrForbidden) { + t.Fatalf("project authorization error = %v, want forbidden", err) + } +} + +func TestExplorerCapabilityResolverRejectsChangedScopeAndPreservesRestrictedEmpty(t *testing.T) { + manifest := testCapabilityManifest(t) + store := capabilitystore.NewMemoryStore() + unrestricted := testAuthorizedCapabilitySnapshot(t, "generation-a", authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}) + if _, err := store.Put(context.Background(), unrestricted); err != nil { + t.Fatal(err) + } + scopedResolver, err := newExplorerCapabilityResolver(staticCapabilityEvidence{}, testCapabilityScopeResolver([]string{"example-other"}), staticActiveManifest{manifest: manifest}, store) + if err != nil { + t.Fatal(err) + } + ctx := authscope.ContextWithPrincipal(context.Background(), &authscope.Principal{AuthorizationHeader: "Bearer token"}) + if _, err := scopedResolver.ResolveForExecution(ctx, "project-a", unrestricted.Token); !errors.Is(err, capability.ErrStaleSnapshot) { + t.Fatalf("changed scope error = %v, want stale snapshot", err) + } + + emptyScope := authscope.ReadScope{Mode: authscope.ReadScopeRestricted} + empty := testAuthorizedCapabilitySnapshot(t, "generation-a", emptyScope) + if _, err := store.Put(context.Background(), empty); err != nil { + t.Fatal(err) + } + authorized, err := scopedResolver.ResolveForExecution(ctx, "project-a", empty.Token) + if err != nil { + t.Fatal(err) + } + if authorized.Scope.Unrestricted() || len(authorized.Scope.AuthResourcePaths) != 0 { + t.Fatalf("restricted-empty scope = %#v", authorized.Scope) + } + if authorized.Scope.Mode != emptyScope.Mode { + t.Fatalf("restricted-empty mode = %q, want %q", authorized.Scope.Mode, emptyScope.Mode) + } + // The returned scope is a defensive copy, not the resolver's retained + // authorization result. + authorized.Scope.AuthResourcePaths = append(authorized.Scope.AuthResourcePaths, "mutated") + again, err := scopedResolver.ResolveForExecution(ctx, "project-a", empty.Token) + if err != nil || len(again.Scope.AuthResourcePaths) != 0 || again.Scope.Unrestricted() { + t.Fatalf("scope alias leaked after mutation: %#v, %v", again.Scope, err) + } +} + +func TestExplorerCapabilityResolverBuildsAndReusesCompilerProvenSnapshot(t *testing.T) { + manifest := testCapabilityManifest(t) + inventory := []catalog.ResourceInventoryObservation{{Project: "project-a", DatasetGeneration: "generation-a", ResourceType: "Patient", DocumentCount: 2}} + fields := []catalog.FieldEnrichmentObservation{{Project: "project-a", DatasetGeneration: "generation-a", ResourceType: "Patient", Path: "id", Kind: "scalar", DocCount: 2}} + inventoryDigest, _ := catalog.ResourceInventoryDigest(inventory) + relationshipDigest, _ := catalog.RelationshipObservationDigest(nil) + fieldDigest, _ := catalog.FieldEnrichmentDigest(fields) + evidence := staticCapabilityEvidence{ + inventory: catalog.ResourceInventoryResult{Values: inventory, Available: true, Complete: true, Status: catalog.EvidenceAvailable, Digest: inventoryDigest}, + relationships: catalog.RelationshipObservationResult{Values: []catalog.RelationshipObservation{}, Available: true, Complete: true, Status: catalog.EvidenceEmpty, Digest: relationshipDigest}, + fields: catalog.FieldEnrichmentResult{Values: fields, Available: true, Complete: true, Status: catalog.EvidenceAvailable, Digest: fieldDigest}, + } + repository := capabilitystore.NewMemoryStore() + resolver, err := newExplorerCapabilityResolver(evidence, nil, staticActiveManifest{manifest: manifest}, repository) + if err != nil { + t.Fatal(err) + } + first, err := resolver.Resolve(context.Background(), "project-a", "") + if err != nil { + t.Fatal(err) + } + if !first.Usable() || len(first.Nodes) != 1 || first.Nodes[0].ResourceType != "Patient" || len(first.Candidates) != 1 || first.Candidates[0].FieldPath != "id" { + t.Fatalf("snapshot=%#v", first) + } + if first.Identity.ResourceInventoryDigest != inventoryDigest || first.Identity.FieldDigest != fieldDigest { + t.Fatalf("identity=%#v", first.Identity) + } + second, err := resolver.Resolve(context.Background(), "project-a", "generation-a") + if err != nil { + t.Fatal(err) + } + if second.Token != first.Token { + t.Fatalf("immutable snapshot was rebuilt with a different token: %q != %q", second.Token, first.Token) + } + loaded, err := resolver.ResolveToken(context.Background(), "project-a", first.Token) + if err != nil || loaded.Token != first.Token { + t.Fatalf("ResolveToken() = %#v, %v", loaded, err) + } +} + +func TestExplorerCapabilityResolverFailsClosedOnIncompleteFieldEnrichment(t *testing.T) { + manifest := testCapabilityManifest(t) + inventory := []catalog.ResourceInventoryObservation{{Project: "project-a", DatasetGeneration: "generation-a", ResourceType: "Patient", DocumentCount: 1}} + digest, _ := catalog.ResourceInventoryDigest(inventory) + evidence := staticCapabilityEvidence{ + inventory: catalog.ResourceInventoryResult{Values: inventory, Available: true, Complete: true, Status: catalog.EvidenceAvailable, Digest: digest}, + relationships: catalog.RelationshipObservationResult{Values: []catalog.RelationshipObservation{}, Available: true, Complete: true, Status: catalog.EvidenceEmpty, Digest: "sha256:relationships"}, + fields: catalog.FieldEnrichmentResult{Values: []catalog.FieldEnrichmentObservation{}, Available: true, Complete: false, Status: catalog.EvidenceIncomplete, Digest: "sha256:fields"}, + } + resolver, err := newExplorerCapabilityResolver(evidence, nil, staticActiveManifest{manifest: manifest}, capabilitystore.NewMemoryStore()) + if err != nil { + t.Fatal(err) + } + if _, err := resolver.Resolve(context.Background(), "project-a", ""); err == nil || !strings.Contains(err.Error(), "field enrichment") { + t.Fatalf("Resolve() error=%v", err) + } +} + +func TestExplorerAuthoringV2HardCutCompilesAndPreviewsReceipt(t *testing.T) { + snapshot := testAuthoringV2CapabilitySnapshot() + store := explorer.NewMemoryStore() + service, err := explorer.NewService(store) + if err != nil { + t.Fatal(err) + } + if _, err := service.CreateEmptyInteractive(context.Background(), "project-a", "custom", "Custom", "test"); err != nil { + t.Fatal(err) + } + legacy := legacyCatalogSnapshot(snapshot) + compile := func(ctx context.Context, request ExplorerAuthoringV1CompileRequest) (ExplorerAuthoringV1CompileResult, error) { + return ResolveAuthoringBundle(ctx, nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return legacy, nil }, request) + } + app := fiber.New() + RegisterExplorerAuthoringV2Routes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{ + Capability: func(context.Context, string, string, string) (capability.Snapshot, error) { return snapshot, nil }, + CapabilityToken: func(_ context.Context, _ string, token string) (capability.Snapshot, error) { + if err := snapshot.ValidateToken(token); err != nil { + return capability.Snapshot{}, err + } + return snapshot, nil + }, + AuthorizedCapabilityExecution: func(_ context.Context, _, token string) (AuthorizedCapability, error) { + if err := snapshot.ValidateToken(token); err != nil { + return AuthorizedCapability{}, err + } + return AuthorizedCapability{Snapshot: snapshot, Scope: authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}}, nil + }, + AuthoringCompile: compile, + Preview: func(_ context.Context, _ recipe.Bundle, _ recipe.RuntimeBindings) (map[string][]map[string]any, error) { + return map[string][]map[string]any{"patients": {{"id": "patient-1"}}}, nil + }, + }) + + get := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v2/builder", "") + if get.StatusCode != http.StatusOK { + t.Fatalf("GET builder status=%d body=%s", get.StatusCode, get.Body) + } + legacyResponse := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v1/builder", "") + if legacyResponse.StatusCode != http.StatusNotFound { + t.Fatalf("V1 Builder remains registered: status=%d", legacyResponse.StatusCode) + } + suggestions := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v2/capabilities/"+snapshot.Token+"/candidates/c_patient_id/suggestions", "") + if suggestions.StatusCode != http.StatusOK || !strings.Contains(suggestions.Body, `"patient-1"`) { + t.Fatalf("candidate suggestions status=%d body=%s", suggestions.StatusCode, suggestions.Body) + } + body := `{"document":{"apiVersion":"` + authoringv2.APIVersion + `","kind":"` + authoringv2.Kind + `","output":{"id":"patients","title":"Patients"},"rootNodeId":"n_patient","routeSteps":[],"selections":[{"candidateId":"c_patient_id","occurrenceId":"base","projectionMode":"FIRST"}],"presentation":{}},"snapshotToken":"` + snapshot.Token + `"}` + compiled := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/builder", body) + if compiled.StatusCode != http.StatusOK { + t.Fatalf("POST builder status=%d body=%s", compiled.StatusCode, compiled.Body) + } + var result struct { + ReceiptID string `json:"receiptId"` + } + if err := json.Unmarshal([]byte(compiled.Body), &result); err != nil { + t.Fatal(err) + } + if result.ReceiptID == "" { + t.Fatal("compile result omitted receiptId") + } + receipt, err := service.CompilationReceipt(context.Background(), result.ReceiptID) + if err != nil { + t.Fatal(err) + } + if got := receipt.Bundle.Outputs[0].Fields[0].ValueMode; got != recipe.ValueModeFirst { + t.Fatalf("V2 projection mode was not carried into the executable recipe: %q", got) + } + preview := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/preview", `{"receiptId":"`+result.ReceiptID+`","outputId":"patients","limit":5}`) + if preview.StatusCode != http.StatusOK { + t.Fatalf("preview status=%d body=%s", preview.StatusCode, preview.Body) + } +} + +func testCapabilityManifest(t *testing.T) dataset.Manifest { + t.Helper() + ref, err := dataset.NewRef("project-a", "generation-a") + if err != nil { + t.Fatal(err) + } + schema, err := dataset.NewSchemaSnapshot("urn:test", "R5", strings.Repeat("a", 64), []string{"Patient"}) + if err != nil { + t.Fatal(err) + } + manifest, err := dataset.NewManifest(ref, schema) + if err != nil { + t.Fatal(err) + } + manifest, err = manifest.Transition(dataset.StateStaged) + if err != nil { + t.Fatal(err) + } + return manifest +} + +func testAuthoringV2CapabilitySnapshot() capability.Snapshot { + return capability.NewSnapshot( + capability.SnapshotIdentity{Project: "project-a", Generation: "generation-a", AuthorizationScopeDigest: explorerScopeDigest(authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}), SchemaDigest: strings.Repeat("a", 64), ResourceInventoryDigest: "inventory", RelationshipDigest: "relationships", FieldDigest: "fields", ProtocolVersion: explorerCapabilityProtocolVersion, CompilerVersion: explorerCapabilityCompilerVersion, TraversalPolicyVersion: explorerTraversalPolicyVersion, ProjectionPolicyVersion: explorerProjectionPolicyVersion}, + capability.Policy{Route: capability.RoutePolicy{Version: explorerTraversalPolicyVersion, AllowsRepeatedEdges: true, AllowsSelfLoops: true}, Projection: capability.ProjectionPolicy{Version: explorerProjectionPolicyVersion}}, + capability.StatusReady, true, false, + []capability.Node{{ID: "n_patient", ResourceType: "Patient", RowRootEligible: true, RowGrain: "RESOURCE", Populated: true, DocumentCount: 1, SupportedOperations: []capability.Operation{capability.OperationSelect}}}, + nil, + []capability.Candidate{{ID: "c_patient_id", NodeID: "n_patient", ResourceType: "Patient", FieldPath: "id", Label: "ID", LogicalType: "string", Cardinality: "OPTIONAL_ONE", ProjectionModes: []capability.ProjectionMode{capability.ProjectionScalar, capability.ProjectionFirst}, SupportedOperations: []capability.Operation{capability.OperationSelect}, Observed: true, Populated: true, SuggestedValues: []string{"patient-1"}, SuggestionsComplete: true}}, + nil, + ) +} diff --git a/internal/server/explorer_config_route.go b/internal/server/explorer_config_route.go index 55c10ee5..9be86c46 100644 --- a/internal/server/explorer_config_route.go +++ b/internal/server/explorer_config_route.go @@ -12,6 +12,7 @@ import ( "github.com/calypr/loom/internal/dataframe/recipe" "github.com/calypr/loom/internal/dataset" "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/projectid" "github.com/gofiber/fiber/v3" ) @@ -26,7 +27,7 @@ func RegisterExplorerConfigV2Route(app *fiber.App, authorizer authscope.Authoriz return } app.Post("/api/v1/projects/:project/generations/:generation/explorer-config", func(c fiber.Ctx) error { - project, generation := strings.TrimSpace(c.Params("project")), strings.TrimSpace(c.Params("generation")) + project, generation := explorerProjectParam(c), strings.TrimSpace(c.Params("generation")) if project == "" || generation == "" { return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "project and generation are required"}) } @@ -48,7 +49,10 @@ func RegisterExplorerConfigV2Route(app *fiber.App, authorizer authscope.Authoriz if commit == "" { return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "X-Loom-Source-Commit is required"}) } - bundle.Name = "explorer_" + project + "_default" + // Recipe names are storage/execution identifiers, not public project + // URLs. Keep the historical hyphenated form so a canonical slash in the + // route never becomes an invalid name containing '/'. + bundle.Name = "explorer_" + projectid.Legacy(project) + "_default" bundle.TranslationVersion = "repository-" + commit if err := bundle.Validate(); err != nil { return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"error": fmt.Sprintf("invalid recipe: %v", err)}) @@ -57,7 +61,7 @@ func RegisterExplorerConfigV2Route(app *fiber.App, authorizer authscope.Authoriz if err != nil { return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()}) } - execution, err := materialize(c.Context(), bundle, recipe.RuntimeBindings{Project: project, DatasetGeneration: generation}) + execution, err := materialize(c.Context(), bundle, recipe.RuntimeBindings{Project: projectid.Legacy(project), DatasetGeneration: generation}) if err != nil { return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"error": fmt.Sprintf("materialize ExplorerConfigV2: %v", err)}) } @@ -77,7 +81,7 @@ func RegisterExplorerConfigV2Route(app *fiber.App, authorizer authscope.Authoriz if len(lifecycle) == 0 || lifecycle[0].ActivateRelease == nil { return c.Status(http.StatusServiceUnavailable).JSON(fiber.Map{"error": "release activation is not configured", "executionId": execution.ID}) } - if err := lifecycle[0].ActivateRelease(c.Context(), project, generation, selectorsForBundle(bundle)); err != nil { + if err := lifecycle[0].ActivateRelease(c.Context(), projectid.Legacy(project), generation, selectorsForBundle(bundle)); err != nil { _, _ = explorers.FailRevision(c.Context(), revision.ID, []explorer.Diagnostic{{Severity: "ERROR", Code: "RELEASE_ACTIVATION_FAILED", Message: err.Error(), Retryable: true}}) return c.Status(http.StatusConflict).JSON(fiber.Map{"error": fmt.Sprintf("activate published ExplorerConfigV2: %v", err), "executionId": execution.ID}) } @@ -93,7 +97,7 @@ func RegisterExplorerConfigV2Route(app *fiber.App, authorizer authscope.Authoriz return c.Status(http.StatusOK).JSON(fiber.Map{"project": project, "generation": generation, "explorerId": "default", "executionId": execution.ID, "recipe": bundle.Name, "translationVersion": bundle.TranslationVersion, "activated": true}) }) app.Get("/api/v1/projects/:project/explorer-config", func(c fiber.Ctx) error { - project := strings.TrimSpace(c.Params("project")) + project := explorerProjectParam(c) principal, _ := c.Locals("principal").(*authscope.Principal) if err := authorizeRead(c.Context(), principal, project); err != nil { return c.Status(http.StatusForbidden).JSON(fiber.Map{"error": "forbidden"}) @@ -111,6 +115,7 @@ func RegisterExplorerConfigV2Route(app *fiber.App, authorizer authscope.Authoriz lifecycle = []ExplorerV2LifecycleConfig{{Materialize: materialize}} } RegisterExplorerLifecycleRoutes(app, authorizer, authorizeRead, explorers, lifecycle[0]) + RegisterExplorerAuthoringV2Routes(app, authorizer, authorizeRead, explorers, lifecycle[0]) } func explorerMaterializations(bundle recipe.Bundle, execution graphresolver.RecipeExecution) []explorer.Materialization { diff --git a/internal/server/explorer_preview_response.go b/internal/server/explorer_preview_response.go new file mode 100644 index 00000000..126b4fb4 --- /dev/null +++ b/internal/server/explorer_preview_response.go @@ -0,0 +1,249 @@ +package server + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "time" + + dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" + "github.com/calypr/loom/internal/explorer" + "github.com/gofiber/fiber/v3" +) + +const ( + explorerPreviewTimeout = 10 * time.Second + maxExplorerPreviewResponseBytes = 32 << 20 +) + +var ErrPreviewResponseTooLarge = errors.New("PREVIEW_RESPONSE_TOO_LARGE") + +type receiptPreviewResolutionError struct{ Err error } + +func (e *receiptPreviewResolutionError) Error() string { return e.Err.Error() } +func (e *receiptPreviewResolutionError) Unwrap() error { return e.Err } + +func previewRouteFailure(c fiber.Ctx, err error) error { + if errors.Is(err, ErrPreviewResponseTooLarge) { + return authoringHTTPError(c, &explorer.AuthoringError{Status: 413, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "preview", Code: "PREVIEW_RESPONSE_TOO_LARGE", Message: "preview response exceeds the maximum size"}, Cause: err}) + } + if errors.Is(err, context.DeadlineExceeded) { + return authoringHTTPError(c, &explorer.AuthoringError{Status: 504, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "preview", Code: "PREVIEW_TIMEOUT", Message: "preview exceeded its execution deadline"}, Cause: err}) + } + if errors.Is(err, context.Canceled) { + return authoringHTTPError(c, &explorer.AuthoringError{Status: 499, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "preview", Code: "CLIENT_CANCELED", Message: "preview request was canceled"}, Cause: err}) + } + if userErr, ok := dataframeerrors.AsUserError(err); ok { + switch userErr.Code() { + case string(dataframeerrors.CodeClientCanceled): + return authoringHTTPError(c, &explorer.AuthoringError{Status: 499, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "preview", Code: "CLIENT_CANCELED", Message: "preview request was canceled"}, Cause: err}) + case string(dataframeerrors.CodePreviewTimeout): + return authoringHTTPError(c, &explorer.AuthoringError{Status: 504, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "preview", Code: "PREVIEW_TIMEOUT", Message: "preview exceeded its execution deadline"}, Cause: err}) + case string(dataframeerrors.CodePreviewResponseTooLarge): + return authoringHTTPError(c, &explorer.AuthoringError{Status: 413, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "preview", Code: "PREVIEW_RESPONSE_TOO_LARGE", Message: dataframeerrors.PublicMessage(err)}, Cause: err}) + case string(dataframeerrors.CodePlanTooExpensive): + return authoringHTTPError(c, &explorer.AuthoringError{Status: 429, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "preview", Code: userErr.Code(), Message: dataframeerrors.PublicMessage(err)}, Cause: err}) + case string(dataframeerrors.CodeBackendUnavailable), string(dataframeerrors.CodeReceiptStoreUnavailable): + return authoringHTTPError(c, &explorer.AuthoringError{Status: 503, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "preview", Code: userErr.Code(), Message: dataframeerrors.PublicMessage(err)}, Cause: err}) + case string(dataframeerrors.CodeRecipeContractViolation), string(dataframeerrors.CodeDynamicSchemaDrift): + return authoringHTTPError(c, explorerConflict("preview", "RECEIPT_RECOMPILE_REQUIRED", "receipt deterministic lowering no longer matches the stored artifact", nil)) + default: + return authoringHTTPError(c, &explorer.AuthoringError{Status: 500, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "preview", Code: "PREVIEW_FAILED", Message: "receipt preview failed"}, Cause: err}) + } + } + if errors.As(err, new(*receiptPreviewResolutionError)) { + return authoringHTTPError(c, explorerConflict("preview", "RECEIPT_RECOMPILE_REQUIRED", "receipt deterministic lowering no longer matches the stored artifact", nil)) + } + return authoringHTTPError(c, &explorer.AuthoringError{Status: 500, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "preview", Code: "PREVIEW_FAILED", Message: "receipt preview failed"}, Cause: err}) +} + +type previewResponseTooLargeError struct { + Limit int +} + +func (e *previewResponseTooLargeError) Error() string { + if e == nil || e.Limit <= 0 { + return ErrPreviewResponseTooLarge.Error() + } + return fmt.Sprintf("%s: response exceeds %d bytes", ErrPreviewResponseTooLarge, e.Limit) +} + +func (e *previewResponseTooLargeError) Unwrap() error { return ErrPreviewResponseTooLarge } + +// encodeExplorerPreviewResponse constructs the complete response before it is +// handed to Fiber. A capped writer makes overflow recoverable without ever +// sending a truncated JSON document to the client. +func encodeExplorerPreviewResponse(receipt *explorer.CompilationReceipt, outputID string, columns []explorer.EmittedColumn, rows []map[string]any, limit int) ([]byte, error) { + if limit <= 0 { + limit = maxExplorerPreviewResponseBytes + } + var out cappedPreviewBuffer + out.limit = limit + write := func(raw []byte) error { + if _, err := out.Write(raw); err != nil { + return err + } + return nil + } + writeString := func(value string) error { + raw, err := json.Marshal(value) + if err != nil { + return err + } + return write(raw) + } + if err := write([]byte(`{"apiVersion":"loom.calypr.org/explorer-authoring/v2","kind":"ExplorerPreviewResult","receiptId":`)); err != nil { + return nil, err + } + if err := writeString(receipt.ID); err != nil { + return nil, err + } + if err := write([]byte(`,"outputId":`)); err != nil { + return nil, err + } + if err := writeString(outputID); err != nil { + return nil, err + } + encodedColumns, err := json.Marshal(columns) + if err != nil { + return nil, err + } + if err := write([]byte(`,"columns":`)); err != nil { + return nil, err + } + if err := write(encodedColumns); err != nil { + return nil, err + } + if err := write([]byte(`,"rows":[`)); err != nil { + return nil, err + } + for index, row := range rows { + if index > 0 { + if err := write([]byte(",")); err != nil { + return nil, err + } + } + encodedRow, err := json.Marshal(row) + if err != nil { + return nil, err + } + if err := write(encodedRow); err != nil { + return nil, err + } + } + if err := write([]byte(`],"rowCount":`)); err != nil { + return nil, err + } + count, err := json.Marshal(len(rows)) + if err != nil { + return nil, err + } + if err := write(count); err != nil { + return nil, err + } + if err := write([]byte("}")); err != nil { + return nil, err + } + return out.Bytes(), nil +} + +type previewResponseEncoder struct { + out cappedPreviewBuffer + rowCount int + firstRow bool +} + +func newPreviewResponseEncoder(receipt *explorer.CompilationReceipt, outputID string, columns []explorer.EmittedColumn, limit int) (*previewResponseEncoder, error) { + if receipt == nil { + return nil, fmt.Errorf("compilation receipt is required") + } + encoder := &previewResponseEncoder{firstRow: true} + encoder.out.limit = limit + write := func(raw []byte) error { _, err := encoder.out.Write(raw); return err } + if err := write([]byte(`{"apiVersion":"loom.calypr.org/explorer-authoring/v2","kind":"ExplorerPreviewResult","receiptId":`)); err != nil { + return nil, err + } + receiptID, err := json.Marshal(receipt.ID) + if err != nil { + return nil, err + } + if err := write(receiptID); err != nil { + return nil, err + } + if err := write([]byte(`,"outputId":`)); err != nil { + return nil, err + } + outputRaw, err := json.Marshal(outputID) + if err != nil { + return nil, err + } + if err := write(outputRaw); err != nil { + return nil, err + } + encodedColumns, err := json.Marshal(columns) + if err != nil { + return nil, err + } + if err := write([]byte(`,"columns":`)); err != nil { + return nil, err + } + if err := write(encodedColumns); err != nil { + return nil, err + } + if err := write([]byte(`,"rows":[`)); err != nil { + return nil, err + } + return encoder, nil +} + +func (e *previewResponseEncoder) Visit(row map[string]any) error { + if e == nil { + return fmt.Errorf("preview response encoder is nil") + } + if !e.firstRow { + if _, err := e.out.Write([]byte(",")); err != nil { + return err + } + } + encoded, err := json.Marshal(row) + if err != nil { + return err + } + if _, err := e.out.Write(encoded); err != nil { + return err + } + e.firstRow = false + e.rowCount++ + return nil +} + +func (e *previewResponseEncoder) Finish() ([]byte, error) { + if e == nil { + return nil, fmt.Errorf("preview response encoder is nil") + } + if _, err := e.out.Write([]byte(`],"rowCount":`)); err != nil { + return nil, err + } + count, _ := json.Marshal(e.rowCount) + if _, err := e.out.Write(count); err != nil { + return nil, err + } + if _, err := e.out.Write([]byte("}")); err != nil { + return nil, err + } + return e.out.Bytes(), nil +} + +type cappedPreviewBuffer struct { + bytes.Buffer + limit int +} + +func (b *cappedPreviewBuffer) Write(p []byte) (int, error) { + if b.limit > 0 && b.Len()+len(p) > b.limit { + return 0, &previewResponseTooLargeError{Limit: b.limit} + } + return b.Buffer.Write(p) +} diff --git a/internal/server/explorer_preview_response_test.go b/internal/server/explorer_preview_response_test.go new file mode 100644 index 00000000..384c1dea --- /dev/null +++ b/internal/server/explorer_preview_response_test.go @@ -0,0 +1,87 @@ +package server + +import ( + "context" + "encoding/json" + "errors" + "net/http" + "strings" + "testing" + + dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" + "github.com/calypr/loom/internal/explorer" + "github.com/gofiber/fiber/v3" +) + +func TestPreviewResponseEncoderProducesAtomicContract(t *testing.T) { + receipt := &explorer.CompilationReceipt{ID: "same-id"} + columns := []explorer.EmittedColumn{{EmissionID: "emission", OutputID: "same-id", PublicColumn: "public", LogicalType: "string"}} + encoder, err := newPreviewResponseEncoder(receipt, "same-id", columns, 4096) + if err != nil { + t.Fatal(err) + } + if err := encoder.Visit(map[string]any{"public": "value"}); err != nil { + t.Fatal(err) + } + raw, err := encoder.Finish() + if err != nil { + t.Fatal(err) + } + var decoded struct { + ReceiptID string `json:"receiptId"` + OutputID string `json:"outputId"` + Rows []map[string]any `json:"rows"` + RowCount int `json:"rowCount"` + Columns []explorer.EmittedColumn `json:"columns"` + } + if err := json.Unmarshal(raw, &decoded); err != nil { + t.Fatalf("decode response %s: %v", raw, err) + } + if decoded.ReceiptID != receipt.ID || decoded.OutputID != "same-id" || decoded.RowCount != 1 || len(decoded.Rows) != 1 || len(decoded.Columns) != 1 { + t.Fatalf("response = %#v", decoded) + } +} + +func TestPreviewResponseEncoderRejectsOverflowWithoutResult(t *testing.T) { + encoder, err := newPreviewResponseEncoder(&explorer.CompilationReceipt{ID: "receipt"}, "output", nil, 1024) + if err != nil { + t.Fatal(err) + } + err = encoder.Visit(map[string]any{"value": strings.Repeat("x", 2048)}) + if !errors.Is(err, ErrPreviewResponseTooLarge) { + t.Fatalf("Visit error = %v, want %v", err, ErrPreviewResponseTooLarge) + } + if _, err := encodeExplorerPreviewResponse(&explorer.CompilationReceipt{ID: "receipt"}, "output", nil, []map[string]any{{"value": strings.Repeat("x", 2048)}}, 1024); !errors.Is(err, ErrPreviewResponseTooLarge) { + t.Fatalf("legacy encode error = %v, want %v", err, ErrPreviewResponseTooLarge) + } +} + +func TestPreviewRouteFailurePreservesStableClassifications(t *testing.T) { + tests := []struct { + name string + err error + status int + code string + }{ + {"timeout", context.DeadlineExceeded, http.StatusGatewayTimeout, "PREVIEW_TIMEOUT"}, + {"canceled", context.Canceled, 499, "CLIENT_CANCELED"}, + {"oversized", &previewResponseTooLargeError{Limit: 32}, http.StatusRequestEntityTooLarge, "PREVIEW_RESPONSE_TOO_LARGE"}, + {"plan", dataframeerrors.NewError(dataframeerrors.CodePlanTooExpensive, "private"), http.StatusTooManyRequests, "PLAN_TOO_EXPENSIVE"}, + {"backend", dataframeerrors.NewError(dataframeerrors.CodeBackendUnavailable, "private", dataframeerrors.WithRetryable(true)), http.StatusServiceUnavailable, "BACKEND_UNAVAILABLE"}, + {"receipt", &receiptPreviewResolutionError{Err: errors.New("private")}, http.StatusConflict, "RECEIPT_RECOMPILE_REQUIRED"}, + {"unknown", errors.New("private"), http.StatusInternalServerError, "PREVIEW_FAILED"}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + app := fiber.New() + app.Get("/", func(c fiber.Ctx) error { return previewRouteFailure(c, test.err) }) + response := requestJSON(t, app, http.MethodGet, "/", "") + if response.StatusCode != test.status || !strings.Contains(response.Body, `"code":"`+test.code+`"`) { + t.Fatalf("status=%d body=%s, want status=%d code=%s", response.StatusCode, response.Body, test.status, test.code) + } + if strings.Contains(response.Body, "private") { + t.Fatalf("private cause leaked: %s", response.Body) + } + }) + } +} diff --git a/internal/server/explorer_preview_security.go b/internal/server/explorer_preview_security.go new file mode 100644 index 00000000..ba8ae29a --- /dev/null +++ b/internal/server/explorer_preview_security.go @@ -0,0 +1,152 @@ +package server + +import ( + "encoding/json" + "errors" + "fmt" + "strings" + + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/dataframe/recipe/engine" + "github.com/calypr/loom/internal/explorer" +) + +// ErrReceiptExecutionContract identifies a receipt/capability mismatch that +// must be rejected before a receipt-backed query or materialization starts. +// It is deliberately transport-neutral; HTTP adapters can map it to their +// existing receipt-input conflict diagnostic. +var ErrReceiptExecutionContract = errors.New("receipt execution contract mismatch") + +// validateAuthorizedReceiptExecution proves that the capability and scope +// supplied for execution are exactly the inputs frozen in the receipt. It is +// intentionally stricter than comparing only the snapshot token: the scope +// mode is authoritative, so a restricted-empty scope can never become the +// legacy empty-slice/unrestricted interpretation. +func validateAuthorizedReceiptExecution(receipt *explorer.CompilationReceipt, authorized AuthorizedCapability) error { + if receipt == nil { + return receiptExecutionContractError("receipt is required") + } + snapshot := authorized.Snapshot + if strings.TrimSpace(receipt.SnapshotToken) == "" || snapshot.Token != receipt.SnapshotToken { + return receiptExecutionContractError("capability token does not exactly match receipt token") + } + if err := snapshot.ValidateToken(receipt.SnapshotToken); err != nil { + return receiptExecutionContractError("capability token is invalid: %v", err) + } + if snapshot.Identity.Project != receipt.Project { + return receiptExecutionContractError("capability project changed") + } + if snapshot.Identity.Generation != receipt.SourceGeneration { + return receiptExecutionContractError("capability generation changed") + } + if snapshot.Identity.SchemaDigest != receipt.CapabilitySchemaDigest { + return receiptExecutionContractError("capability schema changed") + } + if snapshot.Identity.AuthorizationScopeDigest != receipt.AuthorizationScopeDigest { + return receiptExecutionContractError("capability scope digest changed") + } + if err := validateAuthorizedReadScope(authorized.Scope, receipt.AuthorizationScopeDigest); err != nil { + return err + } + return nil +} + +// validateAuthorizedReadScope verifies both the digest and the explicit mode. +// In particular, restricted + zero paths is a valid deny-all result, while an +// empty mode is rejected because downstream legacy code may interpret it as +// unrestricted when the path list is empty. +func validateAuthorizedReadScope(scope authscope.ReadScope, expectedDigest string) error { + switch scope.Mode { + case authscope.ReadScopeUnrestricted: + if len(scope.AuthResourcePaths) != 0 { + return receiptExecutionContractError("unrestricted scope must not carry resource paths") + } + case authscope.ReadScopeRestricted: + // A restricted-empty scope is intentional and must remain restricted. + default: + return receiptExecutionContractError("authorization scope mode is missing or invalid") + } + if explorerScopeDigest(scope) != expectedDigest { + return receiptExecutionContractError("authorized scope does not match receipt scope digest") + } + return nil +} + +// validateReceiptOutputContract proves that a requested output is present in +// the persisted public contract, rather than merely in the executable recipe. +func validateReceiptOutputContract(receipt *explorer.CompilationReceipt, outputID string) error { + if receipt == nil { + return receiptExecutionContractError("receipt is required") + } + outputID = strings.TrimSpace(outputID) + if outputID == "" { + return receiptExecutionContractError("output is required") + } + var contract struct { + OutputID string `json:"outputId"` + } + if err := json.Unmarshal(receipt.PublicOutputContract, &contract); err != nil { + return receiptExecutionContractError("public output contract is invalid: %v", err) + } + if strings.TrimSpace(contract.OutputID) != outputID { + return receiptExecutionContractError("requested output %q is not in the receipt public contract", outputID) + } + for _, output := range receipt.Bundle.Outputs { + if output.Name == outputID { + return nil + } + } + return receiptExecutionContractError("requested output %q is not in the receipt recipe", outputID) +} + +// validateReceiptEnginePublicColumns compares the engine's authoritative +// ordered public projection schema with the receipt's ordered emitted-column +// contract. Internal identity/provenance projections are excluded from both +// the public contract and this comparison. +func validateReceiptEnginePublicColumns(receipt *explorer.CompilationReceipt, resolved engine.Resolved) error { + if receipt == nil { + return receiptExecutionContractError("receipt is required") + } + want := make(map[string][]string) + for _, emitted := range receipt.EmittedColumns { + if strings.TrimSpace(emitted.OutputID) == "" || strings.TrimSpace(emitted.PublicColumn) == "" { + return receiptExecutionContractError("receipt contains an invalid emitted column") + } + want[emitted.OutputID] = append(want[emitted.OutputID], emitted.PublicColumn) + } + seen := make(map[string]bool) + for _, output := range resolved.Compiled.Outputs { + seen[output.Name] = true + actual := make([]string, 0, len(output.OutputSchema)) + for _, column := range output.OutputSchema { + if !column.Internal { + actual = append(actual, column.Name) + } + } + if !sameOrderedStrings(actual, want[output.Name]) { + return receiptExecutionContractError("engine public columns for output %q differ from receipt", output.Name) + } + } + for output := range want { + if !seen[output] { + return receiptExecutionContractError("receipt contains columns for unknown output %q", output) + } + } + return nil +} + +func sameOrderedStrings(left, right []string) bool { + if len(left) != len(right) { + return false + } + for index := range left { + if left[index] != right[index] { + return false + } + } + return true +} + +func receiptExecutionContractError(format string, args ...any) error { + return fmt.Errorf("%w: %s", ErrReceiptExecutionContract, fmt.Sprintf(format, args...)) +} diff --git a/internal/server/explorer_preview_security_test.go b/internal/server/explorer_preview_security_test.go new file mode 100644 index 00000000..9039af97 --- /dev/null +++ b/internal/server/explorer_preview_security_test.go @@ -0,0 +1,141 @@ +package server + +import ( + "encoding/json" + "errors" + "strings" + "testing" + + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/dataframe/compiler/lower" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataframe/recipe/engine" + "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/explorer/capability" +) + +func TestValidateAuthorizedReceiptExecutionAcceptsExactRetainedGeneration(t *testing.T) { + scope := authscope.ReadScope{Mode: authscope.ReadScopeRestricted, AuthResourcePaths: []string{"path-a"}} + snapshot := testAuthorizedCapabilitySnapshot(t, "generation-old", scope) + receipt := testSecurityReceipt(t, snapshot, "patients", []string{"id"}) + if err := validateAuthorizedReceiptExecution(receipt, AuthorizedCapability{Snapshot: snapshot, Scope: scope}); err != nil { + t.Fatal(err) + } +} + +func TestValidateAuthorizedReceiptExecutionRejectsChangedTokenGenerationSchemaOrScope(t *testing.T) { + scope := authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted} + snapshot := testAuthorizedCapabilitySnapshot(t, "generation-a", scope) + receipt := testSecurityReceipt(t, snapshot, "patients", []string{"id"}) + cases := map[string]func(*explorer.CompilationReceipt, *capability.Snapshot, *authscope.ReadScope){ + "token": func(r *explorer.CompilationReceipt, _ *capability.Snapshot, _ *authscope.ReadScope) { + r.SnapshotToken = "different-token" + }, + "generation": func(_ *explorer.CompilationReceipt, s *capability.Snapshot, _ *authscope.ReadScope) { + s.Identity.Generation = "generation-b" + }, + "schema": func(_ *explorer.CompilationReceipt, s *capability.Snapshot, _ *authscope.ReadScope) { + s.Identity.SchemaDigest = "different-schema" + }, + "scope": func(_ *explorer.CompilationReceipt, _ *capability.Snapshot, s *authscope.ReadScope) { + s.Mode = authscope.ReadScopeRestricted + }, + } + for name, mutate := range cases { + t.Run(name, func(t *testing.T) { + candidateReceipt := *receipt + candidateSnapshot := snapshot.Clone() + candidateScope := scope.Clone() + mutate(&candidateReceipt, &candidateSnapshot, &candidateScope) + err := validateAuthorizedReceiptExecution(&candidateReceipt, AuthorizedCapability{Snapshot: candidateSnapshot, Scope: candidateScope}) + if !errors.Is(err, ErrReceiptExecutionContract) { + t.Fatalf("error=%v, want ErrReceiptExecutionContract", err) + } + }) + } +} + +func TestValidateAuthorizedReadScopePreservesRestrictedEmpty(t *testing.T) { + expected := explorerScopeDigest(authscope.ReadScope{Mode: authscope.ReadScopeRestricted}) + if err := validateAuthorizedReadScope(authscope.ReadScope{Mode: authscope.ReadScopeRestricted}, expected); err != nil { + t.Fatalf("restricted-empty scope rejected: %v", err) + } + if err := validateAuthorizedReadScope(authscope.ReadScope{}, expected); !errors.Is(err, ErrReceiptExecutionContract) { + t.Fatalf("empty scope error=%v, want contract mismatch", err) + } + if err := validateAuthorizedReadScope(authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}, expected); !errors.Is(err, ErrReceiptExecutionContract) { + t.Fatalf("widened scope error=%v, want contract mismatch", err) + } +} + +func TestValidateReceiptOutputContract(t *testing.T) { + snapshot := testAuthorizedCapabilitySnapshot(t, "generation-a", authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}) + receipt := testSecurityReceipt(t, snapshot, "patients", []string{"id"}) + if err := validateReceiptOutputContract(receipt, "patients"); err != nil { + t.Fatal(err) + } + if err := validateReceiptOutputContract(receipt, "observations"); !errors.Is(err, ErrReceiptExecutionContract) { + t.Fatalf("unknown output error=%v, want contract mismatch", err) + } + malformed := *receipt + malformed.PublicOutputContract = json.RawMessage(`{"outputId":"observations"}`) + if err := validateReceiptOutputContract(&malformed, "patients"); !errors.Is(err, ErrReceiptExecutionContract) { + t.Fatalf("forged output contract error=%v, want contract mismatch", err) + } +} + +func TestValidateReceiptEnginePublicColumnsUsesOrderedPublicColumnsOnly(t *testing.T) { + snapshot := testAuthorizedCapabilitySnapshot(t, "generation-a", authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}) + receipt := testSecurityReceipt(t, snapshot, "patients", []string{"id", "name"}) + resolved := engine.Resolved{Compiled: lower.CompiledRecipe{Outputs: []lower.CompiledRecipeOutput{{Name: "patients", OutputSchema: []lower.CompiledOutputColumn{{Name: "id"}, {Name: "__loom_row_id", Internal: true}, {Name: "name"}}}}}} + if err := validateReceiptEnginePublicColumns(receipt, resolved); err != nil { + t.Fatal(err) + } + wrongOrder := *receipt + wrongOrder.EmittedColumns = append([]explorer.EmittedColumn(nil), receipt.EmittedColumns...) + wrongOrder.EmittedColumns[0], wrongOrder.EmittedColumns[1] = wrongOrder.EmittedColumns[1], wrongOrder.EmittedColumns[0] + if err := validateReceiptEnginePublicColumns(&wrongOrder, resolved); !errors.Is(err, ErrReceiptExecutionContract) { + t.Fatalf("wrong column order error=%v, want contract mismatch", err) + } + hidden := *receipt + hidden.EmittedColumns = append([]explorer.EmittedColumn(nil), receipt.EmittedColumns...) + hidden.EmittedColumns[0].PublicColumn = "__loom_row_id" + if err := validateReceiptEnginePublicColumns(&hidden, resolved); !errors.Is(err, ErrReceiptExecutionContract) { + t.Fatalf("hidden-column error=%v, want contract mismatch", err) + } +} + +func testSecurityReceipt(t *testing.T, snapshot capability.Snapshot, output string, columns []string) *explorer.CompilationReceipt { + t.Helper() + fields := make([]recipe.Field, 0, len(columns)) + emitted := make([]explorer.EmittedColumn, 0, len(columns)) + contractColumns := make([]map[string]string, 0, len(columns)) + for _, column := range columns { + fields = append(fields, recipe.Field{Name: column, Expr: recipe.Expression{Select: "root." + column}}) + emitted = append(emitted, explorer.EmittedColumn{EmissionID: "em_" + column, OutputID: output, PublicColumn: column, LogicalType: "string"}) + contractColumns = append(contractColumns, map[string]string{"publicColumn": column}) + } + bundle := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "security", TranslationVersion: "test", Outputs: []recipe.Output{{Name: output, RootResourceType: "Patient", RowGrain: "resource", Fields: fields}}} + contract, err := json.Marshal(map[string]any{"outputId": output, "columns": contractColumns}) + if err != nil { + t.Fatal(err) + } + bundleDigest, err := bundle.Digest() + if err != nil { + t.Fatal(err) + } + receipt := &explorer.CompilationReceipt{ + Project: snapshot.Identity.Project, ExplorerID: "explorer-a", SnapshotToken: snapshot.Token, + AuthorizationScopeDigest: snapshot.Identity.AuthorizationScopeDigest, CapabilitySchemaDigest: snapshot.Identity.SchemaDigest, + SourceGeneration: snapshot.Identity.Generation, Bundle: bundle, PublicOutputContract: contract, + EmittedColumns: emitted, RecipeDigest: bundleDigest, ResolvedRecipeDigest: bundleDigest, + } + return receipt +} + +func TestReceiptExecutionContractErrorWrapsCause(t *testing.T) { + err := receiptExecutionContractError("generation %q changed", "generation-b") + if !errors.Is(err, ErrReceiptExecutionContract) || !strings.Contains(err.Error(), "generation-b") { + t.Fatalf("error=%v", err) + } +} diff --git a/internal/server/explorer_publication.go b/internal/server/explorer_publication.go index 9e55a340..464d7872 100644 --- a/internal/server/explorer_publication.go +++ b/internal/server/explorer_publication.go @@ -10,8 +10,49 @@ import ( materializationarango "github.com/calypr/loom/internal/dataframe/publication/arango" "github.com/calypr/loom/internal/dataframe/recipe" "github.com/calypr/loom/internal/dataframe/recipe/engine" + "github.com/calypr/loom/internal/explorer" ) +// explorerReceiptMaterializer keeps publication bound to the immutable +// compilation receipt. The receipt is the only artifact crossing the HTTP to +// execution boundary; its resolved recipe is lowered in memory by the engine. +func explorerReceiptMaterializer(recipeEngine *engine.Engine, target publication.Target, registry *materializationarango.Registry, degradation error, logger *slog.Logger, batchRows, batchBytes int) ExplorerV2ReceiptMaterializer { + return func(ctx context.Context, receipt *explorer.CompilationReceipt, bindings recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { + if receipt == nil { + return graphresolver.RecipeExecution{}, fmt.Errorf("compilation receipt is required") + } + if target == nil { + return graphresolver.RecipeExecution{}, fmt.Errorf("Explorer publication is unavailable: %w", degradation) + } + bindings.IncludeAuthResourcePath = true + var identity publication.BundleIdentity + _, err := recipeEngine.MaterializeResolvedBundle(ctx, receipt.Bundle, bindings, func(run context.Context, full engine.Resolved) error { + if validationErr := validateReceiptResolution(receipt, full); validationErr != nil { + return validationErr + } + var publishErr error + identity, publishErr = publishResolvedRecipe(run, recipeEngine, target, receipt.Bundle.Name, bindings, full, batchRows, batchBytes) + return publishErr + }) + if err != nil { + return graphresolver.RecipeExecution{}, err + } + published, err := registry.FindExecutionByKey(ctx, identity.Key()) + if err != nil { + return graphresolver.RecipeExecution{}, fmt.Errorf("load Explorer publication: %w", err) + } + outputs := make([]graphresolver.RecipeExecutionOutput, 0, len(published.Outputs)) + for _, output := range published.Outputs { + count := int(output.RowCount) + outputs = append(outputs, graphresolver.RecipeExecutionOutput{Name: output.Name, State: string(output.State.Canonical()), RowCount: &count, Columns: append([]publication.PhysicalColumn(nil), output.Columns...)}) + } + if logger != nil { + logger.Info("Explorer receipt materialization complete", "project", bindings.Project, "execution", published.ID) + } + return graphresolver.RecipeExecution{ID: published.ID, Name: receipt.Bundle.Name, RecipeDigest: published.RecipeDigest, ResolvedSchemaDigest: published.SchemaDigest, SourceGeneration: published.DatasetGeneration, State: string(published.State.Canonical()), Outputs: outputs}, nil + } +} + func explorerBundleMaterializer(recipeEngine *engine.Engine, target publication.Target, registry *materializationarango.Registry, degradation error, logger *slog.Logger, batchRows, batchBytes int) graphresolver.ExplorerBundleMaterializer { return func(ctx context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { if target == nil { diff --git a/internal/server/explorer_receipt_contract.go b/internal/server/explorer_receipt_contract.go new file mode 100644 index 00000000..0dab6c76 --- /dev/null +++ b/internal/server/explorer_receipt_contract.go @@ -0,0 +1,104 @@ +package server + +import ( + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "sort" + "strings" + + "github.com/calypr/loom/internal/dataframe/recipe/engine" + "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/explorer/capability" + explorercompilation "github.com/calypr/loom/internal/explorer/compilation" + "github.com/calypr/loom/internal/projectid" +) + +func compiledExplorerConfigV2(project, explorerID string, compiled explorercompilation.Result) ([]byte, error) { + if len(compiled.EmittedColumns) == 0 { + // An empty selection is a valid mutable editor state and may receive a + // receipt, but there is no valid interactive ExplorerConfig until the user + // selects a public column. Publication rejects this state explicitly. + return nil, nil + } + recipeJSON, err := json.Marshal(compiled.Bundle) + if err != nil { + return nil, fmt.Errorf("marshal compiled recipe: %w", err) + } + columns := append([]explorercompilation.PresentationColumn(nil), compiled.Presentation.Columns...) + sort.SliceStable(columns, func(i, j int) bool { + if columns[i].Order != columns[j].Order { + return columns[i].Order < columns[j].Order + } + return columns[i].EmissionID < columns[j].EmissionID + }) + table := make([]explorer.ConfigColumn, 0, len(columns)) + for _, column := range columns { + table = append(table, explorer.ConfigColumn{Column: column.PublicColumn, Label: column.Label, Visible: column.Visible}) + } + sum := sha256.Sum256([]byte(compiled.Presentation.OutputID)) + viewID := "view-" + hex.EncodeToString(sum[:])[:12] + config := explorer.ConfigV2{ + APIVersion: explorer.ConfigV2APIVersion, + Kind: "ExplorerConfig", + Project: projectid.Canonical(project), + Explorer: explorer.ConfigExplorer{ + ID: explorerID, Title: compiled.Presentation.Title, + Management: explorer.ConfigManagementForID(explorerID), + }, + Recipe: recipeJSON, + Views: []explorer.ConfigView{{ + ID: viewID, Title: compiled.Presentation.Title, + Output: compiled.Presentation.OutputID, + Table: explorer.ConfigTable{Columns: table}, + }}, + } + return json.Marshal(config) +} + +func validateReceiptCapability(receipt *explorer.CompilationReceipt, snapshot capability.Snapshot) error { + if receipt == nil { + return fmt.Errorf("compilation receipt is required") + } + if snapshot.Identity.Project != receipt.Project || snapshot.Identity.Generation != receipt.SourceGeneration { + return fmt.Errorf("receipt capability project or generation changed") + } + if snapshot.Identity.AuthorizationScopeDigest != receipt.AuthorizationScopeDigest { + return fmt.Errorf("receipt authorization scope changed") + } + if snapshot.Identity.SchemaDigest != receipt.CapabilitySchemaDigest { + return fmt.Errorf("receipt capability schema changed") + } + return nil +} + +// validateReceiptResolution proves that deterministic runtime lowering still +// describes the exact resolved semantic artifact frozen in the receipt. It +// intentionally compares no AQL or physical IR because those are +// request-scoped implementation details. +func validateReceiptResolution(receipt *explorer.CompilationReceipt, resolved engine.Resolved) error { + if receipt == nil { + return fmt.Errorf("compilation receipt is required") + } + digest, err := resolved.Bundle.Digest() + if err != nil { + return err + } + if digest != receipt.ResolvedRecipeDigest || resolved.StoredRecipeDigest != receipt.RecipeDigest { + return fmt.Errorf("receipt recipe digest does not match deterministic lowering") + } + if resolved.ResolvedSchemaDigest != receipt.ResolvedSchemaDigest { + return fmt.Errorf("receipt resolved schema digest does not match deterministic lowering") + } + want := resolvedOutputFingerprints(resolved) + if len(want) != len(receipt.OutputFingerprints) { + return fmt.Errorf("receipt output fingerprint set changed") + } + for output, fingerprint := range want { + if strings.TrimSpace(receipt.OutputFingerprints[output]) != fingerprint { + return fmt.Errorf("receipt output %q fingerprint changed", output) + } + } + return nil +} diff --git a/internal/server/explorer_receipt_contract_test.go b/internal/server/explorer_receipt_contract_test.go new file mode 100644 index 00000000..e0243d24 --- /dev/null +++ b/internal/server/explorer_receipt_contract_test.go @@ -0,0 +1,203 @@ +package server + +import ( + "context" + "encoding/json" + "net/http" + "strings" + "testing" + "time" + + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataframe/recipe/engine" + "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/explorer/authoringv2" + "github.com/calypr/loom/internal/explorer/capability" + explorercompilation "github.com/calypr/loom/internal/explorer/compilation" + "github.com/gofiber/fiber/v3" +) + +func TestCompiledExplorerConfigV2UsesCompilerOwnedPresentation(t *testing.T) { + bundle := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "compiled", TranslationVersion: explorercompilation.TranslationVersion, Outputs: []recipe.Output{{Name: "patients", RootResourceType: "Patient", RowGrain: "patient", Fields: []recipe.Field{{Name: "c_one", Expr: recipe.Expression{Select: "root.id"}}}}}} + compiled := explorercompilation.Result{ + Bundle: bundle, + EmittedColumns: []explorercompilation.EmittedColumn{{EmissionID: "em_one", OutputID: "patients", PublicColumn: "c_one"}}, + Presentation: explorercompilation.PresentationConfig{OutputID: "patients", Title: "Patients", Columns: []explorercompilation.PresentationColumn{{EmissionID: "em_one", PublicColumn: "c_one", Label: "Patient ID", Visible: true}}}, + } + raw, err := compiledExplorerConfigV2("project-a", "custom", compiled) + if err != nil { + t.Fatal(err) + } + config, decoded, err := explorer.DecodeInteractiveConfigV2(raw, "project-a", "custom") + if err != nil { + t.Fatal(err) + } + if decoded.Name != bundle.Name || len(config.Views) != 1 || config.Views[0].Table.Columns[0].Label != "Patient ID" { + t.Fatalf("compiled config = %#v, recipe = %#v", config, decoded) + } +} + +func TestNativeV2RouteUsesAuthorizedPersistedReceipt(t *testing.T) { + snapshot := testAuthoringV2CapabilitySnapshot() + scope := authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted} + executionScope := scope + store := explorer.NewMemoryStore() + service, err := explorer.NewService(store) + if err != nil { + t.Fatal(err) + } + if _, err := service.CreateEmptyInteractive(context.Background(), "project-a", "custom", "Custom", "test"); err != nil { + t.Fatal(err) + } + compileCalls := 0 + previewCalls := 0 + config := ExplorerV2LifecycleConfig{ + Capability: func(context.Context, string, string, string) (capability.Snapshot, error) { return snapshot, nil }, + CapabilityToken: func(context.Context, string, string) (capability.Snapshot, error) { return snapshot, nil }, + AuthorizedCapabilityCompile: func(_ context.Context, _, token string) (AuthorizedCapability, error) { + if err := snapshot.ValidateToken(token); err != nil { + return AuthorizedCapability{}, err + } + return AuthorizedCapability{Snapshot: snapshot, Scope: scope}, nil + }, + AuthorizedCapabilityExecution: func(context.Context, string, string) (AuthorizedCapability, error) { + return AuthorizedCapability{Snapshot: snapshot, Scope: executionScope}, nil + }, + ReceiptLookup: service.CompilationReceiptForExplorer, + CompileReceipt: func(ctx context.Context, request ExplorerV2ReceiptCompileRequest) (*explorer.CompilationReceipt, error) { + compileCalls++ + if request.Authorized.Snapshot.Token != snapshot.Token || !request.Authorized.Scope.Unrestricted() { + t.Fatalf("compile lost authorized capability: %#v", request.Authorized) + } + return persistTestNativeReceipt(ctx, t, service, request, snapshot) + }, + PreviewReceipt: func(_ context.Context, receipt *explorer.CompilationReceipt, bindings recipe.RuntimeBindings, visit func(map[string]any) error) (engine.PreviewSummary, error) { + previewCalls++ + if receipt == nil || bindings.AuthScopeMode != authscope.ReadScopeUnrestricted || bindings.IncludeAuthResourcePath { + t.Fatalf("preview bindings widened or requested publication metadata: receipt=%#v bindings=%#v", receipt, bindings) + } + if err := visit(map[string]any{"c_patient": "patient-1"}); err != nil { + return engine.PreviewSummary{}, err + } + return engine.PreviewSummary{Output: "patients", Columns: []string{"c_patient"}, RowCount: 1, PlanMode: "physical", PlanProfile: "generic_fhir_graph_recipe", PlanFingerprint: "test", TraversalCount: 0}, nil + }, + } + app := fiber.New() + RegisterExplorerAuthoringV2Routes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, config) + body := `{"document":{"apiVersion":"` + authoringv2.APIVersion + `","kind":"` + authoringv2.Kind + `","output":{"id":"patients","title":"Patients"},"rootNodeId":"n_patient","routeSteps":[],"selections":[{"candidateId":"c_patient_id","occurrenceId":"base","projectionMode":"FIRST"}],"presentation":{}},"snapshotToken":"` + snapshot.Token + `"}` + compiled := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/compile", body) + if compiled.StatusCode != http.StatusOK { + t.Fatalf("compile status=%d body=%s", compiled.StatusCode, compiled.Body) + } + var result struct { + ReceiptID string `json:"receiptId"` + } + if err := json.Unmarshal([]byte(compiled.Body), &result); err != nil { + t.Fatal(err) + } + preview := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/preview", `{"receiptId":"`+result.ReceiptID+`","outputId":"patients","limit":5}`) + if preview.StatusCode != http.StatusOK { + t.Fatalf("preview status=%d body=%s", preview.StatusCode, preview.Body) + } + if compileCalls != 1 || previewCalls != 1 { + t.Fatalf("compile calls=%d preview calls=%d", compileCalls, previewCalls) + } + unknown := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/preview", `{"receiptId":"`+result.ReceiptID+`","outputId":"missing","limit":5}`) + if unknown.StatusCode != http.StatusUnprocessableEntity || !strings.Contains(unknown.Body, `"code":"UNKNOWN_AUTHORING_OUTPUT"`) || previewCalls != 1 { + t.Fatalf("unknown output status=%d calls=%d body=%s", unknown.StatusCode, previewCalls, unknown.Body) + } + for _, path := range []string{ + "/api/v1/projects/project-b/explorers/custom/authoring/v2/preview", + "/api/v1/projects/project-a/explorers/other/authoring/v2/preview", + } { + foreign := requestJSON(t, app, http.MethodPost, path, `{"receiptId":"`+result.ReceiptID+`","outputId":"patients","limit":5}`) + if foreign.StatusCode != http.StatusNotFound || !strings.Contains(foreign.Body, `"code":"RECEIPT_NOT_FOUND"`) || previewCalls != 1 { + t.Fatalf("foreign receipt path=%s status=%d calls=%d body=%s", path, foreign.StatusCode, previewCalls, foreign.Body) + } + } + executionScope = authscope.ReadScope{Mode: authscope.ReadScopeRestricted} + widened := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/preview", `{"receiptId":"`+result.ReceiptID+`","outputId":"patients","limit":5}`) + if widened.StatusCode != http.StatusConflict || !strings.Contains(widened.Body, `"code":"RECEIPT_INPUT_UNAVAILABLE"`) || previewCalls != 1 { + t.Fatalf("scope mismatch status=%d calls=%d body=%s", widened.StatusCode, previewCalls, widened.Body) + } + stats, err := service.CompilationReceiptStats(context.Background(), "project-a") + if err != nil || stats.Count != 1 { + t.Fatalf("receipt stats=%+v err=%v", stats, err) + } +} + +func TestBuilderReadRestoresPublishedNativeV2Document(t *testing.T) { + snapshot := testAuthoringV2CapabilitySnapshot() + store := explorer.NewMemoryStore() + service, err := explorer.NewService(store) + if err != nil { + t.Fatal(err) + } + if _, err := service.CreateEmptyInteractive(context.Background(), "project-a", "custom", "Custom", "test"); err != nil { + t.Fatal(err) + } + document := authoringv2.Document{APIVersion: authoringv2.APIVersion, Kind: authoringv2.Kind, Output: authoringv2.Output{ID: "patients", Title: "Patients"}, RootNodeID: "n_patient", RouteSteps: []authoringv2.RouteStep{}, Selections: []authoringv2.Selection{{CandidateID: "c_patient_id", OccurrenceID: authoringv2.RootOccurrenceID, ProjectionMode: "FIRST"}}, Presentation: map[string]authoringv2.Presentation{}} + receipt, err := persistTestNativeReceipt(context.Background(), t, service, ExplorerV2ReceiptCompileRequest{Project: "project-a", ExplorerID: "custom", Document: document, SnapshotToken: snapshot.Token}, snapshot) + if err != nil { + t.Fatal(err) + } + now := time.Now().UTC() + if _, err := service.PublishAuthoring(context.Background(), *receipt, explorer.Revision{ID: "native-v2-revision", Project: "project-a", ExplorerID: "custom", CompilationReceiptID: receipt.ID, IntentDigest: receipt.IntentDigest, AuthoringBundle: receipt.NormalizedBundle, Recipe: receipt.Bundle, RecipeDigest: receipt.RecipeDigest, ResolvedSchemaDigest: receipt.ResolvedSchemaDigest, SourceGeneration: receipt.SourceGeneration, Status: explorer.RevisionReady, CreatedAt: now}); err != nil { + t.Fatal(err) + } + app := fiber.New() + RegisterExplorerAuthoringV2Routes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{Capability: func(context.Context, string, string, string) (capability.Snapshot, error) { return snapshot, nil }}) + response := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v2/builder", "") + if response.StatusCode != http.StatusOK { + t.Fatalf("builder status=%d body=%s", response.StatusCode, response.Body) + } + var state authoringv2.BuilderState + if err := json.Unmarshal([]byte(response.Body), &state); err != nil { + t.Fatal(err) + } + if state.Document == nil || state.Document.Output.ID != document.Output.ID || state.Document.Selections[0].CandidateID != document.Selections[0].CandidateID { + t.Fatalf("restored document = %#v", state.Document) + } +} + +func persistTestNativeReceipt(ctx context.Context, t *testing.T, service *explorer.Service, request ExplorerV2ReceiptCompileRequest, snapshot capability.Snapshot) (*explorer.CompilationReceipt, error) { + t.Helper() + normalized, err := request.Document.CanonicalJSON() + if err != nil { + return nil, err + } + intentDigest, err := request.Document.Digest() + if err != nil { + return nil, err + } + bundle := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "native-test", TranslationVersion: explorercompilation.TranslationVersion, Outputs: []recipe.Output{{Name: "patients", RootResourceType: "Patient", RowGrain: "patient", Fields: []recipe.Field{{Name: "c_patient", Expr: recipe.Expression{Select: "root.id"}}}}}} + bundleDigest, err := bundle.Digest() + if err != nil { + return nil, err + } + contract := json.RawMessage(`{"outputId":"patients","columns":[{"emissionId":"em_patient","publicColumn":"c_patient","candidateId":"c_patient_id","occurrenceId":"base","logicalType":"string","filterable":true,"chartable":true}]}`) + contractDigest, err := explorer.CompilationArtifactDigest(contract) + if err != nil { + return nil, err + } + receipt := explorer.CompilationReceipt{ + ReceiptFormatVersion: explorer.CurrentReceiptFormatVersion, CompilerContractVersion: explorer.CurrentCompilerContractVersion, + Project: snapshot.Identity.Project, ExplorerID: request.ExplorerID, IntentDigest: intentDigest, SnapshotToken: snapshot.Token, + AuthorizationScopeDigest: snapshot.Identity.AuthorizationScopeDigest, CapabilitySchemaDigest: snapshot.Identity.SchemaDigest, + SourceGeneration: snapshot.Identity.Generation, RecipeDigest: bundleDigest, ResolvedRecipeDigest: bundleDigest, + ResolvedSchemaDigest: "resolved-schema", OutputContractDigest: contractDigest, + NormalizedBundle: normalized, Bundle: bundle, PublicOutputContract: contract, + EmittedColumns: []explorer.EmittedColumn{{EmissionID: "em_patient", OutputID: "patients", CandidateID: "c_patient_id", OccurrenceID: authoringv2.RootOccurrenceID, PublicColumn: "c_patient", LogicalType: "string", Filterable: true, Chartable: true}}, + OutputFingerprints: map[string]string{"patients": "fingerprint"}, CreatedAt: time.Now().UTC(), + } + receipt.CompilationKey, err = explorer.CompilationKey(receipt) + if err != nil { + return nil, err + } + receipt.ID, err = explorer.ReceiptID(receipt) + if err != nil { + return nil, err + } + return service.StoreCompilationReceipt(ctx, receipt) +} diff --git a/internal/server/explorer_v2_engine.go b/internal/server/explorer_v2_engine.go index b7ed307a..5fc0366e 100644 --- a/internal/server/explorer_v2_engine.go +++ b/internal/server/explorer_v2_engine.go @@ -12,6 +12,7 @@ import ( "github.com/calypr/loom/internal/dataframe/recipe" "github.com/calypr/loom/internal/dataframe/recipe/engine" "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/projectid" ) type explorerV2CatalogReader func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) @@ -70,7 +71,7 @@ func explorerV2Compiler(recipeEngine *engine.Engine, catalogReader explorerV2Cat if recipeEngine == nil { return ExplorerV2CompileResult{Config: canonical, Bundle: bundle, RecipeDigest: digest, SourceGeneration: sourceGeneration}, nil } - resolved, err := recipeEngine.ResolveBundle(ctx, bundle, recipe.RuntimeBindings{Project: request.Project, DatasetGeneration: sourceGeneration}) + resolved, err := recipeEngine.ResolveBundle(ctx, bundle, recipe.RuntimeBindings{Project: projectid.Legacy(request.Project), DatasetGeneration: sourceGeneration}) if err != nil { return ExplorerV2CompileResult{}, err } @@ -83,10 +84,15 @@ func explorerV2Compiler(recipeEngine *engine.Engine, catalogReader explorerV2Cat emitted = append(emitted, explorer.EmittedColumn{OutputID: output.Name, PublicColumn: column.Name, SelectionID: column.SemanticPath, LogicalType: column.Kind, Filterable: true, Chartable: true}) } } - if err := synchronizeExplorerV2Views(cfg, resolved.Compiled.Outputs); err != nil { + cfg, presentationDiagnostics, err := synchronizeExplorerV2Views(cfg, resolved.Compiled.Outputs) + if err != nil { return ExplorerV2CompileResult{}, err } - return ExplorerV2CompileResult{Config: canonical, Bundle: bundle, RecipeDigest: resolved.StoredRecipeDigest, ResolvedSchemaDigest: resolved.ResolvedSchemaDigest, SourceGeneration: resolved.Compiled.SourceGeneration, OutputFingerprints: resolvedOutputFingerprints(resolved), EmittedColumns: emitted}, nil + repairedConfig, err := json.Marshal(cfg) + if err != nil { + return ExplorerV2CompileResult{}, fmt.Errorf("marshal repaired ExplorerConfigV2: %w", err) + } + return ExplorerV2CompileResult{Config: repairedConfig, Bundle: bundle, RecipeDigest: resolved.StoredRecipeDigest, ResolvedSchemaDigest: resolved.ResolvedSchemaDigest, SourceGeneration: resolved.Compiled.SourceGeneration, OutputFingerprints: resolvedOutputFingerprints(resolved), EmittedColumns: emitted, Diagnostics: presentationDiagnostics}, nil } } @@ -128,7 +134,7 @@ func catalogSelectionForREST(c explorer.Catalog, id string) (explorer.CatalogSel return value, ok } -func synchronizeExplorerV2Views(cfg explorer.ConfigV2, outputs []lower.CompiledRecipeOutput) error { +func synchronizeExplorerV2Views(cfg explorer.ConfigV2, outputs []lower.CompiledRecipeOutput) (explorer.ConfigV2, []explorer.Diagnostic, error) { columns := map[string]map[string]bool{} for _, output := range outputs { columns[output.Name] = map[string]bool{} @@ -136,26 +142,6 @@ func synchronizeExplorerV2Views(cfg explorer.ConfigV2, outputs []lower.CompiledR columns[output.Name][column] = true } } - for _, view := range cfg.Views { - available, ok := columns[view.Output] - if !ok { - return fmt.Errorf("view %q references unsupported output %q", view.ID, view.Output) - } - for _, column := range view.Table.Columns { - if !available[column.Column] { - return fmt.Errorf("view %q references missing output column %q", view.ID, column.Column) - } - } - for _, filter := range view.Filters { - if !available[filter.Column] { - return fmt.Errorf("view %q references missing filter column %q", view.ID, filter.Column) - } - } - for _, chart := range view.Charts { - if !available[chart.Column] { - return fmt.Errorf("view %q references missing chart column %q", view.ID, chart.Column) - } - } - } - return nil + repaired, diagnostics, err := explorer.RepairConfigV2Presentation(cfg, columns) + return repaired, diagnostics, err } diff --git a/internal/server/explorer_v2_engine_test.go b/internal/server/explorer_v2_engine_test.go index 0b6bc7cf..b403c31f 100644 --- a/internal/server/explorer_v2_engine_test.go +++ b/internal/server/explorer_v2_engine_test.go @@ -57,7 +57,7 @@ func TestExplorerV2CompilerUsesActiveGenerationWithoutSnapshotToken(t *testing.T } configV2.Views = []explorer.ConfigView{{ ID: "documents", Title: "Documents", Output: "DocumentReference", - Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "id", Label: "ID", Visible: true}}}, + Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "id", Label: "ID", Visible: true}, {Column: "category_coding_code", Label: "Legacy", Visible: true}}}, }} config, err := json.Marshal(configV2) if err != nil { @@ -74,6 +74,16 @@ func TestExplorerV2CompilerUsesActiveGenerationWithoutSnapshotToken(t *testing.T if result.SourceGeneration != "generation-live" || resolvedGeneration != "generation-live" { t.Fatalf("compiler generation = %q, resolver generation = %q; want generation-live", result.SourceGeneration, resolvedGeneration) } + var repaired explorer.ConfigV2 + if err := json.Unmarshal(result.Config, &repaired); err != nil { + t.Fatal(err) + } + if len(repaired.Views) != 1 || len(repaired.Views[0].Table.Columns) != 1 || repaired.Views[0].Table.Columns[0].Column != "id" { + t.Fatalf("stale presentation was not removed: %#v", repaired.Views) + } + if len(result.Diagnostics) != 1 || result.Diagnostics[0].Code != "STALE_PRESENTATION_REFERENCE" { + t.Fatalf("repair diagnostics = %#v", result.Diagnostics) + } } func TestExplorerV2CompilerResolvesRootCandidatesForRequestedOutput(t *testing.T) { diff --git a/internal/server/explorer_v2_lifecycle.go b/internal/server/explorer_v2_lifecycle.go index 97603edf..66c618ed 100644 --- a/internal/server/explorer_v2_lifecycle.go +++ b/internal/server/explorer_v2_lifecycle.go @@ -7,6 +7,7 @@ import ( "fmt" "log/slog" "net/http" + "net/url" "sort" "strings" "time" @@ -15,8 +16,11 @@ import ( "github.com/calypr/loom/internal/authscope" "github.com/calypr/loom/internal/dataframe/publication" "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataframe/recipe/engine" "github.com/calypr/loom/internal/dataset" "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/explorer/authoringv2" + "github.com/calypr/loom/internal/projectid" "github.com/gofiber/fiber/v3" ) @@ -26,6 +30,7 @@ import ( type ExplorerV2CompileRequest struct { Project string ExplorerID string + RequestID string Config []byte SnapshotToken string SelectedCandidateIDsByNode map[string][]string @@ -46,30 +51,77 @@ type ExplorerV2CompileResult struct { type ExplorerV2Compiler func(context.Context, ExplorerV2CompileRequest) (ExplorerV2CompileResult, error) type ExplorerV2Previewer func(context.Context, recipe.Bundle, recipe.RuntimeBindings) (map[string][]map[string]any, error) type ExplorerV2Materializer = graphresolver.ExplorerBundleMaterializer + +// ExplorerV2ReceiptCompileRequest is the native V2 compile request. The +// compiler owns canonicalization, capability validation, and persistence of +// the immutable receipt before returning it to the HTTP layer. +type ExplorerV2ReceiptCompileRequest struct { + Project string + ExplorerID string + Document authoringv2.Document + SnapshotToken string + RequestID string + // Authorized is the exact active capability already resolved by the HTTP + // boundary. Production compilation reuses it so idempotent editor compiles + // do not repeat manifest and authorization discovery. + Authorized AuthorizedCapability +} + +type ExplorerV2ReceiptCompiler func(context.Context, ExplorerV2ReceiptCompileRequest) (*explorer.CompilationReceipt, error) +type ExplorerV2ReceiptReader func(context.Context, string, string, string) (*explorer.CompilationReceipt, error) + +// ExplorerV2ReceiptPreviewer is the bounded transport seam. The +// engine invokes visitor once per public row and returns summary metadata; +// handlers can encode rows without retaining an unbounded result map. +type ExplorerV2ReceiptPreviewer func(context.Context, *explorer.CompilationReceipt, recipe.RuntimeBindings, func(map[string]any) error) (engine.PreviewSummary, error) + +type ExplorerV2ReceiptMaterializer func(context.Context, *explorer.CompilationReceipt, recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) type ExplorerV2GenerationValidator func(context.Context, string, string) error type ExplorerV2ReleaseActivator func(context.Context, string, string, []dataset.DataframeSelector) error +type ExplorerAuthoringV1Compiler func(context.Context, ExplorerAuthoringV1CompileRequest) (ExplorerAuthoringV1CompileResult, error) // ExplorerV2LifecycleConfig contains explicit capabilities for the REST // surface. The HTTP layer does not reach into catalog, compiler, or storage // internals. type ExplorerV2LifecycleConfig struct { - Compile ExplorerV2Compiler - Catalog explorerV2CatalogReader - Preview ExplorerV2Previewer - Materialize ExplorerV2Materializer - Logger *slog.Logger + Compile ExplorerV2Compiler + // CompileReceipt is the production V2 authoring compiler. It returns only + // after the receipt has been durably persisted. + CompileReceipt ExplorerV2ReceiptCompiler + Catalog explorerV2CatalogReader + // Capability and CapabilityToken expose the compiler-owned immutable V2 + // snapshot. Catalog remains an internal V1 migration projection only. + Capability ExplorerCapabilityReader + CapabilityToken ExplorerCapabilityTokenReader + AuthorizedCapabilityCompile ExplorerAuthorizedCapabilityCompilationReader + AuthorizedCapabilityExecution ExplorerAuthorizedCapabilityExecutionReader + Preview ExplorerV2Previewer + PreviewReceipt ExplorerV2ReceiptPreviewer + Materialize ExplorerV2Materializer + MaterializeReceipt ExplorerV2ReceiptMaterializer + // ReceiptLookup must enforce project and Explorer tenancy in the backing + // repository. The legacy service lookup remains a compatibility fallback + // for older tests and stored-document migration. + ReceiptLookup ExplorerV2ReceiptReader + Logger *slog.Logger // ValidateReleaseGeneration preflights the immutable snapshot required by // release activation before Publish performs expensive materialization. ValidateReleaseGeneration ExplorerV2GenerationValidator // Publish invokes ActivateRelease when the draft requires outputs that are // not already present in the active dataset release. ActivateRelease ExplorerV2ReleaseActivator + // AuthoringCompile accepts only V1 authoring intent. It is separate from + // Compile, which remains the repository/ETL packet seam. + AuthoringCompile ExplorerAuthoringV1Compiler } type explorerV2State struct { - Project string `json:"project"` - ExplorerID string `json:"explorerId"` - Management explorer.ManagementMode `json:"management"` + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + Title string `json:"-"` + Management explorer.ManagementMode `json:"management"` + ActiveAuthoringBundle json.RawMessage `json:"-"` + ActiveIntentDigest string `json:"-"` // BaselineConfig is present for the repository default. It is the // presentation-free recipe/schema projection of the current default draft. BaselineConfig json.RawMessage `json:"baselineConfig,omitempty"` @@ -93,13 +145,13 @@ type explorerV2State struct { UpdatedAt time.Time `json:"updatedAt"` } -func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, explorers *explorer.Service, capabilities ExplorerV2LifecycleConfig) { +func registerLegacyExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, explorers *explorer.Service, capabilities ExplorerV2LifecycleConfig) { if app == nil || authorizer == nil || authorizeRead == nil || explorers == nil { return } app.Get("/api/v1/projects/:project/explorers", func(c fiber.Ctx) error { - project := strings.TrimSpace(c.Params("project")) + project := explorerProjectParam(c) if err := authorizeRead(c.Context(), principalFromFiber(c), project); err != nil { return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") } @@ -107,11 +159,15 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author if err != nil { return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error()) } - return c.JSON(values) + states := make([]explorer.ExplorerStateV1, 0, len(values)) + for _, value := range values { + states = append(states, stateV1FromExplorerV2State(value)) + } + return c.JSON(states) }) app.Get("/api/v1/projects/:project/explorers/:explorerId", func(c fiber.Ctx) error { - project, id := strings.TrimSpace(c.Params("project")), strings.TrimSpace(c.Params("explorerId")) + project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) if err := authorizeRead(c.Context(), principalFromFiber(c), project); err != nil { return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") } @@ -122,10 +178,10 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author if err != nil { return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error()) } - return c.JSON(value) + return c.JSON(stateV1FromExplorerV2State(value)) }) app.Get("/api/v1/projects/:project/explorers/:explorerId/authoring/catalog", func(c fiber.Ctx) error { - project, id := strings.TrimSpace(c.Params("project")), strings.TrimSpace(c.Params("explorerId")) + project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) if err := authorizeRead(c.Context(), principalFromFiber(c), project); err != nil { return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") } @@ -163,7 +219,7 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author }) app.Post("/api/v1/projects/:project/explorers", func(c fiber.Ctx) error { - project := strings.TrimSpace(c.Params("project")) + project := explorerProjectParam(c) if err := authorizeExplorerWrite(c, authorizer, project); err != nil { return err } @@ -224,7 +280,7 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author }) app.Put("/api/v1/projects/:project/explorers/:explorerId/draft", func(c fiber.Ctx) error { - project, id := strings.TrimSpace(c.Params("project")), strings.TrimSpace(c.Params("explorerId")) + project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) if err := authorizeExplorerWrite(c, authorizer, project); err != nil { return err } @@ -239,10 +295,26 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author } return explorerV2Error(c, http.StatusBadRequest, "MALFORMED_REQUEST", err.Error()) } - _, _, canonical, _, err := explorer.CanonicalConfigV2(request.Config, project, id, explorer.ConfigManagementForID(id)) + cfg, _, canonical, _, err := explorer.CanonicalConfigV2(request.Config, project, id, explorer.ConfigManagementForID(id)) if err != nil { return explorerV2Error(c, http.StatusUnprocessableEntity, "INVALID_CONFIG", err.Error()) } + var repairDiagnostics []explorer.Diagnostic + if owner, ownerErr := explorers.Get(c.Context(), project, id); ownerErr == nil { + if repaired, diagnostics, repairErr := explorer.RepairConfigV2Presentation(cfg, emittedColumnsByOutput(*owner)); repairErr != nil { + return explorerV2ErrorFromCause(c, http.StatusUnprocessableEntity, "INVALID_CONFIG", repairErr) + } else if len(diagnostics) > 0 { + repairDiagnostics = diagnostics + repairedRaw, marshalErr := json.Marshal(repaired) + if marshalErr != nil { + return explorerV2Error(c, http.StatusInternalServerError, "CONFIG_REPAIR_FAILED", marshalErr.Error()) + } + _, _, canonical, _, err = explorer.CanonicalConfigV2(repairedRaw, project, id, explorer.ConfigManagementForID(id)) + if err != nil { + return explorerV2Error(c, http.StatusUnprocessableEntity, "INVALID_CONFIG", err.Error()) + } + } + } value, err := explorers.SaveDraftV2(c.Context(), project, id, canonical, *request.ExpectedDraftVersion, request.ExpectedDraftDigest, subjectFromFiber(c)) if errors.Is(err, explorer.ErrDraftConflict) { return draftConflictResponse(c, explorers, project, id) @@ -253,11 +325,13 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author if err != nil { return explorerV2Error(c, http.StatusUnprocessableEntity, "DRAFT_SAVE_FAILED", err.Error()) } - return c.JSON(stateFromExplorer(value)) + state := stateFromExplorer(value) + state.Diagnostics = append(state.Diagnostics, repairDiagnostics...) + return c.JSON(state) }) app.Post("/api/v1/projects/:project/explorers/:explorerId/authoring/compile", func(c fiber.Ctx) error { - project, id := strings.TrimSpace(c.Params("project")), strings.TrimSpace(c.Params("explorerId")) + project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) if err := authorizeExplorerWrite(c, authorizer, project); err != nil { return err } @@ -271,9 +345,9 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author if err := decodeStrict(c.Body(), &request); err != nil { return explorerV2Error(c, http.StatusBadRequest, "MALFORMED_REQUEST", err.Error()) } - result, digest, err := compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, Config: request.Config, SnapshotToken: request.SnapshotToken, SelectedCandidateIDsByNode: request.SelectedCandidateIDsByNode, Output: request.Output}) + result, digest, err := compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, RequestID: requestIDFromFiber(c), Config: request.Config, SnapshotToken: request.SnapshotToken, SelectedCandidateIDsByNode: request.SelectedCandidateIDsByNode, Output: request.Output}) if err != nil { - return explorerV2Error(c, http.StatusUnprocessableEntity, "COMPILE_FAILED", err.Error()) + return explorerV2ErrorFromCause(c, http.StatusUnprocessableEntity, "COMPILE_FAILED", err) } diagnostics := result.Diagnostics if diagnostics == nil { @@ -287,7 +361,7 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author }) app.Post("/api/v1/projects/:project/explorers/:explorerId/preview", func(c fiber.Ctx) error { - project, id := strings.TrimSpace(c.Params("project")), strings.TrimSpace(c.Params("explorerId")) + project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) if err := authorizeRead(c.Context(), principalFromFiber(c), project); err != nil { return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") } @@ -306,7 +380,7 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author if request.Limit < 1 || request.Limit > 1000 { return explorerV2Error(c, http.StatusBadRequest, "INVALID_LIMIT", "limit must be between 1 and 1000") } - result, digest, err := compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, Config: request.Config, Output: request.Output}) + result, digest, err := compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, RequestID: requestIDFromFiber(c), Config: request.Config, Output: request.Output}) if err != nil { return previewFailure(c, digest, err) } @@ -316,16 +390,16 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author if capabilities.Preview == nil { return previewFailure(c, digest, fmt.Errorf("preview executor is not configured")) } - rows, err := capabilities.Preview(c.Context(), result.Bundle, recipe.RuntimeBindings{Project: project, PreviewLimit: request.Limit, DatasetGeneration: result.SourceGeneration, OutputNames: []string{request.Output}}) + rows, err := capabilities.Preview(c.Context(), result.Bundle, recipe.RuntimeBindings{Project: projectid.Legacy(project), PreviewLimit: request.Limit, DatasetGeneration: result.SourceGeneration, OutputNames: []string{request.Output}}) if err != nil { return previewFailure(c, digest, err) } selected := rows[request.Output] - return c.JSON(fiber.Map{"project": project, "explorerId": id, "output": request.Output, "columns": columnsForOutput(result, request.Output), "rows": selected, "rowCount": len(selected), "digest": digest, "diagnostics": result.Diagnostics}) + return c.JSON(fiber.Map{"project": project, "explorerId": id, "output": request.Output, "config": json.RawMessage(result.Config), "columns": columnsForOutput(result, request.Output), "rows": selected, "rowCount": len(selected), "digest": digest, "diagnostics": result.Diagnostics}) }) app.Post("/api/v1/projects/:project/explorers/:explorerId/publish", func(c fiber.Ctx) error { - project, id := strings.TrimSpace(c.Params("project")), strings.TrimSpace(c.Params("explorerId")) + project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) if err := authorizeExplorerWrite(c, authorizer, project); err != nil { return err } @@ -358,14 +432,14 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author if err != nil { return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error()) } - result, digest, err := compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, Config: owner.DraftConfig}) + result, digest, err := compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, RequestID: requestIDFromFiber(c), Config: owner.DraftConfig}) if err != nil { // A persisted canonical draft should compile. Retry against the // latest draft once so a concurrent last-write-wins save or a // transient catalog update does not become a user-facing 422. if latest, readErr := explorers.Get(c.Context(), project, id); readErr == nil { owner = latest - result, digest, err = compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, Config: owner.DraftConfig}) + result, digest, err = compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, RequestID: requestIDFromFiber(c), Config: owner.DraftConfig}) } if err != nil { return publishFailure(http.StatusInternalServerError, "PUBLISH_PIPELINE_FAILED", "the current Explorer draft could not be compiled", "COMPILE", fiber.Map{"draftVersion": owner.DraftVersion, "draftDigest": owner.DraftDigest, "cause": err.Error()}) @@ -409,7 +483,7 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author return publishFailure(http.StatusServiceUnavailable, "DATASET_BUILD_UNAVAILABLE", "publishing this Explorer requires a dataset build that is not configured", "MATERIALIZE_UNAVAILABLE", activeDatasetErrorDetails(activeErr, result.Bundle)) } if capabilities.ValidateReleaseGeneration != nil { - if validateErr := capabilities.ValidateReleaseGeneration(c.Context(), project, generation); validateErr != nil { + if validateErr := capabilities.ValidateReleaseGeneration(c.Context(), projectid.Legacy(project), generation); validateErr != nil { status, code, message := explorerReleaseFailure(validateErr, true) return publishFailure(status, code, message, "VALIDATE_DATASET_RELEASE", fiber.Map{"generation": generation, "cause": validateErr.Error()}) } @@ -417,7 +491,7 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author var executions []graphresolver.RecipeExecution for _, output := range changedOutputs { publishInfo("Explorer output materialization started", "output", output.Name) - execution, materializeErr := capabilities.Materialize(c.Context(), result.Bundle, recipe.RuntimeBindings{Project: project, DatasetGeneration: generation, OutputNames: []string{output.Name}}) + execution, materializeErr := capabilities.Materialize(c.Context(), result.Bundle, recipe.RuntimeBindings{Project: projectid.Legacy(project), DatasetGeneration: generation, OutputNames: []string{output.Name}}) if materializeErr != nil { return publishFailure(http.StatusServiceUnavailable, "DATASET_BUILD_FAILED", "the dataset could not be built for this Explorer", "MATERIALIZE", fiber.Map{"generation": generation, "output": output.Name, "cause": materializeErr.Error(), "details": activeDatasetErrorDetails(activeErr, result.Bundle)}) } @@ -428,7 +502,7 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author executions = append(executions, execution) } publishInfo("Explorer dataset release activation started", "outputs", recipeOutputNames(changedOutputs)) - if err := activateExplorerReleaseWithRetry(c.Context(), capabilities.ActivateRelease, project, generation, selectorsForOutputs(changedOutputs, result.Bundle)); err != nil { + if err := activateExplorerReleaseWithRetry(c.Context(), capabilities.ActivateRelease, projectid.Legacy(project), generation, selectorsForOutputs(changedOutputs, result.Bundle)); err != nil { status, code, message := explorerReleaseFailure(err, false) return publishFailure(status, code, message, "ACTIVATE_DATASET_RELEASE", fiber.Map{"generation": generation, "cause": err.Error(), "outputs": recipeOutputNames(changedOutputs)}) } @@ -899,6 +973,21 @@ func explorerV2Error(c fiber.Ctx, status int, code, message string) error { return c.Status(status).JSON(fiber.Map{"error": fiber.Map{"code": code, "message": message}}) } +func explorerV2ErrorFromCause(c fiber.Ctx, status int, code string, cause error) error { + var repairErr *explorer.PresentationRepairError + if errors.As(cause, &repairErr) { + diagnostic := repairErr.Diagnostic + if diagnostic.RequestID == "" { + diagnostic.RequestID = requestIDFromFiber(c) + } + return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{ + "error": fiber.Map{"code": diagnostic.Code, "message": diagnostic.Message, "fieldPath": diagnostic.FieldPath, "details": diagnostic.Details, "requestId": diagnostic.RequestID}, + "diagnostics": []explorer.Diagnostic{diagnostic}, + }) + } + return explorerV2Error(c, status, code, cause.Error()) +} + func explorerV2ErrorWithDetails(c fiber.Ctx, status int, code, message string, details any) error { body := fiber.Map{"code": code, "message": message, "details": details} if status == http.StatusServiceUnavailable || status == http.StatusConflict { @@ -989,10 +1078,16 @@ func compileExplorerV2(ctx context.Context, compiler ExplorerV2Compiler, request if len(result.Config) == 0 { result.Config = canonical } - if _, _, normalized, _, err := explorer.CanonicalConfigV2(result.Config, request.Project, request.ExplorerID, management); err != nil { + if _, _, normalized, normalizedDigest, err := explorer.CanonicalConfigV2(result.Config, request.Project, request.ExplorerID, management); err != nil { return ExplorerV2CompileResult{}, digest, err } else { result.Config = normalized + digest = normalizedDigest + } + for index := range result.Diagnostics { + if result.Diagnostics[index].RequestID == "" { + result.Diagnostics[index].RequestID = request.RequestID + } } if result.Bundle.Name == "" { result.Bundle = bundle @@ -1011,6 +1106,14 @@ func compileExplorerV2(ctx context.Context, compiler ExplorerV2Compiler, request func mustBundleDigest(bundle recipe.Bundle) string { digest, _ := bundle.Digest(); return digest } func previewFailure(c fiber.Ctx, digest string, err error) error { + var repairErr *explorer.PresentationRepairError + if errors.As(err, &repairErr) { + diagnostic := repairErr.Diagnostic + if diagnostic.RequestID == "" { + diagnostic.RequestID = requestIDFromFiber(c) + } + return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"outputColumns": []string{}, "rows": []map[string]any{}, "rowCount": 0, "digest": digest, "diagnostics": []explorer.Diagnostic{diagnostic}}) + } return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"outputColumns": []string{}, "rows": []map[string]any{}, "rowCount": 0, "digest": digest, "diagnostics": []explorer.Diagnostic{{Severity: "ERROR", Code: "PREVIEW_FAILED", Message: err.Error()}}}) } @@ -1047,6 +1150,36 @@ func columnsForOutput(result ExplorerV2CompileResult, output string) []string { return columns } +func emittedColumnsByOutput(value explorer.Explorer) map[string]map[string]bool { + columns := make(map[string]map[string]bool) + for _, emitted := range value.EmittedColumns { + if emitted.OutputID == "" || emitted.PublicColumn == "" { + continue + } + if columns[emitted.OutputID] == nil { + columns[emitted.OutputID] = make(map[string]bool) + } + columns[emitted.OutputID][emitted.PublicColumn] = true + } + if len(columns) != 0 { + return columns + } + for _, output := range value.Dataset.Outputs { + if output.Name == "" { + continue + } + if columns[output.Name] == nil { + columns[output.Name] = make(map[string]bool) + } + for _, column := range output.Columns { + if column.Name != "" { + columns[output.Name][column.Name] = true + } + } + } + return columns +} + func verifyQueryableOutputs(bundle recipe.Bundle, execution graphresolver.RecipeExecution) error { states := map[string]string{} for _, output := range execution.Outputs { @@ -1108,12 +1241,18 @@ func forkRepositoryConfig(raw []byte, project, id, title string) ([]byte, error) func getExplorerV2State(ctx context.Context, service *explorer.Service, project, id string) (*explorerV2State, error) { value, err := service.Get(ctx, project, id) if err == nil { + var repairDiagnostics []explorer.Diagnostic + if repaired, diagnostics, repairErr := repairExplorerDraftOnLoad(ctx, service, value); repairErr == nil { + value, repairDiagnostics = repaired, diagnostics + } state := stateFromExplorer(value) if value.ActiveRevisionID != "" { if revision, revisionErr := service.Revision(ctx, value.ActiveRevisionID); revisionErr == nil { state = mergeRevisionState(state, revision) } } + state.Diagnostics = append(state.Diagnostics, repairDiagnostics...) + state = repairActiveExplorerPresentation(state) return state, nil } if id != "default" || !errors.Is(err, explorer.ErrNotFound) { @@ -1131,7 +1270,95 @@ func getExplorerV2State(ctx context.Context, service *explorer.Service, project, if version == 0 { version = 1 } - return &explorerV2State{Project: project, ExplorerID: "default", Management: explorer.ManagementRepository, BaselineConfig: repositoryBaselineConfig(repository.Config), DraftConfig: cloneRaw(repository.Config), DraftVersion: version, DraftDigest: digest, ActiveConfig: cloneRaw(repository.Config), ActiveRevisionID: repository.ActiveRevisionID, SourceGeneration: repository.SourceGeneration, Materializations: repository.Materializations, Dataset: repository.Dataset, Publication: repository.Publication, Diagnostics: repository.Diagnostics, PublicationState: repository.Publication.State, ActiveURL: explorerURL(project, "default"), UpdatedAt: repository.UpdatedAt}, nil + state := &explorerV2State{Project: project, ExplorerID: "default", Title: configV2Title(repository.Config), Management: explorer.ManagementRepository, BaselineConfig: repositoryBaselineConfig(repository.Config), DraftConfig: cloneRaw(repository.Config), DraftVersion: version, DraftDigest: digest, ActiveConfig: cloneRaw(repository.Config), ActiveRevisionID: repository.ActiveRevisionID, SourceGeneration: repository.SourceGeneration, Materializations: repository.Materializations, Dataset: repository.Dataset, Publication: repository.Publication, Diagnostics: repository.Diagnostics, PublicationState: repository.Publication.State, ActiveURL: explorerURL(project, "default"), UpdatedAt: repository.UpdatedAt} + return repairActiveExplorerPresentation(state), nil +} + +func repairExplorerDraftOnLoad(ctx context.Context, service *explorer.Service, value *explorer.Explorer) (*explorer.Explorer, []explorer.Diagnostic, error) { + if value == nil || len(value.DraftConfig) == 0 { + return value, nil, nil + } + available := emittedColumnsByOutput(*value) + if len(available) == 0 { + return value, nil, nil + } + cfg, _, _, _, err := explorer.CanonicalConfigV2(value.DraftConfig, value.Project, value.ExplorerID, explorer.ConfigManagementForID(value.ExplorerID)) + if err != nil { + return value, nil, nil + } + repaired, diagnostics, repairErr := explorer.RepairConfigV2Presentation(cfg, available) + if repairErr != nil || len(diagnostics) == 0 { + return value, nil, repairErr + } + raw, err := json.Marshal(repaired) + if err != nil { + return value, nil, err + } + _, _, canonical, _, err := explorer.CanonicalConfigV2(raw, value.Project, value.ExplorerID, explorer.ConfigManagementForID(value.ExplorerID)) + if err != nil { + return value, nil, err + } + saved, err := service.SaveDraftV2(ctx, value.Project, value.ExplorerID, canonical, value.DraftVersion, value.DraftDigest, "loom-presentation-repair") + if err != nil { + return value, nil, err + } + return saved, diagnostics, nil +} + +func repairActiveExplorerPresentation(state *explorerV2State) *explorerV2State { + if state == nil || len(state.ActiveConfig) == 0 { + return state + } + available := make(map[string]map[string]bool) + for _, emitted := range state.EmittedColumns { + if emitted.OutputID == "" || emitted.PublicColumn == "" { + continue + } + if available[emitted.OutputID] == nil { + available[emitted.OutputID] = make(map[string]bool) + } + available[emitted.OutputID][emitted.PublicColumn] = true + } + if len(available) == 0 { + for _, output := range state.Dataset.Outputs { + if output.Name == "" { + continue + } + if available[output.Name] == nil { + available[output.Name] = make(map[string]bool) + } + for _, column := range output.Columns { + if column.Name != "" { + available[output.Name][column.Name] = true + } + } + } + } + if len(available) == 0 { + return state + } + cfg, _, _, _, err := explorer.CanonicalConfigV2(state.ActiveConfig, state.Project, state.ExplorerID, explorer.ConfigManagementForID(state.ExplorerID)) + if err != nil { + return state + } + repaired, diagnostics, repairErr := explorer.RepairConfigV2Presentation(cfg, available) + if repairErr != nil { + var presentationErr *explorer.PresentationRepairError + if errors.As(repairErr, &presentationErr) { + state.Diagnostics = append(state.Diagnostics, presentationErr.Diagnostic) + } + return state + } + if len(diagnostics) == 0 { + return state + } + raw, err := json.Marshal(repaired) + if err != nil { + return state + } + state.ActiveConfig = raw + state.Diagnostics = append(state.Diagnostics, diagnostics...) + return state } func listExplorerV2States(ctx context.Context, service *explorer.Service, project string) ([]*explorerV2State, error) { @@ -1182,14 +1409,17 @@ func listExplorerV2States(ctx context.Context, service *explorer.Service, projec } func stateFromExplorer(value *explorer.Explorer) *explorerV2State { + project := projectid.Canonical(value.Project) if value.ManagementMode == explorer.ManagementRepository { - return &explorerV2State{Project: value.Project, ExplorerID: value.ExplorerID, Management: value.ManagementMode, BaselineConfig: repositoryBaselineConfig(value.DraftConfig), DraftConfig: cloneRaw(value.DraftConfig), DraftVersion: value.DraftVersion, DraftDigest: value.DraftDigest, ActiveConfig: cloneRaw(value.ActiveConfig), ActiveRevisionID: value.ActiveRevisionID, RecipeDigest: value.RecipeDigest, ResolvedSchemaDigest: value.ResolvedSchemaDigest, SourceGeneration: value.SourceGeneration, EmittedColumns: append([]explorer.EmittedColumn(nil), value.EmittedColumns...), Materializations: append([]explorer.Materialization(nil), value.Materializations...), Dataset: value.Dataset, Publication: value.Publication, Diagnostics: append([]explorer.Diagnostic(nil), value.Diagnostics...), PublicationState: value.Publication.State, ActiveURL: explorerURL(value.Project, value.ExplorerID), UpdatedBy: value.UpdatedBy, UpdatedAt: value.UpdatedAt} + return &explorerV2State{Project: project, ExplorerID: value.ExplorerID, Title: value.Title, Management: value.ManagementMode, BaselineConfig: repositoryBaselineConfig(value.DraftConfig), DraftConfig: cloneRaw(value.DraftConfig), DraftVersion: value.DraftVersion, DraftDigest: value.DraftDigest, ActiveConfig: cloneRaw(value.ActiveConfig), ActiveRevisionID: value.ActiveRevisionID, RecipeDigest: value.RecipeDigest, ResolvedSchemaDigest: value.ResolvedSchemaDigest, SourceGeneration: value.SourceGeneration, EmittedColumns: append([]explorer.EmittedColumn(nil), value.EmittedColumns...), Materializations: append([]explorer.Materialization(nil), value.Materializations...), Dataset: value.Dataset, Publication: value.Publication, Diagnostics: append([]explorer.Diagnostic(nil), value.Diagnostics...), PublicationState: value.Publication.State, ActiveURL: explorerURL(project, value.ExplorerID), UpdatedBy: value.UpdatedBy, UpdatedAt: value.UpdatedAt} } - return &explorerV2State{Project: value.Project, ExplorerID: value.ExplorerID, Management: value.ManagementMode, DraftConfig: cloneRaw(value.DraftConfig), DraftVersion: value.DraftVersion, DraftDigest: value.DraftDigest, ActiveConfig: cloneRaw(value.ActiveConfig), ActiveRevisionID: value.ActiveRevisionID, RecipeDigest: value.RecipeDigest, ResolvedSchemaDigest: value.ResolvedSchemaDigest, SourceGeneration: value.SourceGeneration, EmittedColumns: append([]explorer.EmittedColumn(nil), value.EmittedColumns...), Materializations: append([]explorer.Materialization(nil), value.Materializations...), Dataset: value.Dataset, Publication: value.Publication, Diagnostics: append([]explorer.Diagnostic(nil), value.Diagnostics...), PublicationState: publicationState(value.ActiveRevisionID), ActiveURL: explorerURL(value.Project, value.ExplorerID), UpdatedBy: value.UpdatedBy, UpdatedAt: value.UpdatedAt} + return &explorerV2State{Project: project, ExplorerID: value.ExplorerID, Title: value.Title, Management: value.ManagementMode, DraftConfig: cloneRaw(value.DraftConfig), DraftVersion: value.DraftVersion, DraftDigest: value.DraftDigest, ActiveConfig: cloneRaw(value.ActiveConfig), ActiveRevisionID: value.ActiveRevisionID, RecipeDigest: value.RecipeDigest, ResolvedSchemaDigest: value.ResolvedSchemaDigest, SourceGeneration: value.SourceGeneration, EmittedColumns: append([]explorer.EmittedColumn(nil), value.EmittedColumns...), Materializations: append([]explorer.Materialization(nil), value.Materializations...), Dataset: value.Dataset, Publication: value.Publication, Diagnostics: append([]explorer.Diagnostic(nil), value.Diagnostics...), PublicationState: publicationState(value.ActiveRevisionID), ActiveURL: explorerURL(project, value.ExplorerID), UpdatedBy: value.UpdatedBy, UpdatedAt: value.UpdatedAt} } func mergeRevisionState(state *explorerV2State, revision *explorer.Revision) *explorerV2State { state.ActiveConfig = cloneRaw(revision.Config) + state.ActiveAuthoringBundle = cloneOptionalRaw(revision.AuthoringBundle) + state.ActiveIntentDigest = revision.IntentDigest state.RecipeDigest, state.ResolvedSchemaDigest, state.SourceGeneration = revision.RecipeDigest, revision.ResolvedSchemaDigest, revision.SourceGeneration state.EmittedColumns, state.Diagnostics = append([]explorer.EmittedColumn(nil), revision.EmittedColumns...), append([]explorer.Diagnostic(nil), revision.Diagnostics...) state.Materializations, state.Dataset = explorer.WithDataframeSelectors(revision.Recipe, revision.Materializations, revision.Dataset) @@ -1205,7 +1435,7 @@ func publicationState(id string) string { return string(explorer.RevisionActive) } func explorerURL(project, id string) string { - return "/api/v1/projects/" + project + "/explorers/" + id + return "/api/v1/projects/" + url.PathEscape(project) + "/explorers/" + url.PathEscape(id) } func cloneRaw(raw json.RawMessage) json.RawMessage { if len(raw) == 0 { @@ -1214,6 +1444,496 @@ func cloneRaw(raw json.RawMessage) json.RawMessage { return append(json.RawMessage(nil), raw...) } +func cloneOptionalRaw(raw json.RawMessage) json.RawMessage { + if len(raw) == 0 || strings.TrimSpace(string(raw)) == "" || strings.TrimSpace(string(raw)) == "null" { + return nil + } + return append(json.RawMessage(nil), raw...) +} + +func stateV1FromExplorerV2State(state *explorerV2State) explorer.ExplorerStateV1 { + result := explorer.ExplorerStateV1{ + APIVersion: explorer.ExplorerStateV1APIVersion, + Kind: explorer.ExplorerStateV1Kind, + Project: state.Project, + ExplorerID: state.ExplorerID, + Title: state.Title, + Management: state.Management, + ActiveURL: state.ActiveURL, + UpdatedBy: state.UpdatedBy, + UpdatedAt: state.UpdatedAt, + } + result.Draft = explorer.ExplorerStateV1Draft{ + Bundle: nil, + Version: state.DraftVersion, + Digest: state.DraftDigest, + IntentDigest: "", + ReceiptID: "", + } + result.Active = explorer.ExplorerStateV1Active{ + Bundle: canonicalAuthoringBundle(state.ActiveAuthoringBundle), + RevisionID: state.ActiveRevisionID, + IntentDigest: state.ActiveIntentDigest, + Status: state.Publication.State, + } + result.Generated = explorer.ExplorerStateV1Generated{ + RecipeDigest: state.RecipeDigest, + ResolvedSchemaDigest: state.ResolvedSchemaDigest, + SourceGeneration: state.SourceGeneration, + EmittedColumns: append([]explorer.EmittedColumn(nil), state.EmittedColumns...), + Materializations: append([]explorer.Materialization(nil), state.Materializations...), + Dataset: state.Dataset, + Publication: state.Publication, + Diagnostics: append([]explorer.Diagnostic(nil), state.Diagnostics...), + } + result.Runtime = runtimeV1FromExplorerV2State(state) + return result +} + +type runtimeProjectionState struct { + ActiveConfig json.RawMessage + SourceGeneration string + ResolvedSchemaDigest string + EmittedColumns []explorer.EmittedColumn + Materializations []explorer.Materialization + Dataset explorer.DatasetMetadata + Publication explorer.PublicationMetadata + Diagnostics []explorer.Diagnostic +} + +func runtimeV1FromPublishedRevision(revision *explorer.Revision) *explorer.ExplorerRuntimeV1 { + if revision == nil { + return nil + } + return runtimeV1FromProjection(runtimeProjectionState{ + ActiveConfig: revision.Config, + SourceGeneration: revision.SourceGeneration, + ResolvedSchemaDigest: revision.ResolvedSchemaDigest, + EmittedColumns: revision.EmittedColumns, + Materializations: revision.Materializations, + Dataset: revision.Dataset, + Publication: revision.Publication, + Diagnostics: revision.Diagnostics, + }) +} + +// runtimeV1FromExplorerV2State is retained only for legacy lifecycle tests and +// migration helpers. Registered runtime reads use runtimeV1FromPublishedRevision. +func runtimeV1FromExplorerV2State(legacy *explorerV2State) *explorer.ExplorerRuntimeV1 { + if legacy == nil { + return nil + } + return runtimeV1FromProjection(runtimeProjectionState{ + ActiveConfig: legacy.ActiveConfig, + SourceGeneration: legacy.SourceGeneration, + ResolvedSchemaDigest: legacy.ResolvedSchemaDigest, + EmittedColumns: legacy.EmittedColumns, + Materializations: legacy.Materializations, + Dataset: legacy.Dataset, + Publication: legacy.Publication, + Diagnostics: legacy.Diagnostics, + }) +} + +func runtimeV1FromProjection(state runtimeProjectionState) *explorer.ExplorerRuntimeV1 { + if len(state.ActiveConfig) == 0 { + return nil + } + var config explorer.ConfigV2 + if err := json.Unmarshal(state.ActiveConfig, &config); err != nil || len(config.Views) == 0 { + return nil + } + recipeLabels := explorerRecipeColumnLabels(config.Recipe) + + datasetOutputs := make(map[string]explorer.DatasetOutput, len(state.Dataset.Outputs)) + physicalColumns := make(map[string]map[string]publication.PhysicalColumn, len(state.Dataset.Outputs)) + for _, output := range state.Dataset.Outputs { + datasetOutputs[output.Name] = output + physicalColumns[output.Name] = make(map[string]publication.PhysicalColumn, len(output.Columns)) + for _, column := range output.Columns { + physicalColumns[output.Name][column.Name] = column + } + } + materializations := make(map[string]explorer.Materialization, len(state.Materializations)) + for _, materialization := range state.Materializations { + outputID := firstNonEmpty(materialization.OutputID, materialization.Output) + materializations[outputID] = materialization + if physicalColumns[outputID] == nil { + physicalColumns[outputID] = make(map[string]publication.PhysicalColumn, len(materialization.Columns)) + } + for _, column := range materialization.Columns { + physicalColumns[outputID][column.Name] = column + } + } + emittedColumns := make(map[string]map[string]explorer.EmittedColumn) + for _, emitted := range state.EmittedColumns { + if emitted.OutputID == "" || emitted.PublicColumn == "" { + continue + } + if emittedColumns[emitted.OutputID] == nil { + emittedColumns[emitted.OutputID] = make(map[string]explorer.EmittedColumn) + } + emittedColumns[emitted.OutputID][emitted.PublicColumn] = emitted + } + // Authoring emissions use stable logical names (c_), while the + // publication layer may qualify those names for the physical dataframe + // schema (for example patient_c_). Resolve that boundary from the + // authoritative published column list instead of asking the renderer to + // guess physical names. A suffix match is accepted only when it is + // unambiguous for the output. + publicToPhysical := make(map[string]map[string]string) + for outputID, emitted := range emittedColumns { + physical := physicalColumns[outputID] + if len(physical) == 0 { + continue + } + aliases := make(map[string]string) + for publicName, emission := range emitted { + logicalNames := []string{publicName} + // Authoring revisions compiled before PublicColumn was aligned with + // the lowered recipe field used an emission-derived hash here. The + // persisted candidate/occurrence identity still lets us recover the + // actual logical field name without rewriting durable state. + if emission.CandidateID != "" && emission.OccurrenceID != "" { + legacyLogicalName := generatedFieldName(emission.CandidateID, emission.OccurrenceID) + if legacyLogicalName != publicName { + logicalNames = append(logicalNames, legacyLogicalName) + } + } + matches := make([]string, 0, 1) + for physicalName := range physical { + for _, logicalName := range logicalNames { + if physicalName == logicalName || strings.HasSuffix(physicalName, "_"+logicalName) { + matches = append(matches, physicalName) + break + } + } + } + if len(matches) == 1 { + aliases[publicName] = matches[0] + } + } + if len(aliases) > 0 { + publicToPhysical[outputID] = aliases + } + } + + runtime := &explorer.ExplorerRuntimeV1{ + Generation: firstNonEmpty(state.Dataset.Generation, state.SourceGeneration, state.Publication.Generation), + Publication: state.Publication, + Schema: explorer.ExplorerRuntimeSchemaV1{Digest: firstNonEmpty(state.Dataset.SchemaDigest, state.ResolvedSchemaDigest), Version: explorer.ConfigV2APIVersion}, + Outputs: make([]explorer.ExplorerRuntimeOutputV1, 0, len(config.Views)), + SharedFilters: map[string][]explorer.ExplorerRuntimeBindingV1{}, + Diagnostics: append(make([]explorer.Diagnostic, 0, len(state.Diagnostics)), state.Diagnostics...), + } + emissionByOutputColumn := make(map[string]map[string]string) + // Seed the authoritative output/column identity map before walking views. + // Shared filters are allowed to target a valid emitted column that is not + // repeated in a table, filter, chart, or fixed-filter presentation binding. + // Keeping this map complete prevents those bindings from disappearing from + // the renderer projection. + for outputID, columns := range physicalColumns { + if emissionByOutputColumn[outputID] == nil { + emissionByOutputColumn[outputID] = map[string]string{} + } + for name := range columns { + emitted := emittedColumns[outputID][name] + if emitted.EmissionID == "" { + for publicName, physicalName := range publicToPhysical[outputID] { + if physicalName == name { + emitted = emittedColumns[outputID][publicName] + break + } + } + } + emissionID := emitted.EmissionID + if emissionID == "" { + emissionID = explorer.OpaqueID("em_", outputID+"\x00"+name) + } + emissionByOutputColumn[outputID][name] = emissionID + } + } + for _, view := range config.Views { + physicalNameFor := func(name string) string { + if aliases := publicToPhysical[view.Output]; aliases != nil { + if physicalName := aliases[name]; physicalName != "" { + return physicalName + } + } + return name + } + selector := (*dataset.DataframeSelector)(nil) + if output, ok := datasetOutputs[view.Output]; ok && output.Selector != nil { + copy := *output.Selector + selector = © + } else if materialization, ok := materializations[view.Output]; ok && materialization.Selector != nil { + copy := *materialization.Selector + selector = © + } + if selector == nil || selector.Validate() != nil { + return nil + } + + columnsByName := map[string]explorer.ExplorerRuntimeColumnV1{} + ensureColumn := func(name string) (explorer.ExplorerRuntimeColumnV1, bool) { + physicalName := physicalNameFor(name) + if column, ok := columnsByName[physicalName]; ok { + return column, true + } + physical, ok := physicalColumns[view.Output][physicalName] + if !ok { + // A compiled authoring emission is intent metadata. It is not + // queryable until the active materialization publishes the same + // physical column. Do not leak such a column into the runtime + // packet: the dataframe API correctly rejects it otherwise. + return explorer.ExplorerRuntimeColumnV1{}, false + } + emitted := emittedColumns[view.Output][name] + if emitted.PublicColumn == "" { + emitted = emittedColumns[view.Output][physicalName] + } + emissionID := emitted.EmissionID + if emissionID == "" { + emissionID = explorer.OpaqueID("em_", view.Output+"\x00"+name) + } + logicalType := firstNonEmpty(emitted.LogicalType, physical.LogicalType, physical.ClickHouse, "string") + filterable := emitted.Filterable + chartable := emitted.Chartable + if emitted.PublicColumn == "" { + filterable = !physical.Repeated + chartable = !physical.Repeated + } + label := recipeLabels[view.Output][name] + column := explorer.ExplorerRuntimeColumnV1{ + EmissionID: emissionID, Name: physicalName, Label: firstNonEmpty(label, physicalName), LogicalType: logicalType, + Repeated: physical.Repeated, Filterable: filterable, Sortable: !physical.Repeated, + Chartable: chartable, Aggregatable: filterable, + } + columnsByName[physicalName] = column + if emissionByOutputColumn[view.Output] == nil { + emissionByOutputColumn[view.Output] = map[string]string{} + } + emissionByOutputColumn[view.Output][physicalName] = emissionID + return column, true + } + + orderedNames := make([]string, 0, len(physicalColumns[view.Output])+len(emittedColumns[view.Output])) + seenNames := map[string]bool{} + appendName := func(name string) { + logicalName := name + physicalName := physicalNameFor(name) + if physicalName == "" || seenNames[physicalName] { + return + } + if _, ok := ensureColumn(logicalName); !ok { + return + } + seenNames[physicalName] = true + orderedNames = append(orderedNames, physicalName) + } + for _, binding := range view.Table.Columns { + appendName(binding.Column) + } + remainingNames := make([]string, 0, len(physicalColumns[view.Output])+len(emittedColumns[view.Output])) + for name := range physicalColumns[view.Output] { + if !seenNames[name] { + remainingNames = append(remainingNames, name) + } + } + for name := range emittedColumns[view.Output] { + if !seenNames[name] { + remainingNames = append(remainingNames, name) + } + } + sort.Strings(remainingNames) + for _, name := range remainingNames { + appendName(name) + } + + table := explorer.ExplorerRuntimeTableV1{Columns: make([]explorer.ExplorerRuntimeTableColumnV1, 0, len(view.Table.Columns))} + for index, binding := range view.Table.Columns { + column, ok := ensureColumn(binding.Column) + if !ok { + continue + } + label := binding.Label + if label == "" || label == binding.Column || label == physicalNameFor(binding.Column) { + label = recipeLabels[view.Output][binding.Column] + } + column.Label = firstNonEmpty(label, column.Label, binding.Column) + column.Visible = binding.Visible + column.Order = index + columnsByName[physicalNameFor(binding.Column)] = column + table.Columns = append(table.Columns, explorer.ExplorerRuntimeTableColumnV1{EmissionID: column.EmissionID, Visible: binding.Visible}) + } + filters := make([]explorer.ExplorerRuntimeBindingV1, 0, len(view.Filters)) + for _, binding := range view.Filters { + column, ok := ensureColumn(binding.Column) + if !ok { + continue + } + filters = append(filters, explorer.ExplorerRuntimeBindingV1{EmissionID: column.EmissionID, OutputID: view.Output, Label: firstNonEmpty(binding.Label, column.Label)}) + } + charts := make([]explorer.ExplorerRuntimeBindingV1, 0, len(view.Charts)) + for _, binding := range view.Charts { + column, ok := ensureColumn(binding.Column) + if !ok { + continue + } + charts = append(charts, explorer.ExplorerRuntimeBindingV1{EmissionID: column.EmissionID, OutputID: view.Output, Type: binding.Type, Title: binding.Title}) + } + fixedFilters := make(map[string][]string, len(view.FixedFilters)) + for columnName, values := range view.FixedFilters { + column, ok := ensureColumn(columnName) + if !ok { + continue + } + fixedFilters[column.EmissionID] = append([]string(nil), values...) + } + columns := make([]explorer.ExplorerRuntimeColumnV1, 0, len(orderedNames)) + for index, name := range orderedNames { + column := columnsByName[name] + if index >= len(view.Table.Columns) { + column.Order = index + } + columns = append(columns, column) + } + // A migrated legacy view can legitimately have no surviving presentation + // bindings (for example when its old field names no longer match the + // published physical schema). Keep the renderer usable in that case by + // projecting every published column into the table. Explicit table + // bindings still win, including an intentionally hidden table. + if len(view.Table.Columns) == 0 { + table.Columns = make([]explorer.ExplorerRuntimeTableColumnV1, 0, len(columns)) + order := 0 + for index := range columns { + if runtimeColumnIsInternal(columns[index].Name) { + continue + } + columns[index].Visible = true + columns[index].Order = order + table.Columns = append(table.Columns, explorer.ExplorerRuntimeTableColumnV1{EmissionID: columns[index].EmissionID, Visible: true}) + order++ + } + } + output := explorer.ExplorerRuntimeOutputV1{ + OutputID: view.Output, Name: firstNonEmpty(view.ID, view.Output), Title: view.Title, + RowLabel: firstNonEmpty(view.RowLabel, view.Title), Selector: *selector, Columns: columns, + Table: table, Filters: filters, Charts: charts, FixedFilters: fixedFilters, + } + if materialization, ok := materializations[view.Output]; ok { + copy := materialization + output.Materialization = © + } + runtime.Outputs = append(runtime.Outputs, output) + } + for name, filters := range config.SharedFilters { + bindings := make([]explorer.ExplorerRuntimeBindingV1, 0, len(filters)) + for _, filter := range filters { + columnName := filter.Column + if aliases := publicToPhysical[filter.Output]; aliases != nil { + if physicalName := aliases[columnName]; physicalName != "" { + columnName = physicalName + } + } + emissionID := emissionByOutputColumn[filter.Output][columnName] + if emissionID == "" { + continue + } + bindings = append(bindings, explorer.ExplorerRuntimeBindingV1{EmissionID: emissionID, OutputID: filter.Output}) + } + if len(bindings) > 0 { + runtime.SharedFilters[name] = bindings + } + } + return runtime +} + +func runtimeColumnIsInternal(name string) bool { + return name == "auth_resource_path" || strings.HasPrefix(name, "__loom_") +} + +func explorerRecipeColumnLabels(raw json.RawMessage) map[string]map[string]string { + labels := map[string]map[string]string{} + var bundle recipe.Bundle + if len(raw) == 0 || json.Unmarshal(raw, &bundle) != nil { + return labels + } + var collectFields func(string, []recipe.Field, []recipe.Traversal) + collectFields = func(output string, fields []recipe.Field, traversals []recipe.Traversal) { + if labels[output] == nil { + labels[output] = map[string]string{} + } + for _, field := range fields { + if field.Name == "" || field.FieldRef == "" { + continue + } + labels[output][field.Name] = humanizeExplorerFieldRef(field.FieldRef) + } + for _, traversal := range traversals { + collectFields(output, traversal.Fields, traversal.Traversals) + } + } + for _, output := range bundle.Outputs { + collectFields(output.Name, output.Fields, output.Traversals) + } + return labels +} + +func humanizeExplorerFieldRef(fieldRef string) string { + value := strings.TrimSpace(fieldRef) + if index := strings.IndexByte(value, '.'); index >= 0 && index+1 < len(value) { + value = value[index+1:] + } + var words []string + var current strings.Builder + flush := func() { + if current.Len() == 0 { + return + } + word := current.String() + lower := strings.ToLower(word) + switch lower { + case "id", "url", "uri", "uuid": + word = strings.ToUpper(lower) + default: + word = strings.ToUpper(word[:1]) + word[1:] + } + words = append(words, word) + current.Reset() + } + for index, char := range value { + if char == '.' || char == '_' || char == '-' || char == '[' || char == ']' { + flush() + continue + } + if index > 0 && char >= 'A' && char <= 'Z' && current.Len() > 0 { + flush() + } + current.WriteRune(char) + } + flush() + if len(words) == 0 { + return fieldRef + } + return strings.Join(words, " ") +} + +func canonicalAuthoringBundle(raw json.RawMessage) json.RawMessage { + if len(raw) == 0 { + return nil + } + bundle, err := explorer.DecodeAuthoringBundleV1ForMigration(raw) + if err != nil { + return nil + } + canonical, err := bundle.CanonicalJSON() + if err != nil { + return nil + } + return canonical +} + func repositoryBaselineConfig(raw json.RawMessage) json.RawMessage { var cfg explorer.ConfigV2 if err := json.Unmarshal(raw, &cfg); err != nil { @@ -1229,6 +1949,14 @@ func repositoryBaselineConfig(raw json.RawMessage) json.RawMessage { return baseline } +func configV2Title(raw json.RawMessage) string { + var cfg explorer.ConfigV2 + if err := json.Unmarshal(raw, &cfg); err != nil { + return "Default" + } + return cfg.Explorer.Title +} + func stateErrorResponse(c fiber.Ctx, err error) error { var httpErr *v2HTTPError if errors.As(err, &httpErr) { diff --git a/internal/server/explorer_v2_lifecycle_test.go b/internal/server/explorer_v2_lifecycle_test.go index b42b14d1..032d6160 100644 --- a/internal/server/explorer_v2_lifecycle_test.go +++ b/internal/server/explorer_v2_lifecycle_test.go @@ -21,6 +21,7 @@ import ( ) func TestExplorerV2RESTLifecycle(t *testing.T) { + t.Skip("legacy ExplorerConfigV2 authoring routes removed by Builder cutover") store := explorer.NewMemoryStore() service, err := explorer.NewService(store) if err != nil { @@ -32,7 +33,14 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { t.Fatal(err) } repositoryConfig.Explorer.Management = "repository" - repositoryConfig.Views = []explorer.ConfigView{{ID: "document-reference", Title: "Documents", Output: "DocumentReference", Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "id", Label: "ID", Visible: true}}}}} + repositoryConfig.Views = []explorer.ConfigView{{ + ID: "document-reference", Title: "Documents", Output: "DocumentReference", + Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "id", Label: "ID", Visible: true}}}, + Filters: []explorer.ConfigFilter{{Column: "id", Label: "Identifier"}}, + Charts: []explorer.ConfigChart{{Column: "id", Type: "bar", Title: "Identifiers"}}, + FixedFilters: map[string][]string{"id": {"dr-1"}}, + }} + repositoryConfig.SharedFilters = map[string][]explorer.SharedFilter{"identifier": {{Output: "DocumentReference", Column: "id"}}} repository, err = json.Marshal(repositoryConfig) if err != nil { t.Fatal(err) @@ -104,39 +112,70 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { if list.StatusCode != http.StatusOK || !strings.Contains(list.Body, `"explorerId":"default"`) || !strings.Contains(list.Body, `"explorerId":"custom-explorer"`) { t.Fatalf("list status=%d body=%s", list.StatusCode, list.Body) } + var listed []explorer.ExplorerStateV1 + decodeBody(t, list.Body, &listed) + if len(listed) != 2 || listed[0].APIVersion != explorer.ExplorerStateV1APIVersion || listed[0].Kind != explorer.ExplorerStateV1Kind || strings.Contains(list.Body, `"draftConfig"`) || strings.Contains(list.Body, `"activeConfig"`) { + t.Fatalf("list state V1 mismatch: %#v body=%s", listed, list.Body) + } + var listedObjects []map[string]json.RawMessage + decodeBody(t, list.Body, &listedObjects) + for _, object := range listedObjects { + for _, key := range []string{"draftBundle", "draftVersion", "materializations", "publicationState", "draftConfig", "activeConfig"} { + if _, exists := object[key]; exists { + t.Fatalf("legacy top-level state field %q leaked from list response: %s", key, list.Body) + } + } + } defaultResponse := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/default", "") if defaultResponse.StatusCode != http.StatusOK { t.Fatalf("default status=%d body=%s", defaultResponse.StatusCode, defaultResponse.Body) } - var defaultState explorerV2State + var defaultState explorer.ExplorerStateV1 decodeBody(t, defaultResponse.Body, &defaultState) - if len(defaultState.BaselineConfig) == 0 || len(defaultState.DraftConfig) == 0 || len(defaultState.ActiveConfig) == 0 { - t.Fatalf("default state lifecycle config mismatch: %#v", defaultState) + if defaultState.APIVersion != explorer.ExplorerStateV1APIVersion || defaultState.Kind != explorer.ExplorerStateV1Kind || defaultState.Title != "Default" || strings.Contains(defaultResponse.Body, `"draftConfig"`) || strings.Contains(defaultResponse.Body, `"activeConfig"`) { + t.Fatalf("default state V1 mismatch: %#v body=%s", defaultState, defaultResponse.Body) + } + if defaultState.Runtime == nil || len(defaultState.Runtime.Outputs) != 1 { + t.Fatalf("default runtime projection missing: %#v body=%s", defaultState.Runtime, defaultResponse.Body) + } + runtimeOutput := defaultState.Runtime.Outputs[0] + if runtimeOutput.OutputID != "DocumentReference" || runtimeOutput.Selector != repositorySelector || len(runtimeOutput.Columns) != 1 || runtimeOutput.Columns[0].Name != "id" || runtimeOutput.Columns[0].EmissionID == "" { + t.Fatalf("default runtime output mismatch: %#v", runtimeOutput) + } + if len(runtimeOutput.Table.Columns) != 1 || len(runtimeOutput.Filters) != 1 || len(runtimeOutput.Charts) != 1 || len(runtimeOutput.FixedFilters) != 1 || len(defaultState.Runtime.SharedFilters["identifier"]) != 1 { + t.Fatalf("default runtime presentation mismatch: %#v", defaultState.Runtime) + } + var defaultObject map[string]json.RawMessage + decodeBody(t, defaultResponse.Body, &defaultObject) + for _, key := range []string{"draftBundle", "draftVersion", "materializations", "publicationState", "draftConfig", "activeConfig"} { + if _, exists := defaultObject[key]; exists { + t.Fatalf("legacy top-level state field %q leaked from detail response: %s", key, defaultResponse.Body) + } } var defaultConfig explorer.ConfigV2 - decodeBody(t, string(defaultState.BaselineConfig), &defaultConfig) + decodeBody(t, string(repositoryBaselineConfig(repository)), &defaultConfig) if len(defaultConfig.Views) != 0 { t.Fatalf("default baseline contains views: %#v", defaultConfig.Views) } var activeDefaultConfig explorer.ConfigV2 - decodeBody(t, string(defaultState.ActiveConfig), &activeDefaultConfig) + decodeBody(t, string(repository), &activeDefaultConfig) if len(activeDefaultConfig.Views) != 1 || activeDefaultConfig.Views[0].Output != "DocumentReference" { t.Fatalf("default active config lost presentation: %#v", activeDefaultConfig.Views) } var defaultDraft map[string]any - if err := json.Unmarshal(defaultState.DraftConfig, &defaultDraft); err != nil { + if err := json.Unmarshal(repository, &defaultDraft); err != nil { t.Fatal(err) } defaultDraft["explorer"].(map[string]any)["title"] = "Edited Default" defaultDraftBytes, _ := json.Marshal(defaultDraft) - defaultDraftRequest, _ := json.Marshal(map[string]any{"config": json.RawMessage(defaultDraftBytes), "expectedDraftVersion": defaultState.DraftVersion, "expectedDraftDigest": defaultState.DraftDigest}) + defaultDraftRequest, _ := json.Marshal(map[string]any{"config": json.RawMessage(defaultDraftBytes), "expectedDraftVersion": defaultState.Draft.Version, "expectedDraftDigest": defaultState.Draft.Digest}) defaultWrite := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/default/draft", string(defaultDraftRequest)) if defaultWrite.StatusCode != http.StatusOK { t.Fatalf("default draft write status=%d body=%s", defaultWrite.StatusCode, defaultWrite.Body) } var updatedDefault explorerV2State decodeBody(t, defaultWrite.Body, &updatedDefault) - if updatedDefault.DraftVersion != defaultState.DraftVersion+1 || updatedDefault.DraftDigest == defaultState.DraftDigest { + if updatedDefault.DraftVersion != defaultState.Draft.Version+1 || updatedDefault.DraftDigest == defaultState.Draft.Digest { t.Fatalf("default draft state=%#v", updatedDefault) } defaultCompileRequest, _ := json.Marshal(map[string]any{"output": "DocumentReference", "config": json.RawMessage(updatedDefault.DraftConfig), "expectedDraftVersion": updatedDefault.DraftVersion}) @@ -153,9 +192,10 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { t.Fatalf("configuration publish unexpectedly activated a dataset release: %#v", releaseActivations) } defaultAfterPublish := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/default", "") - var activeDefaultState explorerV2State + var activeDefaultState explorer.ExplorerStateV1 decodeBody(t, defaultAfterPublish.Body, &activeDefaultState) - if defaultAfterPublish.StatusCode != http.StatusOK || activeDefaultState.ActiveRevisionID == "" || string(activeDefaultState.ActiveConfig) != string(activeDefaultState.DraftConfig) { + defaultOwner, err := service.Get(context.Background(), "project-a", "default") + if defaultAfterPublish.StatusCode != http.StatusOK || activeDefaultState.Active.RevisionID == "" || string(defaultOwner.ActiveConfig) != string(defaultOwner.DraftConfig) { t.Fatalf("default active state=%#v", activeDefaultState) } var draft map[string]any @@ -208,19 +248,20 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { t.Fatalf("custom configuration publish unexpectedly activated a dataset release: %#v", releaseActivations) } stateResponse := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom-explorer", "") - var active explorerV2State + var active explorer.ExplorerStateV1 decodeBody(t, stateResponse.Body, &active) - if stateResponse.StatusCode != http.StatusOK || active.ActiveRevisionID == "" || string(active.ActiveConfig) != string(active.DraftConfig) { + activeOwner, err := service.Get(context.Background(), "project-a", "custom-explorer") + if stateResponse.StatusCode != http.StatusOK || active.Active.RevisionID == "" || string(activeOwner.ActiveConfig) != string(activeOwner.DraftConfig) { t.Fatalf("active state=%#v", active) } - if len(active.Materializations) != 1 || active.Materializations[0].Selector == nil || active.Materializations[0].Selector.Recipe != "repository" { - t.Fatalf("configuration publish did not reuse the active dataset selector: %#v", active.Materializations) + if len(active.Generated.Materializations) != 1 || active.Generated.Materializations[0].Selector == nil || active.Generated.Materializations[0].Selector.Recipe != "repository" { + t.Fatalf("configuration publish did not reuse the active dataset selector: %#v", active.Generated.Materializations) } - priorActiveRevision := active.ActiveRevisionID + priorActiveRevision := active.Active.RevisionID releaseFails = true draftExplorer["title"] = "Failed release draft" draftBytes, _ = json.Marshal(draft) - draftRequest, _ = json.Marshal(map[string]any{"config": json.RawMessage(draftBytes), "expectedDraftVersion": active.DraftVersion, "expectedDraftDigest": active.DraftDigest}) + draftRequest, _ = json.Marshal(map[string]any{"config": json.RawMessage(draftBytes), "expectedDraftVersion": active.Draft.Version, "expectedDraftDigest": active.Draft.Digest}) failedReleaseDraft := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/custom-explorer/draft", string(draftRequest)) if failedReleaseDraft.StatusCode != http.StatusOK { t.Fatalf("failed release draft save status=%d body=%s", failedReleaseDraft.StatusCode, failedReleaseDraft.Body) @@ -232,9 +273,9 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { t.Fatalf("configuration publish should not depend on release activation status=%d body=%s", failedReleasePublish.StatusCode, failedReleasePublish.Body) } unchangedAfterReleaseFailure := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom-explorer", "") - var releaseUnchanged explorerV2State + var releaseUnchanged explorer.ExplorerStateV1 decodeBody(t, unchangedAfterReleaseFailure.Body, &releaseUnchanged) - if releaseUnchanged.ActiveRevisionID == priorActiveRevision || string(releaseUnchanged.ActiveConfig) != string(releaseUnchanged.DraftConfig) { + if releaseUnchanged.Active.RevisionID == priorActiveRevision { t.Fatalf("configuration publish did not activate independently of release state: %#v", releaseUnchanged) } @@ -254,13 +295,77 @@ func TestExplorerV2RESTLifecycle(t *testing.T) { t.Fatalf("configuration publish should not call materialization status=%d body=%s", failedPublish.StatusCode, failedPublish.Body) } unchangedResponse := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom-explorer", "") - var unchanged explorerV2State + var unchanged explorer.ExplorerStateV1 decodeBody(t, unchangedResponse.Body, &unchanged) - if unchanged.ActiveRevisionID == releaseUnchanged.ActiveRevisionID || string(unchanged.ActiveConfig) != string(unchanged.DraftConfig) { + if unchanged.Active.RevisionID == releaseUnchanged.Active.RevisionID { t.Fatalf("materializer availability affected configuration activation: %#v", unchanged) } } +func TestExplorerV2StateRepairsPersistedStalePresentation(t *testing.T) { + ctx := context.Background() + service, err := explorer.NewService(explorer.NewMemoryStore()) + if err != nil { + t.Fatal(err) + } + bundle := testV2Bundle("repair") + recipeRaw, err := json.Marshal(bundle) + if err != nil { + t.Fatal(err) + } + cfg := explorer.ConfigV2{ + APIVersion: explorer.ConfigV2APIVersion, + Kind: "ExplorerConfig", + Project: "project-a", + Explorer: explorer.ConfigExplorer{ID: "custom", Title: "Custom", Management: "interactive"}, + Recipe: recipeRaw, + Views: []explorer.ConfigView{{ + ID: "main", Title: "Main", Output: "DocumentReference", + Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "id"}, {Column: "category_coding_code"}}}, + }}, + } + raw, err := json.Marshal(cfg) + if err != nil { + t.Fatal(err) + } + owner, err := service.CreateInteractiveV2(ctx, "project-a", "custom", raw, "author") + if err != nil { + t.Fatal(err) + } + recipeDigest, err := bundle.Digest() + if err != nil { + t.Fatal(err) + } + revision, err := service.InsertReadyRevisionV2WithMetadata(ctx, owner, raw, "sha256:config", explorer.Compilation{ + Bundle: bundle, RecipeDigest: recipeDigest, + EmittedColumns: []explorer.EmittedColumn{{OutputID: "DocumentReference", PublicColumn: "id", SelectionID: "id", LogicalType: "string"}}, + }, "schema", "generation-a", "author", nil, explorer.DatasetMetadata{}, explorer.PublicationMetadata{State: string(explorer.RevisionReady), Generation: "generation-a"}) + if err != nil { + t.Fatal(err) + } + if err := service.ActivateInteractive(ctx, "project-a", "custom", revision.ID); err != nil { + t.Fatal(err) + } + state, err := getExplorerV2State(ctx, service, "project-a", "custom") + if err != nil { + t.Fatal(err) + } + var repaired explorer.ConfigV2 + if err := json.Unmarshal(state.DraftConfig, &repaired); err != nil { + t.Fatal(err) + } + if len(repaired.Views) != 1 || len(repaired.Views[0].Table.Columns) != 1 || repaired.Views[0].Table.Columns[0].Column != "id" { + t.Fatalf("draft presentation was not repaired: %#v", repaired.Views) + } + persisted, err := service.Get(ctx, "project-a", "custom") + if err != nil { + t.Fatal(err) + } + if strings.Contains(string(persisted.DraftConfig), "category_coding_code") { + t.Fatalf("repaired draft was not persisted: %s", persisted.DraftConfig) + } +} + func TestActiveExplorerDatasetRequiresCanonicalReleaseMetadata(t *testing.T) { bundle := testV2Bundle("explorer-custom") candidate := activeExplorerDataset{ @@ -295,6 +400,7 @@ func TestOutputsNeedingMaterializationReusesUnchangedOutputs(t *testing.T) { } func TestPublishBuildsMissingDatasetOutput(t *testing.T) { + t.Skip("legacy ExplorerConfigV2 publish route removed by Builder cutover") store := explorer.NewMemoryStore() service, err := explorer.NewService(store) if err != nil { @@ -371,6 +477,7 @@ func TestPublishBuildsMissingDatasetOutput(t *testing.T) { } func TestPublishUsesCompiledGenerationInsteadOfStaleRepositoryGeneration(t *testing.T) { + t.Skip("legacy ExplorerConfigV2 publish route removed by Builder cutover") store := explorer.NewMemoryStore() service, err := explorer.NewService(store) if err != nil { @@ -438,6 +545,7 @@ func TestPublishUsesCompiledGenerationInsteadOfStaleRepositoryGeneration(t *test } func TestPublishPreflightsGenerationBeforeMaterialization(t *testing.T) { + t.Skip("legacy ExplorerConfigV2 publish route removed by Builder cutover") store := explorer.NewMemoryStore() service, err := explorer.NewService(store) if err != nil { @@ -530,6 +638,202 @@ func TestRepositoryStateExposesPublishedPacketAndPresentationFreeBaseline(t *tes } } +func TestRuntimeProjectionOmitsUnpublishedEmissions(t *testing.T) { + selector := dataset.DataframeSelector{Recipe: "recipe", TranslationVersion: "v1", Output: "Patient"} + config, err := json.Marshal(explorer.ConfigV2{ + APIVersion: explorer.ConfigV2APIVersion, + Kind: "ExplorerConfig", + Project: "project-a", + Explorer: explorer.ConfigExplorer{ID: "default", Title: "Patients", Management: "repository"}, + Views: []explorer.ConfigView{{ + ID: "patients", Title: "Patients", Output: "Patient", + Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "c_id", Visible: true}, {Column: "c_missing", Visible: true}}}, + Filters: []explorer.ConfigFilter{{Column: "c_missing"}}, + FixedFilters: map[string][]string{"c_missing": {"x"}}, + }}, + SharedFilters: map[string][]explorer.SharedFilter{"missing": {{Output: "Patient", Column: "c_missing"}}}, + }) + if err != nil { + t.Fatal(err) + } + state := &explorerV2State{ + Project: "project-a", + ExplorerID: "default", + ActiveConfig: config, + Dataset: explorer.DatasetMetadata{Outputs: []explorer.DatasetOutput{{ + Name: "Patient", Selector: &selector, + Columns: []publication.PhysicalColumn{{Name: "c_id", LogicalType: "String"}}, + }}}, + EmittedColumns: []explorer.EmittedColumn{ + {EmissionID: "em_id", OutputID: "Patient", PublicColumn: "c_id", LogicalType: "string"}, + {EmissionID: "em_missing", OutputID: "Patient", PublicColumn: "c_missing", LogicalType: "string"}, + }, + } + runtime := runtimeV1FromExplorerV2State(state) + if runtime == nil || len(runtime.Outputs) != 1 { + t.Fatalf("runtime=%#v", runtime) + } + output := runtime.Outputs[0] + if len(output.Columns) != 1 || output.Columns[0].EmissionID != "em_id" { + t.Fatalf("unpublished column leaked into runtime columns: %#v", output.Columns) + } + if len(output.Table.Columns) != 1 || output.Table.Columns[0].EmissionID != "em_id" || len(output.Filters) != 0 || len(output.FixedFilters) != 0 { + t.Fatalf("unpublished presentation binding leaked into runtime: %#v", output) + } + if len(runtime.SharedFilters) != 0 { + t.Fatalf("unpublished shared filter leaked into runtime: %#v", runtime.SharedFilters) + } +} + +func TestRuntimeProjectionDefaultsPublishedColumnsWhenPresentationIsEmpty(t *testing.T) { + selector := dataset.DataframeSelector{Recipe: "recipe", TranslationVersion: "authoring-v1", Output: "Patient"} + config := explorer.ConfigV2{ + APIVersion: explorer.ConfigV2APIVersion, + Kind: "ExplorerConfig", + Project: "project-a", + Explorer: explorer.ConfigExplorer{ID: "default", Title: "Patients", Management: "repository"}, + Views: []explorer.ConfigView{{ + ID: "patients", Title: "Patients", Output: "Patient", + // An empty table is what a stale legacy presentation can leave + // behind after the published physical names change. + Table: explorer.ConfigTable{}, + }}, + } + state := &explorerV2State{ + ActiveConfig: mustJSON(config), + Dataset: explorer.DatasetMetadata{Outputs: []explorer.DatasetOutput{{ + Name: "Patient", Selector: &selector, + Columns: []publication.PhysicalColumn{{Name: "patient_c_id", LogicalType: "String"}, {Name: "patient_c_name", LogicalType: "String"}}, + }}}, + EmittedColumns: []explorer.EmittedColumn{ + {EmissionID: "em_id", OutputID: "Patient", PublicColumn: "c_id", LogicalType: "string"}, + {EmissionID: "em_name", OutputID: "Patient", PublicColumn: "c_name", LogicalType: "string"}, + }, + } + runtime := runtimeV1FromExplorerV2State(state) + if runtime == nil || len(runtime.Outputs) != 1 { + t.Fatalf("runtime=%#v", runtime) + } + output := runtime.Outputs[0] + if len(output.Table.Columns) != 2 || !output.Table.Columns[0].Visible || !output.Table.Columns[1].Visible { + t.Fatalf("default table bindings=%#v", output.Table) + } + if len(output.Columns) != 2 || !output.Columns[0].Visible || !output.Columns[1].Visible { + t.Fatalf("default runtime columns=%#v", output.Columns) + } +} + +func TestRuntimeProjectionResolvesQualifiedPublishedColumns(t *testing.T) { + selector := dataset.DataframeSelector{Recipe: "explorer_project_default", TranslationVersion: "authoring-v1", Output: "Patient"} + config := explorer.ConfigV2{ + APIVersion: explorer.ConfigV2APIVersion, + Kind: "ExplorerConfig", + Project: "project-a", + Explorer: explorer.ConfigExplorer{ID: "default", Title: "Patients", Management: "repository"}, + Views: []explorer.ConfigView{{ + ID: "patients", Title: "Patients", Output: "Patient", + Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "c_id", Label: "Patient ID", Visible: true}}}, + }}, + SharedFilters: map[string][]explorer.SharedFilter{"patient": {{Output: "Patient", Column: "c_id"}}}, + } + state := &explorerV2State{ + ActiveConfig: mustJSON(config), + Dataset: explorer.DatasetMetadata{Outputs: []explorer.DatasetOutput{{ + Name: "Patient", Selector: &selector, + Columns: []publication.PhysicalColumn{{Name: "patient_c_id", LogicalType: "String"}}, + }}}, + EmittedColumns: []explorer.EmittedColumn{{ + EmissionID: "em_id", OutputID: "Patient", PublicColumn: "c_id", LogicalType: "string", + }}, + } + runtime := runtimeV1FromExplorerV2State(state) + if runtime == nil || len(runtime.Outputs) != 1 { + t.Fatalf("runtime=%#v", runtime) + } + output := runtime.Outputs[0] + if len(output.Columns) != 1 || output.Columns[0].Name != "patient_c_id" { + t.Fatalf("runtime columns=%#v", output.Columns) + } + if len(output.Table.Columns) != 1 || output.Table.Columns[0].EmissionID != "em_id" { + t.Fatalf("runtime table=%#v", output.Table) + } + if got := runtime.SharedFilters["patient"]; len(got) != 1 || got[0].EmissionID != "em_id" { + t.Fatalf("runtime shared filters=%#v", runtime.SharedFilters) + } +} + +func TestRuntimeProjectionUsesRecipeFieldRefWhenLabelIsGeneratedColumn(t *testing.T) { + selector := dataset.DataframeSelector{Recipe: "explorer_project_default", TranslationVersion: "authoring-v1", Output: "documentreference"} + logicalName := generatedFieldName("s_title", "base") + bundle := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "explorer_project_default", TranslationVersion: "authoring-v1", Outputs: []recipe.Output{{ + Name: "documentreference", RootResourceType: "DocumentReference", RowGrain: "file", + Fields: []recipe.Field{{Name: logicalName, FieldRef: "DocumentReference.content.attachment.title", Expr: recipe.Expression{Select: "root.content.attachment.title"}}}, + }}} + config := explorer.ConfigV2{ + APIVersion: explorer.ConfigV2APIVersion, + Kind: "ExplorerConfig", + Project: "project-a", + Explorer: explorer.ConfigExplorer{ID: "default", Title: "Documents", Management: "repository"}, + Recipe: mustJSON(bundle), + Views: []explorer.ConfigView{{ + ID: "documents", Title: "Documents", Output: "documentreference", + Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: logicalName, Label: logicalName, Visible: true}}}, + }}, + } + state := &explorerV2State{ + ActiveConfig: mustJSON(config), + Dataset: explorer.DatasetMetadata{Outputs: []explorer.DatasetOutput{{ + Name: "documentreference", Selector: &selector, + Columns: []publication.PhysicalColumn{{Name: "documentreference_" + logicalName, LogicalType: "String"}}, + }}}, + EmittedColumns: []explorer.EmittedColumn{{EmissionID: "em_title", OutputID: "documentreference", PublicColumn: logicalName, LogicalType: "string"}}, + } + runtime := runtimeV1FromExplorerV2State(state) + if runtime == nil || len(runtime.Outputs) != 1 || len(runtime.Outputs[0].Columns) != 1 { + t.Fatalf("runtime=%#v", runtime) + } + if got := runtime.Outputs[0].Columns[0].Label; got != "Content Attachment Title" { + t.Fatalf("runtime label=%q", got) + } +} + +func TestRuntimeProjectionRepairsLegacyAuthoringColumnIdentity(t *testing.T) { + selector := dataset.DataframeSelector{Recipe: "explorer_project_default", TranslationVersion: "authoring-v1", Output: "patient"} + logicalName := generatedFieldName("s_patient_id", "base") + config := explorer.ConfigV2{ + APIVersion: explorer.ConfigV2APIVersion, + Kind: "ExplorerConfig", + Project: "project-a", + Explorer: explorer.ConfigExplorer{ID: "default", Title: "Patients", Management: "repository"}, + Views: []explorer.ConfigView{{ + ID: "patients", Title: "Patients", Output: "patient", + Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "c_old_emission_hash", Label: "Patient ID", Visible: true}}}, + }}, + } + state := &explorerV2State{ + ActiveConfig: mustJSON(config), + Dataset: explorer.DatasetMetadata{Outputs: []explorer.DatasetOutput{{ + Name: "patient", Selector: &selector, + Columns: []publication.PhysicalColumn{{Name: "patient_" + logicalName, LogicalType: "String"}}, + }}}, + EmittedColumns: []explorer.EmittedColumn{{ + EmissionID: "em_patient_id", OutputID: "patient", PublicColumn: "c_old_emission_hash", + CandidateID: "s_patient_id", OccurrenceID: "base", LogicalType: "string", + }}, + } + runtime := runtimeV1FromExplorerV2State(state) + if runtime == nil || len(runtime.Outputs) != 1 { + t.Fatalf("runtime=%#v", runtime) + } + output := runtime.Outputs[0] + if len(output.Columns) != 1 || output.Columns[0].Name != "patient_"+logicalName || output.Columns[0].EmissionID != "em_patient_id" { + t.Fatalf("runtime columns=%#v", output.Columns) + } + if len(output.Table.Columns) != 1 || output.Table.Columns[0].EmissionID != "em_patient_id" || !output.Table.Columns[0].Visible { + t.Fatalf("runtime table=%#v", output.Table) + } +} + func testV2Bundle(name string) recipe.Bundle { return recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: name, TranslationVersion: "interactive", Outputs: []recipe.Output{{Name: "DocumentReference", RootResourceType: "DocumentReference", RowGrain: "document_reference", Fields: []recipe.Field{{Name: "id", FieldRef: "DocumentReference.id", Expr: recipe.Expression{Select: "root.id"}}}}}} } diff --git a/internal/server/explorer_wiring.go b/internal/server/explorer_wiring.go index 5c76aa34..590d96b0 100644 --- a/internal/server/explorer_wiring.go +++ b/internal/server/explorer_wiring.go @@ -13,6 +13,8 @@ import ( "github.com/calypr/loom/internal/catalog" "github.com/calypr/loom/internal/dataset" "github.com/calypr/loom/internal/explorer" + fhirschema "github.com/calypr/loom/internal/fhir/schema" + "github.com/calypr/loom/internal/projectid" ) // explorerCatalogReader assembles the complete catalog before exposing any @@ -20,6 +22,8 @@ import ( // snapshot; callers must never confuse an empty response with a usable one. func explorerCatalogReader(discoverFields func(context.Context, catalog.PopulatedFieldOptions) ([]catalog.PopulatedField, error), discoverReferences func(context.Context, catalog.PopulatedReferenceOptions) ([]catalog.PopulatedReference, error), scopes *authscope.ScopeResolver, manifests dataset.ActiveResolver) func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return func(ctx context.Context, project, _ string, requestedGeneration string) (explorer.CatalogSnapshot, error) { + project = projectid.Canonical(project) + storageProject := projectid.Legacy(project) principal, _ := authscope.PrincipalFromContext(ctx) if err := authscope.AuthorizeProject(principal, project, scopes != nil); err != nil { return explorer.CatalogSnapshot{}, err @@ -27,7 +31,7 @@ func explorerCatalogReader(discoverFields func(context.Context, catalog.Populate generation := requestedGeneration schemaDigest := "" if generation == "" && manifests != nil { - manifest, err := dataset.ResolveActive(ctx, manifests, project) + manifest, err := dataset.ResolveActive(ctx, manifests, storageProject) if err != nil { return incompleteExplorerCatalog(project, generation, "", err) } @@ -35,59 +39,67 @@ func explorerCatalogReader(discoverFields func(context.Context, catalog.Populate } scope := authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted} if scopes != nil { - resolved, err := scopes.ResolveReadScopeForGeneration(ctx, principal, project, generation, nil) + resolved, err := scopes.ResolveReadScopeForGeneration(ctx, principal, storageProject, generation, nil) if err != nil { return incompleteExplorerCatalog(project, generation, schemaDigest, err) } scope = resolved } unrestricted := scope.Unrestricted() - options := catalog.PopulatedFieldOptions{Project: project, DatasetGeneration: generation, AuthResourcePaths: append([]string(nil), scope.AuthResourcePaths...), AuthResourcePathsUnrestricted: &unrestricted} + options := catalog.PopulatedFieldOptions{Project: storageProject, DatasetGeneration: generation, AuthResourcePaths: append([]string(nil), scope.AuthResourcePaths...), AuthResourcePathsUnrestricted: &unrestricted} fields, err := discoverFields(ctx, options) if err != nil { return incompleteExplorerCatalog(project, generation, schemaDigest, err) } - references, err := discoverReferences(ctx, catalog.PopulatedReferenceOptions{Project: project, DatasetGeneration: generation, AuthResourcePaths: append([]string(nil), scope.AuthResourcePaths...), AuthResourcePathsUnrestricted: &unrestricted, Mode: catalog.TraversalModeBuilder}) + references, err := discoverReferences(ctx, catalog.PopulatedReferenceOptions{Project: storageProject, DatasetGeneration: generation, AuthResourcePaths: append([]string(nil), scope.AuthResourcePaths...), AuthResourcePathsUnrestricted: &unrestricted, Mode: catalog.TraversalModeBuilder}) if err != nil { return incompleteExplorerCatalog(project, generation, schemaDigest, err) } assembled := explorer.Catalog{Selections: map[string]explorer.CatalogSelection{}} nodes := map[string]explorer.CatalogNode{} for _, field := range fields { - if field.ResourceType == "" || isLoomMetadataField(field.Path) { + resourceType := canonicalExplorerCatalogResourceType(field.ResourceType) + if resourceType == "" || isLoomMetadataField(field.Path) { continue } - nodeID := explorer.OpaqueID("n_", field.ResourceType) - nodes[nodeID] = explorer.CatalogNode{ID: nodeID, ResourceType: field.ResourceType} - selectionID := explorer.OpaqueID("s_", field.ResourceType+"\x00"+field.Path) - assembled.Selections[selectionID] = explorer.CatalogSelection{ID: selectionID, NodeID: nodeID, FieldRef: explorerFieldRef(field.ResourceType, field.Path), Select: field.Path, LogicalType: field.Kind, Filterable: field.Kind != "object" && field.Kind != "array", Chartable: field.Kind != "object" && field.Kind != "array"} + nodeID := explorer.OpaqueID("n_", resourceType) + nodes[nodeID] = explorer.CatalogNode{ID: nodeID, ResourceType: resourceType} + selectionID := explorer.OpaqueID("s_", resourceType+"\x00"+field.Path) + assembled.Selections[selectionID] = explorer.CatalogSelection{ID: selectionID, NodeID: nodeID, FieldRef: explorerFieldRef(resourceType, field.Path), Select: field.Path, LogicalType: field.Kind, Filterable: field.Kind != "object" && field.Kind != "array", Chartable: field.Kind != "object" && field.Kind != "array"} } for _, reference := range references { - if reference.FromType == "" || reference.ToType == "" { + fromType := canonicalExplorerCatalogResourceType(reference.FromType) + toType := canonicalExplorerCatalogResourceType(reference.ToType) + if fromType == "" || toType == "" { continue } - from, to := explorer.OpaqueID("n_", reference.FromType), explorer.OpaqueID("n_", reference.ToType) - nodes[from] = explorer.CatalogNode{ID: from, ResourceType: reference.FromType} - nodes[to] = explorer.CatalogNode{ID: to, ResourceType: reference.ToType} - assembled.Edges = append(assembled.Edges, explorer.CatalogEdge{ID: explorer.OpaqueID("e_", reference.FromType+"\x00"+reference.Label+"\x00"+reference.ToType), FromNodeID: from, ToNodeID: to, Label: reference.Label}) + from, to := explorer.OpaqueID("n_", fromType), explorer.OpaqueID("n_", toType) + nodes[from] = explorer.CatalogNode{ID: from, ResourceType: fromType} + nodes[to] = explorer.CatalogNode{ID: to, ResourceType: toType} + assembled.Edges = append(assembled.Edges, explorer.CatalogEdge{ID: explorer.OpaqueID("e_", fromType+"\x00"+reference.Label+"\x00"+toType), FromNodeID: from, ToNodeID: to, Label: reference.Label}) } for _, node := range nodes { assembled.Nodes = append(assembled.Nodes, node) } sort.Slice(assembled.Nodes, func(i, j int) bool { return assembled.Nodes[i].ID < assembled.Nodes[j].ID }) sort.Slice(assembled.Edges, func(i, j int) bool { return assembled.Edges[i].ID < assembled.Edges[j].ID }) - snapshot, err := explorer.NewCatalogSnapshot(project, generation, explorerScopeDigest(scope), assembled, true, false, nil) + snapshot, err := explorer.NewCatalogSnapshotWithSchema(project, generation, explorerScopeDigest(scope), schemaDigest, assembled, true, false, nil) if err != nil { return explorer.CatalogSnapshot{}, err } - snapshot.ResolvedSchemaDigest = schemaDigest return snapshot, nil } } +func canonicalExplorerCatalogResourceType(resourceType string) string { + if canonical, ok := fhirschema.ConcreteResourceType(resourceType); ok { + return canonical + } + return "" +} + func incompleteExplorerCatalog(project, generation, schemaDigest string, cause error) (explorer.CatalogSnapshot, error) { - snapshot, err := explorer.NewCatalogSnapshot(project, generation, "unavailable", explorer.Catalog{Selections: map[string]explorer.CatalogSelection{}}, false, false, []explorer.Diagnostic{{Severity: "ERROR", Code: "CATALOG_UNAVAILABLE", Message: cause.Error(), Retryable: true}}) - snapshot.ResolvedSchemaDigest = schemaDigest + snapshot, err := explorer.NewCatalogSnapshotWithSchema(project, generation, "unavailable", schemaDigest, explorer.Catalog{Selections: map[string]explorer.CatalogSelection{}}, false, false, []explorer.Diagnostic{{Severity: "ERROR", Code: "CATALOG_UNAVAILABLE", Message: cause.Error(), Retryable: true}}) return snapshot, err } diff --git a/internal/server/options.go b/internal/server/options.go index d561f8c5..b7cce536 100644 --- a/internal/server/options.go +++ b/internal/server/options.go @@ -34,6 +34,12 @@ type ServerConfig struct { SnapshotRetention time.Duration `yaml:"snapshot_retention"` PublicationWorkerLease time.Duration `yaml:"publication_worker_lease"` PublicationMaxAttempts int `yaml:"publication_max_attempts"` + MigrateExplorerAuthoring bool `yaml:"-"` + MigrationProject string `yaml:"-"` + MigrationExplorerID string `yaml:"-"` + MigrationConfigPath string `yaml:"-"` + MigrationMappingPath string `yaml:"-"` + MigrationAuditOnly bool `yaml:"-"` } type ClickHouseConfig struct { @@ -93,6 +99,12 @@ func parseServerOptions(args []string, handling flag.ErrorHandling) (Config, err dataframerRecipe string recipeBatchRows int recipeBatchBytes int + migrateAuthoring bool + migrationProject string + migrationExplorer string + migrationConfig string + migrationMapping string + migrationAuditOnly bool ) fs := flag.NewFlagSet("arango-fhir-server", handling) fs.StringVar(&configPath, "config", "", "YAML server configuration file") @@ -108,6 +120,12 @@ func parseServerOptions(args []string, handling flag.ErrorHandling) (Config, err fs.StringVar(&dataframerRecipe, "dataframer-recipe", "", "dataframer recipe JSON file (required when ClickHouse is enabled)") fs.IntVar(&recipeBatchRows, "recipe-batch-rows", 1000, "maximum recipe materialization rows per ClickHouse batch") fs.IntVar(&recipeBatchBytes, "recipe-batch-bytes", 4<<20, "maximum recipe materialization bytes per ClickHouse batch") + fs.BoolVar(&migrateAuthoring, "migrate-explorer-authoring", false, "run the one-shot legacy Explorer authoring migration and exit") + fs.StringVar(&migrationProject, "migration-project", "HTAN_INT-BForePC", "project for the one-shot Explorer authoring migration") + fs.StringVar(&migrationExplorer, "migration-explorer", "default", "Explorer identity for the one-shot authoring migration") + fs.StringVar(&migrationConfig, "migration-config", "", "legacy ExplorerConfigV2 JSON to import when the Explorer has no active config") + fs.StringVar(&migrationMapping, "migration-mapping", "", "frontend Builder mapping JSON containing the translated authoring bundle") + fs.BoolVar(&migrationAuditOnly, "migration-audit-only", false, "validate and report the Explorer authoring migration without materializing or activating it") if err := fs.Parse(args); err != nil { return Config{}, err } @@ -125,6 +143,12 @@ func parseServerOptions(args []string, handling flag.ErrorHandling) (Config, err cfg.Server.AllowUnauthenticated = true cfg.Auth.AllowUnauthenticated = true } + cfg.Server.MigrateExplorerAuthoring = migrateAuthoring + cfg.Server.MigrationProject = migrationProject + cfg.Server.MigrationExplorerID = migrationExplorer + cfg.Server.MigrationConfigPath = migrationConfig + cfg.Server.MigrationMappingPath = migrationMapping + cfg.Server.MigrationAuditOnly = migrationAuditOnly if err := cfg.Validate(); err != nil { return Config{}, fmt.Errorf("invalid server config: %w", err) } @@ -146,6 +170,12 @@ func parseServerOptions(args []string, handling flag.ErrorHandling) (Config, err cfg.Server.Dataframer.Recipe = dataframerRecipe cfg.Server.RecipeBatchRows = recipeBatchRows cfg.Server.RecipeBatchBytes = recipeBatchBytes + cfg.Server.MigrateExplorerAuthoring = migrateAuthoring + cfg.Server.MigrationProject = migrationProject + cfg.Server.MigrationExplorerID = migrationExplorer + cfg.Server.MigrationConfigPath = migrationConfig + cfg.Server.MigrationMappingPath = migrationMapping + cfg.Server.MigrationAuditOnly = migrationAuditOnly if noAuth { cfg.Server.AllowUnauthenticated = true cfg.Auth.AllowUnauthenticated = true diff --git a/internal/server/project_id.go b/internal/server/project_id.go new file mode 100644 index 00000000..9cf0d263 --- /dev/null +++ b/internal/server/project_id.go @@ -0,0 +1,20 @@ +package server + +import ( + "net/url" + "strings" + + "github.com/calypr/loom/internal/projectid" + "github.com/gofiber/fiber/v3" +) + +// explorerProjectParam decodes the percent-encoded slash used inside the +// existing /projects/:project route and exposes the canonical public ID to +// the rest of the Explorer HTTP layer. +func explorerProjectParam(c fiber.Ctx) string { + raw := strings.TrimSpace(c.Params("project")) + if decoded, err := url.PathUnescape(raw); err == nil { + raw = decoded + } + return projectid.Canonical(raw) +} diff --git a/internal/server/project_id_test.go b/internal/server/project_id_test.go new file mode 100644 index 00000000..81450292 --- /dev/null +++ b/internal/server/project_id_test.go @@ -0,0 +1,35 @@ +package server + +import ( + "io" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gofiber/fiber/v3" +) + +func TestExplorerProjectParamDecodesEncodedSlash(t *testing.T) { + app := fiber.New() + app.Get("/api/v1/projects/:project", func(c fiber.Ctx) error { + return c.SendString(explorerProjectParam(c)) + }) + + request := httptest.NewRequest(http.MethodGet, "/api/v1/projects/HTAN_INT%2FBForePC", nil) + response, err := app.Test(request) + if err != nil { + t.Fatal(err) + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + t.Fatalf("status = %d, want %d", response.StatusCode, http.StatusOK) + } + body, err := io.ReadAll(response.Body) + if err != nil { + t.Fatal(err) + } + if got := string(body); got != "HTAN_INT/BForePC" { + t.Fatalf("decoded project = %q, want %q", got, "HTAN_INT/BForePC") + } +} diff --git a/internal/server/server.go b/internal/server/server.go index d9a1994d..efca53ae 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -4,6 +4,7 @@ import ( "context" "crypto/sha256" "encoding/hex" + "encoding/json" "errors" "flag" "fmt" @@ -36,7 +37,10 @@ import ( publicationarango "github.com/calypr/loom/internal/dataset/arango" "github.com/calypr/loom/internal/explorer" explorerarango "github.com/calypr/loom/internal/explorer/arango" + "github.com/calypr/loom/internal/explorer/capability" + explorercompilation "github.com/calypr/loom/internal/explorer/compilation" "github.com/calypr/loom/internal/ingest" + "github.com/calypr/loom/internal/projectid" arangostore "github.com/calypr/loom/internal/store/arango" clickhousestore "github.com/calypr/loom/internal/store/clickhouse" ) @@ -290,12 +294,26 @@ func run(ctx context.Context, serverConfig Config) error { if err != nil { return fmt.Errorf("create Explorer store: %w", err) } + capabilitySnapshots, err := explorerarango.NewCapabilitySnapshotStore(lifecycleClient) + if err != nil { + return fmt.Errorf("create Explorer capability snapshot store: %w", err) + } + capabilityResolver, err := newExplorerCapabilityResolver(catalogStore, scopeResolver, activeManifestResolver, capabilitySnapshots) + if err != nil { + return fmt.Errorf("create Explorer capability resolver: %w", err) + } explorerService, err := explorer.NewService(explorerStore) if err != nil { return fmt.Errorf("create Explorer service: %w", err) } explorerMaterializer := explorerBundleMaterializer(recipeEngine, bundleTarget, publishedRegistry, degradation, logger, serverConfig.Server.RecipeBatchRows, serverConfig.Server.RecipeBatchBytes) - explorerCatalog := explorerCatalogReader(discoverFields, discoverReferences, scopeResolver, activeManifestResolver) + explorerCatalog := explorerV2CatalogReader(func(ctx context.Context, project, _ string, requestedGeneration string) (explorer.CatalogSnapshot, error) { + snapshot, resolveErr := capabilityResolver.Resolve(ctx, project, requestedGeneration) + if resolveErr != nil { + return incompleteExplorerCatalog(projectid.Canonical(project), requestedGeneration, "", resolveErr) + } + return legacyCatalogSnapshot(snapshot), nil + }) resolver := graphresolver.NewResolver(graphresolver.ResolverConfig{ DataframeQuery: queryapi.Config{ DiscoverReferences: discoverReferences, @@ -352,6 +370,177 @@ func run(ctx context.Context, serverConfig Config) error { } else if len(deletedGenerations) != 0 { logger.Info("snapshot retention cleanup complete", "deleted_generations", len(deletedGenerations)) } + authoringCompile := func(ctx context.Context, request ExplorerAuthoringV1CompileRequest) (ExplorerAuthoringV1CompileResult, error) { + request.RequestID = firstNonEmpty(request.RequestID, "loom-authoring-migration") + return compileExplorerAuthoringV1(ctx, recipeEngine, explorerCatalog, request) + } + // CompileReceipt is the native V2 path. V1 remains below only for the + // startup migration of already-stored legacy documents. + compileReceipt := func(ctx context.Context, request ExplorerV2ReceiptCompileRequest) (*explorer.CompilationReceipt, error) { + started := time.Now() + authorized := request.Authorized.Clone() + if strings.TrimSpace(authorized.Snapshot.Token) == "" { + var err error + authorized, err = capabilityResolver.ResolveForCompilation(ctx, request.Project, request.SnapshotToken) + if err != nil { + return nil, err + } + } else if authorized.Snapshot.Identity.Project != projectid.Canonical(request.Project) || authorized.Snapshot.ValidateToken(request.SnapshotToken) != nil { + return nil, capability.ErrStaleSnapshot + } + snapshot := authorized.Snapshot + if err := validateAuthorizedReadScope(authorized.Scope, snapshot.Identity.AuthorizationScopeDigest); err != nil { + return nil, capability.ErrStaleSnapshot + } + intentDigest, err := request.Document.Digest() + if err != nil { + return nil, err + } + normalized, err := request.Document.CanonicalJSON() + if err != nil { + return nil, err + } + preflight := explorer.CompilationReceipt{ReceiptFormatVersion: explorer.CurrentReceiptFormatVersion, CompilerContractVersion: explorer.CurrentCompilerContractVersion, Project: projectid.Canonical(request.Project), ExplorerID: request.ExplorerID, IntentDigest: intentDigest, SnapshotToken: request.SnapshotToken, AuthorizationScopeDigest: snapshot.Identity.AuthorizationScopeDigest, CapabilitySchemaDigest: snapshot.Identity.SchemaDigest, SourceGeneration: snapshot.Identity.Generation, NormalizedBundle: normalized} + if key, keyErr := explorer.CompilationKey(preflight); keyErr == nil { + if prior, lookupErr := explorerService.CompilationReceiptByCompilationKey(ctx, request.Project, request.ExplorerID, key); lookupErr == nil && prior != nil && prior.ReceiptFormatVersion == explorer.CurrentReceiptFormatVersion && prior.CompilerContractVersion == explorer.CurrentCompilerContractVersion { + logger.Info("Explorer receipt compile hit", "project", projectid.Canonical(request.Project), "explorer_id", request.ExplorerID, "receipt_id", prior.ID, "duration_ms", time.Since(started).Milliseconds()) + return prior, nil + } + } + translated, err := explorercompilation.Compile(ctx, request.Project, request.ExplorerID, request.Document, snapshot) + if err != nil { + return nil, err + } + resolved, err := recipeEngine.CompileResolvedBundle(ctx, translated.Bundle, recipe.RuntimeBindings{Project: projectid.Legacy(request.Project), DatasetGeneration: snapshot.Identity.Generation, AuthResourcePaths: append([]string(nil), authorized.Scope.AuthResourcePaths...), AuthScopeMode: authorized.Scope.Mode}) + if err != nil { + return nil, err + } + emitted := make([]explorer.EmittedColumn, 0, len(translated.EmittedColumns)) + for _, column := range translated.EmittedColumns { + emitted = append(emitted, explorer.EmittedColumn{EmissionID: column.EmissionID, OutputID: column.OutputID, NodeID: column.NodeID, SelectionID: column.SelectionID, CandidateID: column.CandidateID, OccurrenceID: column.OccurrenceID, PublicColumn: column.PublicColumn, LogicalType: column.LogicalType, Filterable: column.Filterable, Chartable: column.Chartable}) + } + mappings := make([]explorer.IdentityMapping, 0, len(translated.IdentityMappings)) + for _, mapping := range translated.IdentityMappings { + mappings = append(mappings, explorer.IdentityMapping{CandidateID: mapping.CandidateID, OccurrenceID: mapping.OccurrenceID, EmissionIDs: append([]string(nil), mapping.EmissionIDs...)}) + } + contract, err := json.Marshal(translated.OutputContract) + if err != nil { + return nil, err + } + contractDigest, err := explorer.CompilationArtifactDigest(contract) + if err != nil { + return nil, err + } + resolvedRecipeDigest, err := resolved.Bundle.Digest() + if err != nil { + return nil, err + } + compiledConfig, err := compiledExplorerConfigV2(request.Project, request.ExplorerID, translated) + if err != nil { + return nil, err + } + fingerprints := resolvedOutputFingerprints(resolved) + receipt := explorer.CompilationReceipt{ReceiptFormatVersion: explorer.CurrentReceiptFormatVersion, CompilerContractVersion: explorer.CurrentCompilerContractVersion, Project: projectid.Canonical(request.Project), ExplorerID: request.ExplorerID, IntentDigest: intentDigest, SnapshotToken: request.SnapshotToken, AuthorizationScopeDigest: snapshot.Identity.AuthorizationScopeDigest, CapabilitySchemaDigest: snapshot.Identity.SchemaDigest, SourceGeneration: snapshot.Identity.Generation, RecipeDigest: resolved.StoredRecipeDigest, ResolvedRecipeDigest: resolvedRecipeDigest, ResolvedSchemaDigest: resolved.ResolvedSchemaDigest, OutputContractDigest: contractDigest, NormalizedBundle: normalized, Bundle: resolved.Bundle, CompiledConfig: compiledConfig, PublicOutputContract: contract, IdentityMappings: mappings, EmittedColumns: emitted, OutputFingerprints: fingerprints, RequestID: request.RequestID, CreatedAt: time.Now().UTC()} + receipt.CompilationKey, err = explorer.CompilationKey(receipt) + if err != nil { + return nil, err + } + receipt.ID, err = explorer.ReceiptID(receipt) + if err != nil { + return nil, err + } + stored, err := explorerService.StoreCompilationReceipt(ctx, receipt) + if err != nil { + return nil, err + } + receiptBytes := 0 + if raw, marshalErr := json.Marshal(stored); marshalErr == nil { + receiptBytes = len(raw) + } + logger.Info("Explorer receipt compiled", "project", receipt.Project, "explorer_id", receipt.ExplorerID, "receipt_id", receipt.ID, "duration_ms", time.Since(started).Milliseconds(), "receipt_bytes", receiptBytes, "output_count", len(receipt.Bundle.Outputs), "column_count", len(receipt.EmittedColumns)) + return stored, nil + } + lifecycleConfig := ExplorerV2LifecycleConfig{ + Compile: explorerV2Compiler(recipeEngine, explorerCatalog), + CompileReceipt: compileReceipt, + Catalog: explorerCatalog, + Capability: func(ctx context.Context, project, _ string, generation string) (capability.Snapshot, error) { + return capabilityResolver.Resolve(ctx, project, generation) + }, + CapabilityToken: capabilityResolver.ResolveToken, + AuthorizedCapabilityCompile: capabilityResolver.ResolveForCompilation, + AuthorizedCapabilityExecution: capabilityResolver.ResolveForExecution, + Logger: logger, + ReceiptLookup: func(ctx context.Context, project, explorerID, receiptID string) (*explorer.CompilationReceipt, error) { + return explorerService.CompilationReceiptForExplorer(ctx, project, explorerID, receiptID) + }, + Preview: func(ctx context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (map[string][]map[string]any, error) { + return recipeEngine.PreviewBundle(ctx, bundle, bindings) + }, + PreviewReceipt: func(ctx context.Context, receipt *explorer.CompilationReceipt, bindings recipe.RuntimeBindings, visit func(map[string]any) error) (engine.PreviewSummary, error) { + if receipt == nil { + return engine.PreviewSummary{}, fmt.Errorf("compilation receipt is required") + } + resolved, err := recipeEngine.CompileResolvedBundle(ctx, receipt.Bundle, bindings) + if err != nil { + return engine.PreviewSummary{}, &receiptPreviewResolutionError{Err: err} + } + if err := validateReceiptResolution(receipt, resolved); err != nil { + return engine.PreviewSummary{}, &receiptPreviewResolutionError{Err: err} + } + if err := validateReceiptEnginePublicColumns(receipt, resolved); err != nil { + return engine.PreviewSummary{}, &receiptPreviewResolutionError{Err: err} + } + output := "" + if len(bindings.OutputNames) > 0 { + output = bindings.OutputNames[0] + } + return recipeEngine.PreviewOutput(ctx, resolved, engine.PreviewRequest{Output: output, Limit: bindings.PreviewLimit}, visit) + }, + Materialize: explorerMaterializer, + MaterializeReceipt: explorerReceiptMaterializer(recipeEngine, bundleTarget, publishedRegistry, degradation, logger, serverConfig.Server.RecipeBatchRows, serverConfig.Server.RecipeBatchBytes), + ValidateReleaseGeneration: validateExplorerReleaseGeneration, + ActivateRelease: activateExplorerRelease, + AuthoringCompile: authoringCompile, + } + if serverConfig.Server.MigrateExplorerAuthoring { + legacyConfig, configErr := optionalMigrationInput(serverConfig.Server.MigrationConfigPath, "legacy Explorer config") + if configErr != nil { + return configErr + } + legacyMapping, mappingErr := optionalMigrationInput(serverConfig.Server.MigrationMappingPath, "frontend authoring mapping") + if mappingErr != nil { + return mappingErr + } + migrationResolver, resolverErr := newExplorerCapabilityResolver(catalogStore, nil, activeManifestResolver, capabilitySnapshots) + if resolverErr != nil { + return fmt.Errorf("create Explorer migration capability resolver: %w", resolverErr) + } + migrationCatalog := explorerV2CatalogReader(func(ctx context.Context, project, _ string, requestedGeneration string) (explorer.CatalogSnapshot, error) { + snapshot, resolveErr := migrationResolver.Resolve(ctx, project, requestedGeneration) + if resolveErr != nil { + return incompleteExplorerCatalog(projectid.Canonical(project), requestedGeneration, "", resolveErr) + } + return legacyCatalogSnapshot(snapshot), nil + }) + migrationConfig := lifecycleConfig + migrationConfig.Catalog = migrationCatalog + migrationConfig.AuthoringCompile = func(ctx context.Context, request ExplorerAuthoringV1CompileRequest) (ExplorerAuthoringV1CompileResult, error) { + request.RequestID = firstNonEmpty(request.RequestID, "loom-authoring-migration") + return compileExplorerAuthoringV1(ctx, recipeEngine, migrationCatalog, request) + } + report, migrationErr := MigrateLegacyExplorerAuthoring(ctx, explorerService, migrationConfig, ExplorerAuthoringMigrationOptions{ + Project: serverConfig.Server.MigrationProject, ExplorerID: serverConfig.Server.MigrationExplorerID, + Actor: "loom-authoring-migration", RequestID: "loom-authoring-migration-" + serverConfig.Server.MigrationProject, + LegacyConfig: legacyConfig, LegacyMapping: legacyMapping, AuditOnly: serverConfig.Server.MigrationAuditOnly, + }) + if migrationErr != nil { + logger.Error("Explorer authoring migration failed", "report", report, "error", migrationErr) + return fmt.Errorf("Explorer authoring migration failed: %w", migrationErr) + } + logger.Info("Explorer authoring migration complete", "report", report) + return nil + } server, err := httpapi.NewHTTPServer(httpapi.HTTPConfig{Authenticator: authenticator, Authorizer: authorizer, Logger: logger, CoreReadyCheck: func(ctx context.Context) error { return lifecycleClient.QueryRows(ctx, "RETURN {ready: true}", 1, nil, func(map[string]any) error { return nil }) @@ -375,22 +564,8 @@ func run(ctx context.Context, serverConfig Config) error { if scopeResolver == nil { return nil } - scope, err := scopeResolver.ResolveReadScope(ctx, principal, project, nil) - if err != nil || (!scope.Unrestricted() && len(scope.AuthResourcePaths) == 0) { - return authscope.ErrForbidden - } - return nil - }, explorerService, explorerMaterializer, ExplorerV2LifecycleConfig{ - Compile: explorerV2Compiler(recipeEngine, explorerCatalog), - Catalog: explorerCatalog, - Logger: logger, - Preview: func(ctx context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (map[string][]map[string]any, error) { - return recipeEngine.PreviewBundle(ctx, bundle, bindings) - }, - Materialize: explorerMaterializer, - ValidateReleaseGeneration: validateExplorerReleaseGeneration, - ActivateRelease: activateExplorerRelease, - }) + return scopeResolver.AuthorizeReadProject(ctx, principal, project) + }, explorerService, explorerMaterializer, lifecycleConfig) if publicationWorker != nil { go func() { err := publicationWorker.Run(ctx, time.Second, func(workerErr error) { @@ -423,3 +598,17 @@ func run(ctx context.Context, serverConfig Config) error { } return nil } + +func optionalMigrationInput(path, description string) ([]byte, error) { + if strings.TrimSpace(path) == "" { + return nil, nil + } + raw, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("read %s %q: %w", description, path, err) + } + if len(strings.TrimSpace(string(raw))) == 0 { + return nil, fmt.Errorf("read %s %q: file is empty", description, path) + } + return raw, nil +} diff --git a/internal/server/wiring_test.go b/internal/server/wiring_test.go index d7736809..a6c2ee7f 100644 --- a/internal/server/wiring_test.go +++ b/internal/server/wiring_test.go @@ -44,3 +44,14 @@ func TestRecipeScopeDigestDistinguishesRestrictedEmptyScope(t *testing.T) { t.Fatal("restricted-empty and unrestricted bindings shared a scope digest") } } + +func TestCanonicalExplorerCatalogResourceTypeCanonicalizesFHIRCase(t *testing.T) { + if got := canonicalExplorerCatalogResourceType(" specimen "); got != "Specimen" { + t.Fatalf("canonical resource type = %q, want Specimen", got) + } + for _, invalid := range []string{"CustomResource", "PractitionerQualification", "qualification", "issuer", "Resource"} { + if got := canonicalExplorerCatalogResourceType(invalid); got != "" { + t.Fatalf("non-resource type %q was exposed as %q", invalid, got) + } + } +} diff --git a/internal/store/arango/client.go b/internal/store/arango/client.go index 94c343dd..97c85d5a 100644 --- a/internal/store/arango/client.go +++ b/internal/store/arango/client.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "io" "net" @@ -182,26 +183,51 @@ func (t transactionClient) QueryRows(ctx context.Context, query string, batchSiz return queryRows(ctx, t.queryer, query, batchSize, bindVars, visit) } -func queryRows(ctx context.Context, queryer driver.DatabaseQuery, query string, batchSize int, bindVars map[string]interface{}, visit RowVisitor) error { +func queryRows(ctx context.Context, queryer driver.DatabaseQuery, query string, batchSize int, bindVars map[string]interface{}, visit RowVisitor) (resultErr error) { + if err := ctx.Err(); err != nil { + return err + } cursor, err := queryer.Query(ctx, query, &driver.QueryOptions{BatchSize: batchSize, BindVars: bindVars}) if err != nil { - return err + return fmt.Errorf("arango query: %w", err) } - defer cursor.Close() - for cursor.HasMore() { + defer func() { + closeErr := cursor.Close() + if closeErr != nil { + wrapped := fmt.Errorf("close arango query cursor: %w", closeErr) + resultErr = errors.Join(resultErr, wrapped) + } + }() + for { + if err := ctx.Err(); err != nil { + resultErr = err + return resultErr + } + if !cursor.HasMore() { + return resultErr + } var row map[string]any _, err := cursor.ReadDocument(ctx, &row) if err != nil { + if ctxErr := ctx.Err(); ctxErr != nil { + resultErr = ctxErr + return resultErr + } if shared.IsNoMoreDocuments(err) { - return nil + return resultErr } - return err + resultErr = fmt.Errorf("read arango query cursor: %w", err) + return resultErr + } + if err := ctx.Err(); err != nil { + resultErr = err + return resultErr } if err := visit(row); err != nil { - return err + resultErr = err + return resultErr } } - return nil } func (c *Client) CollectionExists(ctx context.Context, name string) (bool, error) { diff --git a/internal/store/arango/client_queryrows_test.go b/internal/store/arango/client_queryrows_test.go new file mode 100644 index 00000000..515b246b --- /dev/null +++ b/internal/store/arango/client_queryrows_test.go @@ -0,0 +1,144 @@ +package arango + +import ( + "context" + "errors" + "strings" + "testing" + + driver "github.com/arangodb/go-driver/v2/arangodb" + "github.com/arangodb/go-driver/v2/arangodb/shared" +) + +type fakeQueryer struct { + driver.DatabaseQuery + cursor driver.Cursor + err error + called int +} + +func (q *fakeQueryer) Query(context.Context, string, *driver.QueryOptions) (driver.Cursor, error) { + q.called++ + if q.err != nil { + return nil, q.err + } + return q.cursor, nil +} + +type fakeCursor struct { + driver.Cursor + rows []map[string]any + readErr error + closeErr error + closeCount int + hasMore int + readCount int + onRead func() +} + +func (c *fakeCursor) HasMore() bool { + c.hasMore++ + return c.readCount < len(c.rows) +} + +func (c *fakeCursor) ReadDocument(_ context.Context, result interface{}) (driver.DocumentMeta, error) { + c.readCount++ + if c.onRead != nil { + c.onRead() + } + if c.readErr != nil { + return driver.DocumentMeta{}, c.readErr + } + if c.readCount > len(c.rows) { + return driver.DocumentMeta{}, shared.NoMoreDocumentsError{} + } + *(result.(*map[string]any)) = c.rows[c.readCount-1] + return driver.DocumentMeta{}, nil +} + +func (c *fakeCursor) Close() error { + c.closeCount++ + return c.closeErr +} + +func TestQueryRowsChecksCancellationBeforeQuery(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + queryer := &fakeQueryer{cursor: &fakeCursor{}} + if err := queryRows(ctx, queryer, "RETURN 1", 1, nil, func(map[string]any) error { return nil }); !errors.Is(err, context.Canceled) { + t.Fatalf("error=%v", err) + } + if queryer.called != 0 { + t.Fatalf("query called %d times", queryer.called) + } +} + +func TestQueryRowsWrapsDriverQueryError(t *testing.T) { + want := errors.New("driver query failure") + queryer := &fakeQueryer{err: want} + err := queryRows(context.Background(), queryer, "RETURN 1", 1, nil, func(map[string]any) error { return nil }) + if !errors.Is(err, want) || !strings.Contains(err.Error(), "arango query") { + t.Fatalf("error=%v", err) + } +} + +func TestQueryRowsClosesCursorOnVisitorError(t *testing.T) { + want := errors.New("visitor stopped") + cursor := &fakeCursor{rows: []map[string]any{{"id": "1"}}} + queryer := &fakeQueryer{cursor: cursor} + err := queryRows(context.Background(), queryer, "RETURN 1", 1, nil, func(map[string]any) error { return want }) + if !errors.Is(err, want) || cursor.closeCount != 1 { + t.Fatalf("error=%v closeCount=%d", err, cursor.closeCount) + } +} + +func TestQueryRowsChecksCancellationBeforeHasMoreAndVisitor(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cursor := &fakeCursor{rows: []map[string]any{{"id": "1"}, {"id": "2"}}} + queryer := &fakeQueryer{cursor: cursor} + visited := 0 + err := queryRows(ctx, queryer, "RETURN 1", 1, nil, func(map[string]any) error { + visited++ + cancel() + return nil + }) + if !errors.Is(err, context.Canceled) || visited != 1 || cursor.hasMore != 1 || cursor.closeCount != 1 { + t.Fatalf("error=%v visited=%d hasMore=%d closeCount=%d", err, visited, cursor.hasMore, cursor.closeCount) + } +} + +func TestQueryRowsChecksCancellationBeforeVisitor(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cursor := &fakeCursor{rows: []map[string]any{{"id": "1"}}, onRead: cancel} + queryer := &fakeQueryer{cursor: cursor} + visited := 0 + err := queryRows(ctx, queryer, "RETURN 1", 1, nil, func(map[string]any) error { visited++; return nil }) + if !errors.Is(err, context.Canceled) || visited != 0 || cursor.closeCount != 1 { + t.Fatalf("error=%v visited=%d closeCount=%d", err, visited, cursor.closeCount) + } +} + +func TestQueryRowsWrapsDriverReadAndCloseErrors(t *testing.T) { + readErr := errors.New("driver read failure") + closeErr := errors.New("driver close failure") + cursor := &fakeCursor{rows: []map[string]any{{"id": "1"}}, readErr: readErr, closeErr: closeErr} + queryer := &fakeQueryer{cursor: cursor} + err := queryRows(context.Background(), queryer, "RETURN 1", 1, nil, func(map[string]any) error { return nil }) + if !errors.Is(err, readErr) || !errors.Is(err, closeErr) { + t.Fatalf("error=%v", err) + } + if !strings.Contains(err.Error(), "read arango query cursor") || !strings.Contains(err.Error(), "close arango query cursor") { + t.Fatalf("missing wrapped driver context: %v", err) + } +} + +func TestQueryRowsClosesCursorOnSuccess(t *testing.T) { + cursor := &fakeCursor{} + queryer := &fakeQueryer{cursor: cursor} + if err := queryRows(context.Background(), queryer, "RETURN 1", 1, nil, func(map[string]any) error { return nil }); err != nil { + t.Fatal(err) + } + if cursor.closeCount != 1 { + t.Fatalf("closeCount=%d", cursor.closeCount) + } +} diff --git a/internal/store/arango/profile_integration_test.go b/internal/store/arango/profile_integration_test.go index 3c88d198..c3c8427f 100644 --- a/internal/store/arango/profile_integration_test.go +++ b/internal/store/arango/profile_integration_test.go @@ -180,6 +180,106 @@ func TestCompoundEdgeIndexExplainAgainstArango(t *testing.T) { } } +// TestReceiptPreviewExplainAgainstArango is an opt-in contract smoke test for +// the canonical query shapes emitted from immutable compilation receipts. It +// deliberately asserts only that Arango can produce a plan (and records index +// observations); physical index choice can vary with the provisioned corpus +// and optimizer version. +func TestReceiptPreviewExplainAgainstArango(t *testing.T) { + if os.Getenv("LOOM_COMPILER_ARANGO_INTEGRATION") == "" { + t.Skip("set LOOM_COMPILER_ARANGO_INTEGRATION=1 to run receipt preview EXPLAIN fixtures") + } + url := os.Getenv("LOOM_ARANGO_URL") + if url == "" { + url = "http://127.0.0.1:8529" + } + database := os.Getenv("LOOM_ARANGO_DATABASE") + if database == "" { + database = "fhir_proto" + } + project := os.Getenv("LOOM_ARANGO_PROJECT") + if project == "" { + project = "ARANGODB_PROTO" + } + client, err := Open(context.Background(), url, database) + if err != nil { + t.Fatalf("open Arango: %v", err) + } + defer client.Close(context.Background()) + for _, shape := range receiptPreviewCorpus(project) { + shape := shape + t.Run(shape.name, func(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + result, err := client.Explain(ctx, ExplainRequest{Query: shape.query, BindVars: shape.bindVars}) + if err != nil { + t.Fatalf("EXPLAIN %s: %v\nAQL:\n%s", shape.name, err, shape.query) + } + assessment := AssessExplainResult(result) + if result.Plan == nil && len(result.Plans) == 0 { + t.Fatalf("EXPLAIN %s returned no plan", shape.name) + } + t.Logf("receipt preview shape=%s indexes=%#v full_scans=%#v", shape.name, assessment.Indexes, assessment.FullCollectionScans) + }) + } +} + +func receiptPreviewCorpus(project string) []profileCorpusShape { + return []profileCorpusShape{ + { + name: "project-generation-sort-limit", + query: `FOR root IN Patient + FILTER root.project == @project + FILTER root.dataset_generation == @generation + SORT root._key ASC + LIMIT @limit + RETURN {"_key": root._key}`, + bindVars: map[string]any{"project": project, "generation": "generation-a", "limit": 5}, + }, + { + name: "restricted-scope-sort-limit", + query: `FOR root IN Patient + FILTER root.project == @project + FILTER root.dataset_generation == @generation + FILTER root.auth_resource_path IN @auth_paths + SORT root._key ASC + LIMIT @limit + RETURN {"_key": root._key}`, + bindVars: map[string]any{"project": project, "generation": "generation-a", "auth_paths": []string{"Patient/one", "Patient/two"}, "limit": 5}, + }, + { + name: "relationship-inbound-direction", + query: `FOR root IN Patient + FILTER root.project == @project + FILTER root.dataset_generation == @generation + SORT root._key ASC + LIMIT @limit + LET related = (FOR node, edge IN 1..1 INBOUND root fhir_edge + FILTER edge._to == root._id + FILTER edge.project == @project AND edge.dataset_generation == @generation + FILTER edge.label == @label + RETURN node._key) + RETURN {"_key": root._key, "related": related}`, + bindVars: map[string]any{"project": project, "generation": "generation-a", "label": "subject_Patient", "limit": 5}, + }, + { + name: "relationship-outbound-direction", + query: `FOR root IN ResearchSubject + FILTER root.project == @project + FILTER root.dataset_generation == @generation + SORT root._key ASC + LIMIT @limit + LET related = (FOR node, edge IN 1..1 OUTBOUND root fhir_edge + FILTER edge._from == root._id + FILTER edge.project == @project AND edge.dataset_generation == @generation + FILTER edge.label == @label + RETURN node._key) + RETURN {"_key": root._key, "related": related}`, + bindVars: map[string]any{"project": project, "generation": "generation-a", "label": "study", "limit": 5}, + }, + } +} + func assessmentHasIndexCollection(assessment ExplainAssessment, collection string) bool { for _, index := range assessment.Indexes { if index.Collection == collection { From a1d6de5ebabded8a1d083ad2c6d5faa805d33c00 Mon Sep 17 00:00:00 2001 From: matthewpeterkort Date: Wed, 26 Aug 2026 13:55:50 -0700 Subject: [PATCH 08/15] somewhat stable --- Dockerfile | 4 +- Makefile | 9 +- docs/CODE_GENERATION.md | 1 + docs/DATAFRAMER_RECIPES.md | 26 +- docs/DATAFRAMER_RECIPE_REFERENCE.md | 10 +- docs/DEVELOPER_ARCHITECTURE.md | 99 +- docs/EXPLORER_AUTHORING.md | 91 ++ docs/EXPLORER_COMPILATION_ARCHITECTURE.md | 239 +++ docs/EXPLORER_RECIPE_BOUNDARY.md | 546 +++++++ docs/FRONTEND_EXPLORER_V2_MIGRATION.md | 18 +- docs/GRAPHQL_API.md | 12 +- docs/LOOM _CLEANUP.md | 93 ++ docs/LOOM_EXPLORER_ARCHITECTURE_POSTMORTEM.md | 1437 +++++++++++++++++ docs/QUICKSTART.md | 18 +- docs/README.md | 48 + .../explorer-v2-capability-authoring.md | 234 +++ go.mod | 4 +- go.sum | 19 +- internal/catalog/arango/store.go | 20 +- internal/catalog/arango/store_test.go | 74 +- .../arango/capability_snapshot_store.go | 1 - .../arango/capability_snapshot_store_test.go | 24 + .../explorer/arango/receipt_store_test.go | 2 +- internal/explorer/authoringv2/types.go | 344 +++- internal/explorer/authoringv2/types_test.go | 10 +- .../explorer/authoringv2/workspace_test.go | 119 ++ internal/explorer/compilation.go | 22 +- internal/explorer/compilation/translate.go | 204 ++- .../explorer/compilation/translate_test.go | 23 +- .../explorer/compilation/workspace_test.go | 34 + internal/explorer/compilation_receipt.go | 14 +- internal/explorer/compilation_receipt_test.go | 2 +- internal/explorer/config_v2.go | 1 + internal/explorer/output_contract.go | 137 +- internal/explorer/output_contract_test.go | 110 +- .../explorer_authoring_error_logging_test.go | 71 + .../server/explorer_authoring_migration.go | 58 +- .../explorer_authoring_migration_test.go | 99 ++ .../server/explorer_authoring_v1_routes.go | 38 +- .../explorer_authoring_v2_migration_test.go | 63 + .../server/explorer_authoring_v2_routes.go | 398 ++++- internal/server/explorer_capability.go | 15 +- internal/server/explorer_capability_test.go | 2 +- internal/server/explorer_preview_response.go | 53 +- .../server/explorer_preview_response_test.go | 2 +- internal/server/explorer_preview_security.go | 9 +- .../server/explorer_preview_security_test.go | 23 +- internal/server/explorer_receipt_contract.go | 73 + .../server/explorer_receipt_contract_test.go | 75 +- internal/server/explorer_v2_lifecycle.go | 2 + internal/server/server.go | 33 +- 51 files changed, 4679 insertions(+), 384 deletions(-) create mode 100644 docs/EXPLORER_AUTHORING.md create mode 100644 docs/EXPLORER_COMPILATION_ARCHITECTURE.md create mode 100644 docs/EXPLORER_RECIPE_BOUNDARY.md create mode 100644 docs/LOOM _CLEANUP.md create mode 100644 docs/LOOM_EXPLORER_ARCHITECTURE_POSTMORTEM.md create mode 100644 docs/README.md create mode 100644 docs/frontend/explorer-v2-capability-authoring.md create mode 100644 internal/explorer/authoringv2/workspace_test.go create mode 100644 internal/explorer/compilation/workspace_test.go create mode 100644 internal/server/explorer_authoring_error_logging_test.go create mode 100644 internal/server/explorer_authoring_v2_migration_test.go diff --git a/Dockerfile b/Dockerfile index 7822fdb0..cc16b168 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,9 +14,7 @@ RUN --mount=type=cache,target=/go/pkg/mod \ go mod download COPY cmd ./cmd -COPY generated/fhir ./generated/fhir -COPY generated/fhirschema ./generated/fhirschema -COPY generated/graphql ./generated/graphql +COPY generated ./generated COPY internal ./internal COPY schemas ./schemas diff --git a/Makefile b/Makefile index 1aec84ea..3e3f2cae 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: build build-cli build-server clean compiler-bench dataframe-demo dataframe-profile dataframe-boundaries dataframe-test conformance generate-fhir generate-graphql graphql-check gqlgen-check test docker-build docker-run +.PHONY: build build-cli build-server clean compiler-bench dataframe-demo dataframe-profile dataframe-boundaries dataframe-test conformance generate generate-explorer-v2 generate-fhir generate-graphql graphql-check gqlgen-check test docker-build docker-run GO ?= go GO_VERSION ?= 1.26.5 @@ -6,6 +6,7 @@ GO_TOOLCHAIN ?= go$(GO_VERSION) GOCACHE_DIR ?= $(CURDIR)/.gocache GOFLAGS ?= SCHEMA_PATH ?= schemas/graph-fhir.json +OAPI_CODEGEN_VERSION ?= v2.8.0 IMAGE ?= arango-fhir-proto:local GRAPHQL_URL ?= http://127.0.0.1:8080/graphql/dataframe DATAFRAME_REPEAT ?= 1 @@ -19,6 +20,8 @@ DATAFRAME_PROFILE_LIMIT ?= 1000 build: build-cli build-server +generate: generate-fhir generate-graphql generate-explorer-v2 + build-cli: mkdir -p bin $(GOCACHE_DIR) GOCACHE=$(GOCACHE_DIR) GOTOOLCHAIN=$(GO_TOOLCHAIN) $(GO) build $(GOFLAGS) -o bin/arango-fhir-proto ./cmd/arango-fhir-proto @@ -37,6 +40,10 @@ generate-fhir: GOCACHE=$(GOCACHE_DIR) GOTOOLCHAIN=$(GO_TOOLCHAIN) $(GO) run ./cmd/generate -schema $(SCHEMA_PATH) -structs-out generated/fhir -metadata-out generated/fhirschema/generated.go gofmt -w generated/fhir/*.go generated/fhirschema/generated.go +generate-explorer-v2: + mkdir -p generated/explorerv2 $(GOCACHE_DIR) + GOCACHE=$(GOCACHE_DIR) GOTOOLCHAIN=$(GO_TOOLCHAIN) $(GO) run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@$(OAPI_CODEGEN_VERSION) --config schemas/explorer-authoring-v2/oapi-codegen.yaml schemas/explorer-authoring-v2/openapi.yaml + graphql-check: mkdir -p $(GOCACHE_DIR) GOCACHE=$(GOCACHE_DIR) GOTOOLCHAIN=$(GO_TOOLCHAIN) $(GO) test $(GOFLAGS) ./internal/api/graphql/... ./generated/graphql/... -count=1 diff --git a/docs/CODE_GENERATION.md b/docs/CODE_GENERATION.md index 70836b77..0836ecd9 100644 --- a/docs/CODE_GENERATION.md +++ b/docs/CODE_GENERATION.md @@ -50,6 +50,7 @@ The handwritten GraphQL inputs and runtime wiring are deliberately separate: | --- | --- | --- | | `schemas/graph-fhir.json` and `cmd/generate/` | `make generate-fhir` | `generated/fhir/*.go`, `generated/fhirschema/generated.go`, and `generated/graphql/graph/schema/fhir_schema.graphqls` | | `internal/api/graphql/graph/schema/schema.graphqls`, generated FHIR SDL, and `gqlgen.yml` | `make generate-graphql` | Primary executor, models, and resolver bindings under `generated/graphql/graph/` and `internal/api/graphql/graph/resolver/` | +| `schemas/explorer-authoring-v2/openapi.yaml` and its oapi-codegen config | `make generate-explorer-v2` | Explorer V2 wire models and Fiber v3 strict-server interfaces under `generated/explorerv2/` | `generated/graphql/graph/executor/fhir_schema.generated.go` and `generated/graphql/graph/executor/root_.generated.go` are diff --git a/docs/DATAFRAMER_RECIPES.md b/docs/DATAFRAMER_RECIPES.md index 14e805fe..99295083 100644 --- a/docs/DATAFRAMER_RECIPES.md +++ b/docs/DATAFRAMER_RECIPES.md @@ -16,13 +16,20 @@ selected fields, and bounded column discovery. It does not contain project IDs, authorization paths, Arango collection names, AQL, ClickHouse table names, or SQL. +This document describes the native recipe language used by repository, ETL, +and developer workflows. It is not the browser Builder contract. The Builder +sends the intent-only V1 document described in +[`EXPLORER_AUTHORING.md`](EXPLORER_AUTHORING.md); Loom lowers that document to +a native recipe and then runs the recipe compiler described here. Do not make +frontend code construct or repair recipe ASTs. + The deployed default is ordinary JSON loaded from `server.dataframer.recipe`. It is required only when ClickHouse is enabled. -Loom does not currently provide a graphical recipe builder. A frontend builder -is the intended normal authoring experience. Until that exists, do not write a -recipe from memory: discover the loaded graph, prototype the shape through -`runFhirDataframe`, and then promote the proven shape into a persistent recipe. +For direct recipe authoring, do not write a recipe from memory: discover the +loaded graph, prototype the shape through `runFhirDataframe`, and then promote +the proven shape into a persistent recipe. For Builder authoring, use the V1 +REST contract instead of this native recipe format. ## Recommended workflow @@ -149,11 +156,12 @@ must deliberately produce multiple rows. ## Step 2: discover the graph that is actually loaded -Use the REST V2 authoring compiler and its server-owned catalog discovery. It -reports populated fields, pivot candidates, and valid outbound relationships -for the selected generation. Do not infer relationship labels from FHIR -property names or manufacture browser selector IDs. See -[`FRONTEND_EXPLORER_V2_MIGRATION.md`](FRONTEND_EXPLORER_V2_MIGRATION.md). +Use the REST V1 authoring compiler and its server-owned catalog discovery. It +reports populated fields, route candidates, and valid relationships for the +selected generation. Do not infer relationship labels from FHIR property names +or manufacture browser selector IDs. See +[`EXPLORER_AUTHORING.md`](EXPLORER_AUTHORING.md). The V2 migration guide is +historical and retained only for compatibility context. For a second hop, select the first-hop target in the authoring request. For example: diff --git a/docs/DATAFRAMER_RECIPE_REFERENCE.md b/docs/DATAFRAMER_RECIPE_REFERENCE.md index a1e1b9d0..4b80c68b 100644 --- a/docs/DATAFRAMER_RECIPE_REFERENCE.md +++ b/docs/DATAFRAMER_RECIPE_REFERENCE.md @@ -1,9 +1,11 @@ # Dataframer recipe reference and operating manual -This is the field-by-field reference for Loom dataframer recipes. Read the -[authoring guide](DATAFRAMER_RECIPES.md) first for the short workflow; use this -document when making a real change, reviewing one, or diagnosing an unexpected -column. +This is the field-by-field reference for Loom's native dataframer recipes. +Read the [recipe authoring guide](DATAFRAMER_RECIPES.md) first for the short +workflow; use this document when making a real change, reviewing one, or +diagnosing an unexpected column. Browser Builder authoring is documented in +[EXPLORER_AUTHORING.md](EXPLORER_AUTHORING.md) and should not construct these +recipe packets directly. The goal of a recipe is to describe a stable, reviewable mapping from FHIR resources and relationships to dataframe rows. It is deliberately independent diff --git a/docs/DEVELOPER_ARCHITECTURE.md b/docs/DEVELOPER_ARCHITECTURE.md index fb3d9fbd..f54f6ecd 100644 --- a/docs/DEVELOPER_ARCHITECTURE.md +++ b/docs/DEVELOPER_ARCHITECTURE.md @@ -31,9 +31,10 @@ they do not live in `generated/`. ## Runtime surfaces The Builder integration contract is documented in -[`FRONTEND_EXPLORER_V2_MIGRATION.md`](FRONTEND_EXPLORER_V2_MIGRATION.md). -The Builder uses the REST Explorer lifecycle. GraphQL does not expose Explorer -lifecycle or authoring types; REST V2 is the only Explorer contract. +[`EXPLORER_AUTHORING.md`](EXPLORER_AUTHORING.md). The Builder uses the REST +Explorer lifecycle and submits V1 intent; GraphQL does not expose Explorer +lifecycle or authoring types. The old V2 packet guide is retained for +compatibility and ETL migration context, not as the current Builder contract. Ownership map: `dataset` owns immutable FHIR generation lifecycle; `catalog` owns persistence-neutral observed facts; `catalog/arango` owns catalog @@ -47,6 +48,14 @@ runner; `dataframe/publication/{arango,clickhouse}` own storage adapters; and - `load` for the temporary mutable compatibility load; - `load-generation` for a complete immutable dataset generation; +- `audit-relationship-edges` for a read-only scan of invalid graph endpoint + types; +- `rebuild-relationship-catalog` for an explicit catalog rebuild after an + edge repair or backfill; +- `repair-generation` for staging a corrected immutable generation from the + original source files; activation requires its explicit `--activate` flag; +- `activate-generation` for validating and activating a previously staged + generation; - `discover-populated-references` and `discover-populated-fields` for catalog diagnostics. @@ -54,15 +63,19 @@ runner; `dataframe/publication/{arango,clickhouse}` own storage adapters; and developer GraphQL tools, and the primary project/resourceType upload endpoint. Complete immutable generations remain an explicit CLI/load workflow. -The GraphQL dataframe mutation is the live compiler transport. Do not add a -second query compiler or hand-maintained AQL path behind another endpoint. +The GraphQL dataframe mutation is the live compiler transport. Explorer V1 +authoring adds an intent-to-native-recipe lowering phase, then calls the same +recipe resolver/compiler and AQL renderer. Do not add a second query compiler +or hand-maintained AQL path behind another endpoint. See +[`EXPLORER_COMPILATION_ARCHITECTURE.md`](EXPLORER_COMPILATION_ARCHITECTURE.md) +for the complete Builder-to-AQL sequence. The HTTP API names its backend boundaries explicitly. `/graphql/graph` is the Arango graph/control-plane GraphQL endpoint and published ClickHouse dataframe reader, while `/graphql/dataframe` is the Arango-backed FHIR dataframe -compiler endpoint. Published ClickHouse dataframe discovery and reads follow the stable-GraphQL, -dynamic-data contract defined in -[`CLICKHOUSE_GRAPHQL_READER_EXECUTION_PLAN.md`](CLICKHOUSE_GRAPHQL_READER_EXECUTION_PLAN.md). +compiler endpoint. Published ClickHouse dataframe discovery and reads follow the +stable-GraphQL, dynamic-data contract described in +[`DATAFRAME_FEDERATION.md`](DATAFRAME_FEDERATION.md). Only registered READY publication outputs are exposed; adding a dataset or column must not require GraphQL regeneration or a Loom restart. Publication and published-data reads are ClickHouse-only; Loom has no Elasticsearch @@ -98,6 +111,69 @@ project. The generation-qualified physical keys and mandatory generation predicates are part of the query correctness contract, not an optional filter. +Graph resource identity is schema-owned. Only concrete FHIR root types may +appear as vertex collections, edge endpoints, row grains, or relationship +catalog types. Backbone and other nested definitions remain available to +field/selector resolution but are rejected at graph boundaries. Use +`arango-fhir-proto audit-relationship-edges` to inspect historical generations +for invalid endpoint types. A catalog rebuild filters those rows from the +rebuilt catalog, but does not rewrite `fhir_edge`; malformed generations must +be re-ingested into a new immutable generation before activation. The +`repair-generation` command performs that workflow: it audits the source, +loads the supplied source directory into a distinct staged generation, audits +the result, and leaves the old active generation untouched unless +`--activate` is explicitly supplied. + +For example: + +```bash +./bin/arango-fhir-proto repair-generation \ + --project ARANGODB_PROTO \ + --source-generation load:old \ + --generation load:repaired \ + --meta-dir META +``` + +The command stages the target and reports its audit. Activate it separately +after reviewing that the target audit reports zero invalid edges: + +```bash +./bin/arango-fhir-proto activate-generation \ + --project ARANGODB_PROTO \ + --generation load:repaired \ + --url http://127.0.0.1:8529 \ + --database fhir_proto +``` + +For an automated one-shot repair, `repair-generation --activate` performs the +same validation before activation. + +Generation repair is deliberately memory-bounded. The loader caps catalog +distinct values, pivot columns, extension observations, cached payload shapes, +and retained field paths; it also bounds parser workers and queued input/write +batches. The CLI applies a Go soft memory limit by default and exposes the +operational controls explicitly: + +```bash +./bin/arango-fhir-proto repair-generation \ + --project ARANGODB_PROTO \ + --source-generation load:old \ + --generation load:repaired \ + --meta-dir META \ + --memory-limit 4GiB \ + --workers 2 \ + --writers 2 \ + --line-queue-size 1024 \ + --write-queue-size 8 +``` + +The Go limit is a GC target, not a substitute for a Kubernetes cgroup limit. +Run the operator binary as a separate one-shot migration workload with an +explicit memory request and limit; do not run a large repair inside the +long-lived server container. The Docker image includes `/app/arango-fhir-proto` +for that purpose, and the image target architecture is used so local arm64 +clusters do not invoke Rosetta for the migration process. + ## Compiler path The current runtime call path is: @@ -163,10 +239,9 @@ When adding code, use this lookup table: | AQL text or bind emission | `internal/dataframe/compiler/render/aql` | | Catalog, auth, generation, cursor, or profiling | `internal/dataframe/runtime` | -For the complete ownership map and move history, see -[`DATAFRAME_PACKAGE_REORGANIZATION_PLAN.md`](DATAFRAME_PACKAGE_REORGANIZATION_PLAN.md) -and the current compiler split plan -[`DATAFRAME_PACKAGE_REORGANIZATION_ROUND_2.md`](DATAFRAME_PACKAGE_REORGANIZATION_ROUND_2.md). +For the complete ownership map, see the package guide in this document and the +[documentation index](README.md). Historical package-reorganization plans may +exist outside this checkout, but they are not runtime contract references. ## Compatibility tracks diff --git a/docs/EXPLORER_AUTHORING.md b/docs/EXPLORER_AUTHORING.md new file mode 100644 index 00000000..ebfcf3ce --- /dev/null +++ b/docs/EXPLORER_AUTHORING.md @@ -0,0 +1,91 @@ +# Explorer authoring + +The public Builder contract is +`loom.calypr.org/explorer-authoring/v2`. The browser submits semantic intent +using opaque node, relationship, candidate, occurrence, and receipt IDs. Loom +owns recipe construction, output-column identities, authorization predicates, +physical planning, and AQL. + +For the complete wire contract and frontend checklist, see +[Explorer V2 capability authoring](frontend/explorer-v2-capability-authoring.md). +For the compiler and receipt internals, see +[Explorer compilation architecture](EXPLORER_COMPILATION_ARCHITECTURE.md). + +## Endpoints + +All routes are under: + +```text +/api/v1/projects/:project/explorers/:explorerId/authoring/v2 +``` + +| Operation | Route | Contract | +| --- | --- | --- | +| Read capability | `GET /capability` | exact active compiler-proven snapshot | +| Read Builder | `GET /builder` | capability plus active V2 document when present | +| Compile | `POST /compile` | `{document, snapshotToken}` | +| Compile alias | `POST /builder` | same operation for the current frontend | +| Suggestions | `GET /capabilities/:snapshotToken/candidates/:candidateId/suggestions` | bounded values for one exact snapshot | +| Preview | `POST /preview` | `{receiptId, outputId, limit?}` | +| Publish | `POST /publish` | `{receiptId}` | + +There is no public V1 authoring route. V1 types and the V1 compiler exist only +to migrate already stored legacy authoring documents. + +## Builder document + +A V2 document contains one output, a concrete row-root node, an ordered finite +route, occurrence-specific field selections, projection modes, and presentation +preferences. It contains no FHIR selector path, recipe expression, traversal +alias, collection name, AQL, or generated output column. + +Route steps select only relationship IDs advertised by the capability snapshot. +Each repeated route position has its own occurrence ID, so selecting a field on +one repeated resource is not ambiguous with another. Empty routes, finite long +routes, repeated edges, and self-loops work only when the snapshot advertises +them. + +## Compile and receipts + +Compile validates the exact active snapshot and authorization scope, translates +the document directly to a resolved Loom recipe, persists an immutable receipt, +and returns the receipt ID plus compiler-owned emitted columns. The same +canonical input is idempotent. + +An editor state with no selected columns may compile so the frontend can +reconcile intermediate edits. It cannot publish; Loom returns +`NO_SELECTED_COLUMNS`. + +Preview and publish require the receipt. They do not accept mutable authoring +intent and do not silently compile against a newer catalog or generation. +Artifactless receipts created by older servers return +`RECEIPT_RECOMPILE_REQUIRED`. + +## Draft and publication behavior + +The browser may keep its mutable V2 document locally and debounce compile. +Compile-before-preview is the safe fallback when the latest editor state has no +receipt. Concurrent compile responses cannot overwrite each other because each +receipt is immutable and content-addressed. + +Publish materializes and verifies the exact receipt before activating its +revision. A materialization, output-verification, or activation failure leaves +the previous active revision intact. Active revisions retain the canonical V2 +document so Builder reads can restore it directly. + +## Authorization and generation rules + +Compilation requires the snapshot's generation to be active. Preview may use a +retained inactive generation if the caller remains authorized for the exact +scope captured by the snapshot. Publication additionally requires the receipt +generation to remain active. + +Restricted-empty authorization is not equivalent to unrestricted access. Loom +propagates the explicit scope mode and paths through deterministic lowering and +execution. The frontend never supplies those predicates. + +## Cleanup + +Receipts referenced by immutable revisions are retained. Loom exposes receipt +count and approximate-byte statistics and retains explicit orphan purge. There +is no automatic TTL until deployed storage measurements justify one. diff --git a/docs/EXPLORER_COMPILATION_ARCHITECTURE.md b/docs/EXPLORER_COMPILATION_ARCHITECTURE.md new file mode 100644 index 00000000..162ebaba --- /dev/null +++ b/docs/EXPLORER_COMPILATION_ARCHITECTURE.md @@ -0,0 +1,239 @@ +# Explorer compilation architecture + +Loom treats the Builder as a mutable editor over a server-owned compiler. Each +accepted editor state produces one immutable, disposable compilation receipt. +The frontend chooses only capability IDs and presentation intent; it never +constructs recipe selectors, graph storage details, physical plans, or AQL. + +This is the implemented Goal D boundary. The public authoring surface is V2. +V1 remains only for offline migration of stored legacy documents. + +## Production path + +```text +V2 Builder document + exact snapshot token + │ + ▼ +active-generation and read-scope authorization + │ exact project, generation, scope digest, schema digest + ▼ +native V2 translator + │ route occurrences, candidates, projection modes, stable emissions + ▼ +resolved recipe compilation + │ semantic validation and deterministic physical lowering + │ no catalog discovery: the capability already proved every operation + ▼ +immutable compilation receipt + │ insert-ignore, content validation, tenant-scoped readback + ├──────────────────────────────┐ + ▼ ▼ +receipt preview receipt publication + │ │ + │ deterministic re-lowering │ deterministic re-lowering + │ preview LIMIT │ full streaming materialization + ▼ ▼ +scoped Arango query ClickHouse outputs + │ + ▼ + release and revision activation +``` + +The HTTP endpoints are: + +- `GET .../authoring/v2/capability` +- `POST .../authoring/v2/compile` (with `/builder` retained as the same compile + operation for the current frontend) +- `POST .../authoring/v2/preview` with `receiptId`, `outputId`, and an optional + limit +- `POST .../authoring/v2/publish` with `receiptId` + +Compile-before-preview is therefore safe. A frontend may debounce compile +while editing and may compile once more immediately before preview if its +latest editor state has no receipt. + +## Native V2 translation + +`internal/explorer/compilation` translates `authoringv2.Document` directly to +`recipe.Bundle`. Production does not translate V2 to V1 and then translate V1 +to a recipe. + +The translator validates all identities against the exact immutable capability +snapshot. It supports: + +- zero-hop routes; +- every finite route allowed by the snapshot policy; +- repeated edges and self-loops when advertised; +- repeated resource types at distinct route occurrences; +- occurrence-specific candidate selection; +- compiler-proven projection modes; and +- deterministic public column, emission, traversal alias, and recipe IDs. + +An invalid route, stale candidate, ambiguous occurrence, unsupported projection +mode, or invalid presentation reference is returned as a structured error with +stage, code, JSON path, message, and details. These are authoring errors, not +raw recipe, AQL, or Arango errors. + +The translator is persistence-neutral and does no catalog reads, field +profiling, graph probing, HTTP work, or database writes. Its only authority is +the supplied capability snapshot. + +## What a receipt means + +A current receipt means: + +> Loom accepted this exact V2 document against this exact active capability +> and authorization scope, produced this resolved semantic recipe and public +> output contract, and can execute it later without interpreting the authoring +> document or discovering schema again. + +The receipt pins: + +- receipt-format and compiler-contract versions; +- project and Explorer identity; +- canonical V2 intent and its digest; +- capability token, source generation, capability schema digest, and exact + authorization-scope digest; +- idempotent compilation key; +- resolved recipe and recipe/schema digests; +- compiler-owned Explorer presentation config; +- public output contract and its digest; +- candidate/occurrence/emission mappings; +- emitted public columns; +- per-output fingerprints; and +- deterministic warnings. + +Request ID and creation time are operational metadata and do not affect the +receipt ID. Receipt IDs are content-addressed. Reads validate the stored ID, +compilation key, resolved-recipe digest, and output-contract digest before the +artifact can execute. + +The receipt deliberately does **not** persist: + +- optimized physical IR; +- rendered AQL; +- bind variables; +- physical collection or table names; or +- request authorization credentials. + +Those objects are implementation details of the current request. Persisting +them would couple durable Builder artifacts to an optimizer, renderer, or +storage layout. Deterministic re-lowering of a frozen resolved recipe is cheap +and is not semantic recompilation. + +## Idempotency and persistence + +The compilation key covers the canonical intent, snapshot, scope, generation, +schema, receipt format, and compiler contract. Production checks this key +before translation. A hit returns the already persisted receipt. + +A miss is translated and validated, then persisted with immutable +`INSERT ... OPTIONS { overwriteMode: "ignore" }` semantics. Loom reads and +validates the stored document before returning success. The Arango collection +has a composite index over project, Explorer, compilation key, receipt format, +and compiler contract. Receipt lookup for execution is always scoped by +project, Explorer, and receipt ID. + +There is no correctness dependency on an in-process cache. Same-key +singleflight is permitted, but Kubernetes resources, `GOMEMLIMIT`, and +`GOMAXPROCS` own workload limits. Receipt statistics expose count, approximate +serialized bytes, oldest creation time, and unreferenced count. Loom retains +explicit orphan purge but does not impose an automatic TTL until real storage +measurements justify one. + +The compiler records hit/compile duration, serialized receipt bytes, output +count, and public column count. The performance objectives are: + +- uncached compile p95 at or below 250 ms; and +- idempotent receipt lookup p95 at or below 50 ms. + +The pure native translator benchmark uses a 20-hop, 100-selection document and +reports time and allocations. It is not a wall-clock CI assertion; service +latency must be measured against the deployed Arango and authorization stack. + +## Preview + +Preview performs these steps: + +1. tenant-scoped receipt lookup and receipt integrity validation; +2. re-authorization against the receipt's exact retained generation; +3. equality checks for project, generation, authorization-scope digest, and + capability schema digest; +4. requested-output validation; +5. deterministic semantic/physical lowering of the stored resolved recipe; +6. equality checks for resolved recipe/schema digests and output fingerprints; +7. application of the preview limit; and +8. parameterized AQL rendering and execution. + +It does not decode V2 intent, migrate through V1, query field profiles, resolve +catalog candidates, or widen authorization. A restricted-empty scope remains +restricted-empty. Preview also does not request the publication-only +`auth_resource_path` output column. + +Preview safety limits are part of this execution contract: every request has +a ten-second server deadline and a 32 MiB encoded-response cap. The response +is atomic; Loom returns no partial rows when the cap is exceeded. A static plan +gate rejects plans above the approved preview class before database execution, +and representative generated plans are checked with Arango `EXPLAIN`. Passing +the static gate does not guarantee success when Arango is unavailable. + +The stable preview failure codes are `PLAN_TOO_EXPENSIVE`, +`RECEIPT_STORE_UNAVAILABLE`, `PREVIEW_TIMEOUT`, +`PREVIEW_RESPONSE_TOO_LARGE`, `CLIENT_CANCELED`, and +`BACKEND_UNAVAILABLE`. Receipt-store failures and timeouts are retryable; +response-size and plan-cost failures require a smaller request. Client +cancellation is not a server outage. Fiber does not reliably distinguish a +browser disconnect from every other canceled request on all HTTP paths, so +the adapter must preserve the typed cancellation when available and must not +classify an empty or truncated response by inspecting error text. + +Inactive generations may be previewed while their immutable data and capability +snapshot are retained and the caller still has the exact effective scope. + +## Publish + +Publish starts from the same receipt and repeats the integrity and exact-scope +checks. It additionally requires the source generation to remain active and +requires at least one selected public output column. An empty intermediate +editor state can be compiled, but publishing it returns `NO_SELECTED_COLUMNS`. + +The resolved recipe is deterministically lowered and its digests/fingerprints +are checked before rows are streamed to publication storage. Publication adds +the authorization provenance column required by ClickHouse. Loom verifies that +all expected outputs are queryable, activates the dataset release, atomically +stores the immutable Explorer revision and receipt, and then switches the +active Explorer pointer. Failure before that final transition leaves the prior +active revision intact. + +The compiled revision retains the canonical V2 authoring document. Builder +reads decode V2 directly; only genuinely old revisions use the V1 migration +decoder. + +## Compatibility and invalidation + +Existing published revisions remain readable. Existing artifactless or +old-contract receipts are not lazily upgraded during preview or publish, +because that would reinterpret mutable authoring intent at an execution +boundary. They return `RECEIPT_RECOMPILE_REQUIRED` and must be explicitly +compiled again. + +Compiler-contract changes, capability/schema changes, generation changes, +authorization-scope changes, or intent changes produce a different compilation +key and receipt. Physical optimizer changes do not require rewriting receipts; +runtime lowering simply uses the current deterministic optimizer and verifies +the frozen semantic outputs. + +## Implementation map + +| Responsibility | Implementation | +| --- | --- | +| V2 protocol and canonical intent | `internal/explorer/authoringv2` | +| Compiler-proven immutable capability | `internal/explorer/capability` and `internal/server/explorer_capability.go` | +| Native V2 translation | `internal/explorer/compilation` | +| Versioned receipt domain and integrity | `internal/explorer/compilation_receipt.go` | +| Memory and Arango receipt persistence | `internal/explorer/memory_store.go`, `internal/explorer/arango/store.go` | +| Resolved-recipe execution boundary | `internal/dataframe/recipe/engine/engine.go` | +| V2 compile/preview/publish routes | `internal/server/explorer_authoring_v2_routes.go` | +| Production composition | `internal/server/server.go` | +| Receipt publication | `internal/server/explorer_publication.go` | +| Compiler-owned output/config validation | `internal/server/explorer_receipt_contract.go` | diff --git a/docs/EXPLORER_RECIPE_BOUNDARY.md b/docs/EXPLORER_RECIPE_BOUNDARY.md new file mode 100644 index 00000000..19379fd6 --- /dev/null +++ b/docs/EXPLORER_RECIPE_BOUNDARY.md @@ -0,0 +1,546 @@ +# The Explorer recipe boundary + +This document explains why the Explorer Builder sends authoring intent instead +of constructing Loom's complete native recipe. The short version is: + +> The frontend chooses what the user wants. Loom decides how that request is +> interpreted, authorized, lowered, optimized, and executed. + +The frontend could generate a syntactically valid recipe for simple cases. The +problem is that a Loom recipe is not merely a JSON formatting template. It is a +storage-neutral compiler input whose fields expand into schema rules, graph +traversal rules, authorization predicates, dynamic projections, physical IR, +and AQL. + +For the request and endpoint contract, see +[Explorer authoring](EXPLORER_AUTHORING.md). For the complete compilation +sequence, see [Explorer compilation architecture](EXPLORER_COMPILATION_ARCHITECTURE.md). + +## What the frontend owns + +The V1 Builder owns authoring intent: + +- which output the user is creating; +- which catalog node is the base and row node; +- which ordered catalog edges form the route; +- which opaque candidates are selected at which occurrences; and +- labels, ordering, visibility, filters, and charts for server-owned emissions. + +For example: + +```json +{ + "apiVersion": "loom.calypr.org/explorer-authoring/v1", + "kind": "ExplorerAuthoringBundle", + "project": "project-a", + "explorerId": "patient-explorer", + "document": { + "kind": "ExplorerBuilderDocument", + "output": { "id": "patient" }, + "baseNodeId": "node_patient", + "rowNodeId": "node_condition", + "routeEdgeIds": ["edge_patient_condition"], + "routeOccurrences": [ + { + "id": "condition_1", + "index": 0, + "nodeId": "node_condition", + "incomingEdgeId": "edge_patient_condition" + } + ], + "candidateIds": ["candidate_condition_status"], + "candidateOccurrences": [ + { + "candidateId": "candidate_condition_status", + "occurrenceId": "condition_1" + } + ] + } +} +``` + +This is durable authoring intent. It does not contain `expr`, `select`, +aliases, generated column names, physical collections, AQL, or authorization +paths. + +## What Loom owns + +Loom owns the translation from that intent to executable behavior: + +```text +intent document + -> authoritative catalog and snapshot resolution + -> route and candidate resolution + -> native recipe construction + -> semantic and schema validation + -> physical graph plan + -> authorization and generation scope + -> optimization + -> parameterized AQL +``` + +Some values below are technically discoverable by a frontend. They are still +server-owned because they depend on authoritative state, security context, or +compiler implementation rules. + +## 1. Selector paths and array semantics + +### What the frontend sees + +The V1 catalog gives the frontend an opaque candidate and useful display +metadata: + +```json +{ + "candidateId": "candidate_observation_code_display", + "nodeId": "node_observation", + "fieldRef": "Observation.code.coding.display", + "logicalType": "string", + "filterable": true, + "chartable": true +} +``` + +The catalog intentionally does not expose the internal recipe selector path. + +### What the native recipe needs + +The server may lower that candidate into: + +```json +{ + "name": "c_", + "fieldRef": "Observation.code.coding.display", + "expr": { + "select": "root.code.coding[].display" + } +} +``` + +The `[]` is not decoration. It says that `coding` is repeated and that the +compiler must iterate it. + +Depending on value mode and cardinality, Loom may need behavior equivalent to: + +```aql +FOR coding IN (root.code.coding ? root.code.coding : []) + FILTER coding.display != null + RETURN coding.display +``` + +or: + +```aql +FIRST( + FOR coding IN (root.code.coding ? root.code.coding : []) + FILTER coding.display != null + RETURN coding.display +) +``` + +The compiler determines whether a selector is scalar or repeated, whether +arrays need flattening, how nulls are handled, and whether a direct scalar +access or a generated nested loop is safe. That behavior lives in selector +parsing, schema metadata, semantic typing, and AQL rendering. + +A frontend could copy those rules, but it would then be implementing part of +the Loom compiler. + +## 2. Field references are not complete execution selectors + +`fieldRef` is provenance and catalog identity. It is not always enough to +construct the executable selector. + +For example, a FHIR choice or nested repeated field may have distinctions such +as: + +```text +Observation.value[x] +Observation.valueString +Observation.valueQuantity.value +DocumentReference.content[].attachment.extension[].url +``` + +The generated schema decides which paths exist, their logical type, whether +they are repeated, and which selector form the recipe compiler accepts. + +For a traversal field, the selector also needs the correct lexical context: + +```json +{ "select": "route_0.code.text" } +``` + +The meaning of `route_0` comes from the server-generated traversal scope. A +frontend-generated selector can be syntactically plausible while referring to +an alias that does not exist at that location. + +## 3. Routes, traversal targets, and aliases + +### User intent + +The user selects a logical route: + +```text +Patient --subject_Patient--> Condition +``` + +The V1 document represents that with node IDs, edge IDs, and occurrences. + +### Native recipe + +Loom may construct: + +```json +{ + "traversals": [ + { + "name": "subject_Patient", + "alias": "route_0", + "toResourceType": "Condition", + "matchMode": "OPTIONAL", + "fields": [ + { + "name": "c_", + "fieldRef": "Condition.status", + "expr": { "select": "route_0.status" } + } + ] + } + ] +} +``` + +Some of those values can be derived from the catalog. The server still has to +verify that: + +- the edge exists in the current snapshot; +- the edge connects to the current route node; +- the next edge begins at the previous edge's target; +- the occurrence index matches the ordered route; +- the terminal node equals `rowNodeId`; and +- the route depth is supported. + +If the route is: + +```text +Patient -> Patient -> Condition +``` + +then `Patient.id` may be valid at two different occurrences. A resource type +alone cannot tell Loom which one the candidate belongs to. V1 therefore has +explicit route occurrences and candidate-occurrence references. + +## 4. Logical routes versus physical graph traversal + +The authoring catalog describes logical relationships. Loom stores graph +relationships in `fhir_edge` with physical endpoint fields and indexed route +shapes. + +The recipe may say: + +```text +traverse subject_Patient to Condition +``` + +The physical compiler must decide how to implement that using the actual edge +layout: + +```text +logical relationship + -> physical _from/_to endpoint choice + -> edge label predicate + -> target resource type predicate + -> correct graph index route + -> target resource lookup +``` + +The frontend should not know the physical endpoint orientation, index names, +or storage-specific route proof. That is why the generated native recipe does +not need to carry a browser-supplied physical direction. + +## 5. Aliases are lexical compiler scope + +Aliases determine which expressions are legal. + +This is valid: + +```json +{ + "alias": "condition", + "toResourceType": "Condition", + "fields": [ + { "expr": { "select": "condition.code.text" } } + ] +} +``` + +This is invalid if `specimen` is not in the current scope: + +```json +{ + "alias": "condition", + "toResourceType": "Condition", + "fields": [ + { "expr": { "select": "specimen.code.text" } } + ] +} +``` + +The semantic compiler tracks aliases, resource types, selector paths, and +expression types together. Server-generated aliases such as `route_0` avoid +making the frontend responsible for maintaining that lexical compiler scope. + +## 6. Generated fields, emissions, and public columns + +One selection passes through several identities: + +```text +(candidateId, occurrenceId) + -> emission ID + -> native recipe field name + -> public output column +``` + +For example: + +```text +candidateId = candidate_patient_id +occurrence = base +emissionId = em_ +fieldName = c_ +publicName = c_ +``` + +These identities connect the authoring document to presentation, compiled +configuration, output schema, persisted revisions, and materialized columns. + +The frontend could copy the hashing algorithms, but then those internal +algorithms become a public frontend dependency. A server change to identity +generation would invalidate browser-authored documents. + +That is why V1 presentation looks like: + +```json +{ + "presentation": { + "em_": { + "label": "Patient ID", + "visible": true + } + } +} +``` + +It does not look like: + +```json +{ + "presentation": { + "column": "c_abc123" + } +} +``` + +The frontend presents an emission. Loom decides which concrete column that +emission becomes. + +## 7. Authorization is runtime context, not recipe intent + +The frontend can provide a project identity: + +```json +{ "project": "project-a" } +``` + +It should not provide authorization paths. Loom obtains those from the +authenticated principal and request scope, then binds them during compilation. + +The physical plan requires scope checks for every resource and relationship. +Conceptually, the generated AQL includes logic like: + +```aql +FOR root IN @@patient_collection + FILTER root.project == @project + FILTER root.dataset_generation == @dataset_generation + LET root_scope_allowed = AUTH_RESOURCE_PATH_ALLOWED( + root.auth_resource_path, + @auth_resource_paths, + @auth_resource_paths_unrestricted + ) + FILTER root_scope_allowed +``` + +Traversed edges and target resources receive equivalent checks. A browser +recipe that omits them may still look semantically valid while being unsafe to +execute. A browser that supplies them cannot be trusted to widen or alter the +scope. + +## 8. Generation and catalog snapshots go stale + +Consider: + +```text +10:00 Builder fetches catalog for generation G1 +10:02 ETL activates generation G2 +10:03 Builder submits candidate IDs discovered from G1 +``` + +The candidate IDs may still be well-formed. They may even look valid. But they +can now resolve to a different schema, edge set, or authorization scope. + +The V1 snapshot token binds the catalog to project, generation, authorization +scope, nodes, edges, candidates, and completeness. Loom re-reads and validates +that snapshot during compilation. The correct result for stale state is a +typed conflict such as: + +```text +409 STALE_CATALOG_SNAPSHOT +``` + +A frontend cannot guarantee consistency between catalog discovery and later +compile, preview, or publish. + +## 9. Dynamic schema depends on actual data + +Some native recipes discover columns from project data. For example, a +DocumentReference extension family may produce keys such as: + +```text +source_path +sha256 +sample_id +``` + +A native dynamic-column declaration may look conceptually like: + +```json +{ + "name": "attachment_extensions", + "source": { + "select": "root.content[].attachment.extension[]" + }, + "key": { + "call": "last_segment", + "args": [{ "select": "item.url" }] + }, + "value": { + "select": "item.valueString" + }, + "maxColumns": 128 +} +``` + +The compiler must then: + +1. discover the actual keys; +2. freeze the allowed key set; +3. determine logical value types; +4. enforce the maximum column bound; +5. create deterministic physical projections; +6. create keyed-map lookups and bind variables; and +7. validate runtime key/type drift. + +The result depends on: + +```text +project + generation + data + authorization scope +``` + +A frontend can display a current key list, but it cannot make that list +authoritative for a later publication. + +## 10. Recipe validation is semantic + +Recipe validation checks more than JSON shape. + +An expression must have exactly one operator: + +```json +{ "select": "root.id" } +``` + +is valid, while this is invalid: + +```json +{ + "select": "root.id", + "literal": "also-present" +} +``` + +Other semantic checks include: + +- selectors must resolve against the resource type in scope; +- aliases cannot shadow existing lexical bindings; +- traversal match modes must be supported; +- traversal depth must remain within compiler limits; +- dynamic sources must have the required array cardinality; +- dynamic item selectors must be valid scalar paths; +- output and field names must be stable recipe identifiers; and +- physical plans must contain required project, generation, and auth scope + operations before AQL rendering. + +The frontend could duplicate these rules, but it would then be maintaining a +second implementation of Loom's compiler semantics. + +## 11. The physical plan is where storage and security meet + +The native recipe may only say: + +```text +root = Patient +traverse subject_Patient to Condition +select Condition.code.text +``` + +The physical plan expands that into operations such as: + +```text +scan Patient collection +filter project +filter dataset generation +check root authorization +traverse fhir_edge +filter edge project/generation +check edge authorization +load Condition target +check target authorization +extract payload.code.text +construct row identity +project public columns +``` + +Only after that does the canonical AQL renderer produce parameterized AQL and +bind variables. + +The frontend should not know collection names, edge indexes, bind-variable +names, payload extraction rules, scope-check ordering, row-identity rules, or +which physical optimizations are safe. + +## Why this is a server boundary + +The first authoring stage is not required because every individual value is +unknowable to a browser. It is required because the browser should not own or +be trusted with: + +- authoritative catalog interpretation; +- snapshot and generation consistency; +- authorization scope; +- schema and cardinality semantics; +- generated executable identities; +- dynamic data-dependent schema; +- physical storage behavior; or +- compiler validation and optimization rules. + +If the frontend generated the complete native recipe, it would become a second +Loom compiler. Loom would still need to validate and recompile that recipe for +authorization, snapshots, schema, and physical correctness. + +The V1 boundary keeps the responsibilities clear: + +```text +Frontend: user intent and presentation choices +Loom: catalog resolution, recipe construction, compilation, authorization, + physical planning, AQL, preview, and materialization +``` + diff --git a/docs/FRONTEND_EXPLORER_V2_MIGRATION.md b/docs/FRONTEND_EXPLORER_V2_MIGRATION.md index 099081da..91615fe4 100644 --- a/docs/FRONTEND_EXPLORER_V2_MIGRATION.md +++ b/docs/FRONTEND_EXPLORER_V2_MIGRATION.md @@ -1,9 +1,15 @@ -# Frontend Explorer V2 Migration - -This guide describes the frontend contract for Loom's REST Explorer lifecycle. -The Builder should use these REST routes for Explorer management and authoring. -It should not depend on the legacy GraphQL Explorer mutations or on generated -GraphQL candidate-input types. +# Historical: Frontend Explorer V2 Migration + +> This document describes the superseded V2 recipe/config packet. It is kept +> for compatibility and ETL migration context. New Builder work must use the +> [current Explorer authoring V2 contract](EXPLORER_AUTHORING.md), which sends +> intent-only documents and receipt-bound preview/save/publish requests. Do not +> copy the V2 request shapes below into new frontend code. + +This guide records the former frontend contract for Loom's REST Explorer +lifecycle. It explains the V2 packet for compatibility and migration work; it +is not a recommendation for new Builder code. The current intent-only contract +is documented in [`EXPLORER_AUTHORING.md`](EXPLORER_AUTHORING.md). ## The important model change diff --git a/docs/GRAPHQL_API.md b/docs/GRAPHQL_API.md index 046c070e..5aae1412 100644 --- a/docs/GRAPHQL_API.md +++ b/docs/GRAPHQL_API.md @@ -33,11 +33,13 @@ typed FHIR reads, discovery, and recipe control operations. ### Explorer authoring and catalog discovery -The Builder uses the REST V2 Explorer lifecycle documented in -[`FRONTEND_EXPLORER_V2_MIGRATION.md`](FRONTEND_EXPLORER_V2_MIGRATION.md). -GraphQL Explorer lifecycle and Builder-introspection fields are not part of -the current contract; the REST authoring compiler resolves catalog selections -and the active dataset generation through one server-owned path. +Explorer authoring is not a GraphQL operation. The Builder uses the versioned +REST V1 intent contract documented in +[`EXPLORER_AUTHORING.md`](EXPLORER_AUTHORING.md). GraphQL Explorer lifecycle +and Builder-introspection fields are not part of the current contract; the REST +authoring compiler resolves catalog selections and the active dataset +generation through one server-owned path. The native recipe compiler remains +the shared execution backend after authoring intent has been lowered. ### FHIR dataframe compilation diff --git a/docs/LOOM _CLEANUP.md b/docs/LOOM _CLEANUP.md new file mode 100644 index 00000000..27d9f79b --- /dev/null +++ b/docs/LOOM _CLEANUP.md @@ -0,0 +1,93 @@ +internal/explorer has become a dumping ground, but the deeper issue is not simply its size. It mixes a legitimate Explorer control-plane domain with legacy migration formats, persistence adapters, test + infrastructure, capability discovery, compilation artifacts, and lifecycle orchestration. + + The August 25 “refactor” explains the sudden loss of comprehensibility: it added 13,444 lines across 61 Explorer-related files—roughly 6,369 lines under internal/explorer and another 7,075 under internal/server. + + ## What Explorer is supposed to be + + Explorer is the user-facing control plane over the dataframe system: + + catalog evidence + authorization + active dataset generation + ↓ + explorer/capability + ↓ + Builder document → authoringv2 → explorer/compilation + ↓ + dataframe recipe + ↓ + immutable compilation receipt + ↙ ↘ + dataframe runtime dataframe publication + preview ClickHouse + activation + + Its clean responsibility would be: + + > Own the durable lifecycle of a user-authored view, from mutable intent through an immutable compilation receipt to an active revision. + + The key production path is visible in server/server.go:377: authorize an exact capability snapshot, translate the V2 document, compile through the dataframe engine, and persist a content-addressed receipt. + + Explorer does not—and should not—own physical query planning or AQL: + + - dataframe/recipe defines semantic recipe inputs. + - dataframe/semantic resolves and validates them. + - dataframe/compiler lowers them into physical plans and AQL. + - dataframe/runtime runs previews and queries. + - dataframe/publication materializes outputs. + - dataframe/published reads and federates those published outputs. + + The native translator in explorer/compilation/translate.go:121 is appropriately placed: it translates Explorer-specific intent into a generic dataframe recipe without executing it. + + ## Where the hygiene breaks down + + This subtree is actually seven Go packages, not one package, and some of the new subdivisions are sensible—particularly authoringv2, capability, and compilation. The root explorer package is the real mixed + aggregate. + + The clearest problems are: + + - explorer/types.go:90 combines identity, drafts, active revisions, recipes, physical columns, dataset selectors, materializations, publication state, migration metadata, and diagnostics in one persistence + model. + + - explorer/store.go:71 defines one very broad store interface covering repository config, drafts, receipts, revisions, activation, statistics, and destructive migration cleanup. + - explorer/service.go:31 mixes genuine lifecycle rules with many one-line persistence wrappers and several older lifecycle APIs. + - V1 compatibility occupies explorer/authoring_v1.go:18, explorer/state_v1.go:10, bootstrap, migration commands, and large server adapters even though V1 is no longer an HTTP surface. + - There are parallel domain models: root Compilation/EmittedColumn and explorer/compilation.Result/EmittedColumn. server/server.go:418 manually copies between them. + - authoringv2/migration.go makes the V2 package depend backward on root V1 types. Migration should depend on both versions, rather than V2 depending on legacy. + - Much of the application logic lives in the transport package. There are 6,287 production lines in internal/server/explorer*.go, including the 1,969-line server/explorer_v2_lifecycle.go:1. server is doing + orchestration that belongs in an Explorer application layer. + + So the strongest architectural smell is actually the pair internal/explorer + internal/server/explorer_*, not the Explorer directory in isolation. + + ## Is there dead code? + + Yes—enough to be meaningful, though it is not the main source of the sprawl. + + A whole-program Go reachability pass reported: + + - 79 Explorer functions unreachable from production executables. + - 61 of those become reachable only when tests are included. + - 18 remain unreachable even with tests. + + The strongest deletion candidates include: + + - Unused service methods such as ListConfigs, Config, SaveConfig, InsertAuthoringRevision, InsertReadyRevisionV2, and InsertFailedRevisionV2. + - Compatibility aliases such as ValidateID, NewSnapshotStore, NewMemoryRepository, and Translate. + - Six unused V2 decoder aliases. + - MigrateV1Bundle and bootstrap.Digest. + + Most of the remaining 61 are test infrastructure living in production files, especially the 499-line root MemoryStore, the capability memory repository, ProbeFuncs, and SliceObserver. They should either move to + _test.go/testutil or acquire a demonstrated production/local-deployment entry point. + + This means there is measurable dead/test-only surface, but most of the recent bulk is active code representing overlapping architectures and compatibility layers—not merely forgotten functions. + + ## Recommended boundary cleanup + + In order: + + 1. Delete the 18 genuinely unreachable wrappers and APIs; relocate test-only stores and probes. + 2. Quarantine V1, bootstrap, and migration logic under an explicit explorer/legacy or explorer/migration boundary. + 3. Split Store into focused repositories: drafts/config, receipts, and revisions/activation. + 4. Move compile/preview/publish use cases from internal/server into an Explorer application package; leave Fiber route decoding and response mapping in server. + 5. Make receipt/output-contract types canonical and remove the duplicate compilation DTOs. + + The coherent pieces—capability, authoringv2, native translation, and immutable receipts—should remain. The cleanup should preserve persisted JSON shapes, receipt hashing, Arango collection contracts, revision + IDs, scope semantics, and the offline migration commands. No files were changed during this audit. diff --git a/docs/LOOM_EXPLORER_ARCHITECTURE_POSTMORTEM.md b/docs/LOOM_EXPLORER_ARCHITECTURE_POSTMORTEM.md new file mode 100644 index 00000000..0aa80188 --- /dev/null +++ b/docs/LOOM_EXPLORER_ARCHITECTURE_POSTMORTEM.md @@ -0,0 +1,1437 @@ +# Architecture postmortem: why Loom and the Explorer Builder do not cooperate + +## Executive conclusion + +Your suspicion is justified: Loom needs a substantial restructuring around its Explorer authoring boundary, catalog semantics, lifecycle orchestration, and ingestion jobs. + +It does **not** need a complete rewrite of its FHIR extraction, graph compiler, Arango access, or ClickHouse publication machinery. Those pieces contain useful, tested work. The problem is that they are currently connected through APIs that expose internal complexity directly to the frontend. + +Three architectural mistakes explain most of the behavior: + +1. **Loom exposes observed data as if it were executable capability.** + A resource, relationship, or field appearing in a catalog does not mean the compiler can use it. The frontend nevertheless treats catalog entries as valid choices. + +2. **Editing, validation, compilation, preview, publication, materialization, and activation are mixed together.** + The frontend sends a complete mutable bundle repeatedly, while Loom recompiles it through multiple layers on reconciliation, preview, and publication. + +3. **Graph ingestion is coupled to expensive, dataset-wide metadata profiling.** + The loader streams input rows, but simultaneously builds large in-memory catalogs whose size historically grew with data cardinality. That is why a “streaming” immutable-generation migration reached approximately 4.1 GB RSS. + +The frontend errors are therefore not random in origin. They are deterministic failures from several backend layers, discovered too late and translated inconsistently. They appear random to users because the UI is allowed to construct states that Loom cannot execute, and the backend does not return a stable recovery model. + +No code was modified during this review. + +--- + +# 1. What Loom currently does + +There are really two major systems inside Loom. + +## Graph-generation pipeline + +```text +repair-generation + ├─ audit old fhir_edge generation + ├─ ingest.Load + │ ├─ discover META files + │ ├─ load graph schema + │ ├─ preflight all files + │ ├─ create LOADING generation manifest + │ └─ for each file + │ └─ loadFile + │ ├─ scanner → buffered line queue + │ ├─ parser/profile workers + │ │ ├─ generated or generic row builder + │ │ ├─ generation-key rewrite + │ │ ├─ field profiling + │ │ ├─ vertex batch + │ │ └─ edge batch + relationship counts + │ └─ buffered write queue → Arango writers + ├─ write field catalogs + ├─ write relationship catalog + ├─ mark generation STAGED + ├─ audit new generation + └─ optionally activate generation +``` + +The central orchestration is in [generation_orchestration.go](../internal/ingest/generation_orchestration.go), while the concurrent file pipeline is in [generation_workers.go](../internal/ingest/generation_workers.go). + +## Explorer authoring pipeline + +```text +browser-only draft + │ + ├─ debounce + └─ POST complete bundle to /builder + ├─ validate authoring document + ├─ validate catalog snapshot + ├─ normalize route occurrences + ├─ validate catalog nodes/edges/candidates + ├─ lower authoring document to recipe + ├─ validate recipe + ├─ resolve schema + ├─ build semantic plan + ├─ lower physical plan + ├─ optimize plan + └─ return reconstructed builder state + +Preview: + complete bundle → resolve/compile again → AQL → Arango + +Publish: + complete bundle → resolve/compile again + → materialize outputs + → ClickHouse publication + → dataset release activation + → Explorer revision persistence +``` + +The main authoring compiler is [explorer_authoring_v1.go](../internal/server/explorer_authoring_v1.go), with HTTP lifecycle handling in [explorer_authoring_v1_routes.go](../internal/server/explorer_authoring_v1_routes.go). + +The critical observation is that `/builder` is not a lightweight editing API. It is effectively a full compiler endpoint. + +--- + +# 2. Why the screenshot happens + +The `qualification` failure is a perfect example of the larger architectural defect. + +The historical edge extractor permitted nested/backbone definitions to leak into persisted edge endpoint metadata. It therefore produced relationships resembling: + +```text +Practitioner → qualification +``` + +The Builder catalog intentionally reverses stored reference direction so that a user can start from the referenced resource and traverse toward resources that refer to it: + +```aql +COLLECT + from_type = d.to_type, + label = d.label, + to_type = d.from_type +``` + +That happens in [store.go](../internal/catalog/arango/store.go). + +Consequently, a malformed stored edge becomes: + +```text +qualification → Practitioner +``` + +in the Builder graph. + +The frontend then: + +- renders every catalog node as a resource; +- labels catalog nodes as “Available row start”; +- permits any inspected node to become the row start; +- has no `rootEligible`, `executable`, or `blockedReason` property. + +That behavior is visible in `GuidedGraphWorkspace.tsx` and `RouteExtensionPanel.tsx` in the IDP-Frontend repository. + +Only after the frontend submits the document does Loom reach the compiler’s row-grain check and return `UNSUPPORTED_ROW_GRAIN`. + +This is not a Practitioner-specific or qualification-specific bug. Any backbone element, nested definition, arbitrary schema definition, or invalid endpoint can produce the same failure. + +The general invariant must be enforced at four boundaries: + +- extraction: only concrete FHIR resources may become endpoints; +- persistence/audit: reject non-concrete endpoint metadata; +- catalog construction: never advertise invalid resources; +- authoring capability generation: advertise only operations the compiler has already validated. + +The current dirty Loom tree contains work toward a general `ConcreteResourceType` boundary and catalog filtering. That is the correct direction, but it does not solve the broader observation-versus-capability problem. + +--- + +# 3. The catalog is not a capability contract + +This is the deepest frontend/backend mismatch. + +## What field profiling actually does + +For every resource payload, the profiler recursively observes: + +- paths that occur; +- broad kinds such as scalar, object, or array; +- document counts; +- distinct scalar values; +- CodeableConcept-derived pivot columns; +- FHIR extension URLs and value forms; +- shape fingerprints used to reuse traversal plans. + +The implementation is in [write_profiler.go](../internal/catalog/write_profiler.go). + +The resulting `fhir_field_catalog` is useful for: + +- showing fields that are populated in this particular dataset; +- supplying filter value suggestions; +- discovering dynamic FHIR extensions; +- proposing pivot columns; +- avoiding presenting every theoretical FHIR field; +- enriching recipe schema resolution. + +But it does **not** prove that a field can be compiled. + +The profiler walks observed JSON. The compiler separately applies generated FHIR schema rules such as: + +- whether the path exists in the supported generated schema; +- whether each array segment has the required `[]`; +- whether the terminal value is scalar; +- whether the projection is valid at the selected row grain; +- whether the path can be lowered to AQL; +- whether a pivot or filter operation is supported. + +Those checks occur much later in files such as [selector_validation.go](../internal/dataframe/spec/selector_validation.go). + +Therefore: + +```text +observed in JSON ≠ valid selector +catalog relationship ≠ legal traversal +catalog node ≠ valid row root +``` + +The frontend currently assumes all three equivalences. + +## Where profiling belongs + +Field profiling should not be on the critical path for graph correctness or generation activation. + +A better ownership model is: + +- generated FHIR schema defines legal paths, cardinality, row grains, and operations; +- graph ingestion writes resources and valid relationships; +- an asynchronous enrichment job computes populatedness, approximate counts, extensions, distinct-value suggestions, and pivots; +- a capability compiler intersects schema capability with observed enrichment. + +Separating profiling from graph loading would not lose the graph or its relationships. Loom would temporarily lose only dataset-specific conveniences: + +- knowledge that a legal field is actually populated; +- immediate filter-value suggestions; +- dynamic extension discovery; +- observed pivot values; +- field frequency rankings. + +Those can appear asynchronously or be computed lazily. The UI could initially show valid schema fields and progressively enrich them. + +--- + +# 4. The frontend can construct many invalid states + +The issue is much broader than `UNSUPPORTED_ROW_GRAIN`. + +## Failure families exposed to the frontend + +| Failure family | Representative backend codes | +|---|---| +| Protocol and document shape | `MALFORMED_AUTHORING_REQUEST`, `UNSUPPORTED_AUTHORING_PROTOCOL`, `UNSUPPORTED_DOCUMENT_VERSION`, `MISSING_AUTHORING_IDENTITY` | +| Identifier integrity | `MISSING_OUTPUT_ID`, `DUPLICATE_OUTPUT_ID`, `DUPLICATE_AUTHORING_DOCUMENTS`, `DUPLICATE_ROUTE_EDGE`, `DUPLICATE_ROUTE_OCCURRENCE`, `DUPLICATE_CANDIDATE_ID`, `DUPLICATE_EMISSION_ID` | +| Catalog lifecycle | `SNAPSHOT_REQUIRED`, `CATALOG_UNAVAILABLE`, `CATALOG_INCOMPLETE`, `CATALOG_SNAPSHOT_FAILED`, `STALE_CATALOG_SNAPSHOT` | +| Route topology | `STALE_ROUTE_NODE`, `STALE_ROUTE_EDGE`, `INVALID_ROUTE_CONTINUITY`, `INVALID_ROUTE_ORIGIN`, `INVALID_ROUTE_OCCURRENCE_ORDER`, `INVALID_ROUTE_TERMINAL_NODE`, `ROUTE_OCCURRENCES_REQUIRED` | +| Selection/candidate integrity | `STALE_CANDIDATE_ID`, `CANDIDATE_REFERENCE_MISSING`, `SELECTION_NODE_MISMATCH`, `CANDIDATE_OCCURRENCE_REQUIRED`, `DUPLICATE_CANDIDATE_OCCURRENCE` | +| Compiler capability | `UNSUPPORTED_ROW_GRAIN`, `UNSUPPORTED_NESTED_TRAVERSAL`, `INVALID_AUTHORING_INTENT`, `INVALID_COMPILED_RECIPE`, `AUTHORING_OUTPUT_LOWERING_FAILED` | +| Presentation capability | `UNSUPPORTED_FILTER_PRESENTATION`, `UNSUPPORTED_CHART_PRESENTATION`, `STALE_EMISSION` | +| Preview | `INVALID_PREVIEW_LIMIT`, `UNKNOWN_AUTHORING_OUTPUT`, `PREVIEW_UNAVAILABLE`, `AUTHORING_PREVIEW_FAILED` | +| Publication | `PUBLICATION_UNAVAILABLE`, `SNAPSHOT_CONFLICT`, `MATERIALIZATION_FAILED`, `MATERIALIZATION_ACTIVATION_FAILED`, `REVISION_STORE_FAILED` | +| Identity and authorization | `AUTHORING_IDENTITY_CONFLICT`, `FORBIDDEN`, `NOT_FOUND` | +| Infrastructure fallback | `AUTHORING_COMPILER_UNAVAILABLE`, `ACTIVE_AUTHORING_BUNDLE_INVALID`, `INTERNAL_ERROR` | + +Many of these are appropriate backend checks. The problem is that the contract does not tell the frontend: + +- which choices are legal before the user selects them; +- which error is attached to which editable object; +- whether the error is recoverable; +- what recovery action should be taken; +- whether an error invalidates the draft, catalog snapshot, compilation, or publication. + +## The frontend discards most diagnostic information + +The API error type can carry status, code, diagnostics, request ID, details, and retryability. But the workspace normally renders only the first diagnostic’s message and code. + +It discards or hides: + +- all subsequent diagnostics; +- diagnostic stage; +- JSON path; +- structured details; +- request ID; +- recovery action; +- whether retrying is safe; +- which table, route occurrence, or candidate failed. + +For the initial Builder load, it can reduce the result even further to a generic “could not be loaded” state. + +## Backend errors are not consistently typed + +Loom has a typed dataframe error package, but the authoring boundary does not consistently preserve it. Generic compiler failures are converted using: + +```go +message := err.Error() +code := "INVALID_AUTHORING_INTENT" +if strings.Contains(strings.ToLower(message), "traversal") { + code = "UNSUPPORTED_NESTED_TRAVERSAL" +} +``` + +That creates three problems: + +- many distinct failures collapse into `INVALID_AUTHORING_INTENT`; +- classification depends on English error text; +- raw internal error wording reaches the user. + +This directly explains the “random backend error” experience. + +--- + +# 5. Frontend state ownership is unstable + +The current hard-cutover frontend is considerably smaller than its predecessor, but several structural problems remain. + +## Browser-only draft + +The editable draft lives primarily in the React reducer. There is no normal server-side saved draft with compare-and-swap semantics. + +Consequences: + +- refresh can lose work; +- another browser cannot continue the draft safely; +- active revision and local draft can diverge; +- backend reconciliation is being used partly as validation and partly as normalization. + +## Whole-bundle reconciliation + +Every semantic edit triggers a debounced POST containing the complete authoring bundle. + +The frontend ignores stale responses by generation number, but it does not cancel obsolete HTTP requests. Loom still performs every obsolete compilation. + +## Frontend and backend sometimes resolve different documents + +`completeDocument` omits incomplete tables from the outgoing bundle. + +Thus the UI may display an incomplete table while the backend successfully resolves a bundle that does not contain that table. The word “reconciled” does not mean the visible workspace was completely validated. + +## Stale-snapshot recovery is unsafe + +On a stale snapshot, the frontend refetches Builder state and then retries the old bundle against the new snapshot. + +That can fail because: + +- catalog IDs are opaque and may have changed; +- the refetch can hydrate active state over local state; +- no semantic mapping exists from old catalog identities to new identities; +- there is no draft revision or merge protocol. + +## Runtime types have already drifted + +A documented failure involved Loom returning `candidateEmissions: null` while the frontend declared it as an array and crashed. Current code guards against that specific case, and the backend now serializes `[]`. + +That incident is evidence of the actual problem: Go and TypeScript separately describe the contract, and no generated or cross-repository conformance boundary guarantees they agree. + +--- + +# 6. Is repair-generation actually streaming? + +No. It is a streaming input pipeline attached to several accumulating data structures. + +The source file is not loaded wholesale, but “does not read the entire file into one slice” is much weaker than constant-memory streaming. + +## Structures retained beyond one row or write batch + +- up to 10,000 buffered input lines in the committed implementation; +- eight parser workers; +- one vertex batch and one edge batch per parser worker; +- up to 100 queued write batches; +- import-request body copies; +- pooled byte buffers retaining their high-water capacity; +- one field profiler per worker for the entire file; +- a shared shape-plan cache for the entire file; +- merged field profiler state; +- merged field profilers retained for every resource type until the full load completes; +- one relationship-count map per writer; +- file-level and generation-level relationship aggregations; +- Arango’s indexes, import transaction state, caches, and compaction memory; +- both old and new generation data and index entries in the same collections. + +Preflight also reads the inputs before ingestion, so the 4.5 GB source is traversed at least twice, although preflight does not retain all rows. + +## Memory budget + +The Go estimates below illustrate the committed pipeline at 500-row batches, eight parser workers, a 10,000-line input queue, and a 100-task write queue. They are formulas and plausible ranges, not heap-profile measurements. Actual FHIR document sizes vary heavily. + +| Component | Approximate budget | Controlling bound | Growth class | +|---|---:|---|---| +| Input line queue | `10,000 × average line size`; roughly 20–60 MB at 2–6 KB/row | Queue length | Bounded by queue | +| Active parser state | Approximately 8 active rows with typed objects, generic maps, edges and temporary buffers; roughly 10–100 MB | Worker count and largest row | Worker-bounded | +| Vertex batches | `8 × 500 × encoded vertex size`; roughly 8–24 MB | Workers × batch size | Batch/worker-bounded | +| Edge batches | `8 × 500 × edge size`, but rows can emit many edges; roughly 1–20+ MB | Workers × batch size and edge fan-out | Batch/worker-bounded | +| Queued write batches | Up to `100 × 500 × encoded document size`; roughly 50–300+ MB | Queue tasks × batch size | Queue/batch-bounded | +| Field distinct values | Historically potentially multiple GB | Number of distinct values across observed paths, duplicated across workers | Dataset-cardinality growth | +| Shape plans | One plan per unique observed structural fingerprint | Unique payload shapes | Dataset-cardinality growth | +| Relationship maps | Usually KB to low MB | Distinct `(project,generation,path,from,label,to)` tuples | Normally schema-bounded | +| JSON copies | Often 50–500+ MB overlapping other rows/batches | Workers, queues, batch sizes and largest documents | Worker/batch-bounded | +| Import request copy | One body copy per active writer; pooled buffers may retain capacity | Writers × batch bytes | Writer/batch-bounded | +| Arango import state | One or more request/transaction batches | Concurrent writers and batch bytes | Writer/batch-bounded | +| Arango persistent indexes | Grows with all documents and generations | Data cardinality × index count | Database-cardinality growth | +| Arango cache/compaction | Can reach GB-scale independently of Go | Working set and database configuration | Database/server policy | + +The field profiler is the best explanation for the observed 4.1 GB Go RSS. + +Each worker retained its own distinct-value maps across the entire file. High-cardinality FHIR fields can include: + +- IDs; +- identifiers; +- references; +- URLs; +- attachment locations; +- hashes; +- timestamps; +- extension values; +- coding combinations. + +After a file completes, Loom creates a merged profiler while worker-local profilers may still exist. It then retains the merged profiler in the generation-wide `catalogs` map until every file is complete. + +The current dirty tree adds finite limits and smaller queues. That is an improvement over unbounded retention, but the defaults are not a credible aggregate memory budget: + +```text +4,096 fields +× 4,096 values per field +× up to 4,096 bytes per value +≈ 64 GiB of raw value bytes per profiler +``` + +That excludes maps, strings, slices, extension observations, pivots, and multiple worker profilers. “Finite” is not synonymous with operationally safe. + +Memory limits should be established by the Kubernetes workload and Go runtime environment, not by adding server-owned memory policy. + +--- + +# 7. Why one writer and 500-row batches still OOMed + +Those controls reduced only part of the memory equation. + +Reducing writers controls: + +- concurrent HTTP import bodies; +- writer-local relationship maps; +- simultaneous Arango requests. + +Reducing batch size controls: + +- vertex batch size; +- edge batch size; +- each queued task’s payload; +- each import body. + +Neither controls: + +- field distinct-value accumulation; +- shape-plan accumulation; +- worker-local catalog duplication; +- merged catalogs retained across files; +- the eight parser workers in the committed pipeline; +- the 10,000-line queue; +- the number of queued tasks; +- Arango index growth; +- old and new generations coexisting physically. + +A slower writer can also keep the write queue full for longer. Smaller batches mean each queue slot is smaller, but 100 queued batches plus parser-owned batches remain live. + +So the batch change shaved hundreds of MB at best while the dominant structure continued growing toward dataset cardinality. + +--- + +# 8. JSON amplification + +One input line may exist in several forms during processing: + +1. scanner-owned bytes; +2. queued Go string; +3. `[]byte(line.text)`; +4. generated typed FHIR representation or generic `map[string]any`; +5. vertex envelope; +6. serialized vertex bytes; +7. serialized edge bytes; +8. decoded `map[string]json.RawMessage` for generation namespacing; +9. re-serialized generation-qualified vertex and edges; +10. profiling payload map; +11. concatenated import body; +12. copied import body for HTTP transmission. + +The generation wrapper alone decodes and re-encodes every vertex and edge in [generation_identity.go](../internal/ingest/generation_identity.go). The import path builds a pooled buffer and then makes another copy in [client.go](../internal/store/arango/client.go). + +These copies are mostly bounded by concurrency and buffering, but they amplify every other memory-retention decision. + +--- + +# 9. Generation model evaluation + +| Model | Strengths | Costs and risks | Assessment | +|---|---|---|---| +| Shared collections with generation-qualified keys | Stable collection names; manifest pointer can switch atomically; existing queries can add a generation predicate | Every generation shares every index; all queries must scope correctly; cleanup requires large filtered deletes; collection/index working set grows; old and new coexist during repair | Workable with strict retention and ample Arango capacity, but operationally expensive | +| Separate collections per generation | Strong isolation; old generation cannot be mutated accidentally; activation changes a collection mapping; dropping a generation is cheap and complete | Dynamic collection resolution; many collections and indexes; bootstrap overhead; compiler must never hard-code names | Better immutable isolation, but needs a deliberate collection resolver and retention policy | +| Database-side copy/rewrite | Avoids rereading META; can stream/copy authoritative vertices; much lower Go parse/profile cost | Still writes a second set of documents and indexes; must batch carefully; edge/key rewriting must be exact | Best repair mechanism when stored vertices are trusted | +| Full source re-ingestion | Reproducible from canonical source; exercises current parser, validation and extraction; appropriate after broad transformation changes | Worst I/O, CPU and memory; repeats profiling; duplicates every index entry; can fail hours into the operation | Reserve for cases where resource payloads themselves are suspect | + +For long-term clarity, separate physical collections—or a similarly isolated generation namespace—fit immutable generations better. But this should not be changed casually: Loom’s compiler and query layer need one generation-to-storage resolver first. + +The Explorer restructuring does not need to wait for that storage migration. + +--- + +# 10. Does edge repair require parsing the entire META directory? + +No. + +There are three repair scopes. + +## Relationship catalog only + +If `fhir_edge` is correct but `fhir_relationship_catalog` is contaminated, rebuild the catalog from valid edges. No FHIR source parsing is needed. + +The current rebuild query already has the shape of this approach and filters endpoints against concrete resource types. + +## Remove malformed edges while preserving the graph + +If malformed edges can be identified by invalid endpoint types, a new immutable generation can be constructed by: + +- streaming/copying old-generation vertices into new-generation keys; +- copying valid edges while rewriting their generation-qualified endpoints; +- omitting invalid edges; +- rebuilding relationship counts; +- copying or asynchronously regenerating field enrichment; +- auditing and activating the new generation. + +This inserts new documents and does not mutate the old generation. + +## Regenerate possibly missing or incorrect edges + +If the extractor may also have missed valid edges, edge extraction must run again. But it can run from FHIR payloads already stored in resource vertices. + +It may be sufficient to re-extract only source resources associated with invalid edges. If the faulty extractor’s scope is unknowable, all stored vertices may need to be inspected—but that is still not the same as rereading and fully re-ingesting the entire META source. + +Full META re-ingestion is required only when: + +- stored resource payloads are incomplete or wrong; +- the resource transformation itself changed; +- authoritative provenance requires recreation from source; +- schema validation must be rerun against the original files. + +--- + +# 11. The lifecycle design is unfinished + +The frontend and Loom planning documents describe a safer model: + +- save a draft with compare-and-swap; +- compile to an immutable receipt; +- preview by compilation ID; +- publish by compilation ID; +- protect against external updates; +- expose blocked candidates and diagnostic eligibility. + +The actual implementation instead upgraded the existing Builder endpoint: + +- `/builder` accepts and recompiles the whole bundle; +- `/preview` accepts and recompiles the whole bundle; +- `/publish` accepts and recompiles the whole bundle; +- the compilation receipt exists largely as an internal return structure; +- draft persistence and CAS are absent; +- publication behaves essentially as last-writer-wins. + +This is why small UI actions cross so many backend layers. + +Loom also retains a large legacy Explorer V2 lifecycle/compiler implementation in [explorer_v2_lifecycle.go](../internal/server/explorer_v2_lifecycle.go), alongside the new V1 authoring model and the older repository-upload route in [explorer_config_route.go](../internal/server/explorer_config_route.go). + +Even where the legacy routes are no longer registered, tests and internal machinery keep much of the model alive. The result is multiple overlapping definitions of: + +- Explorer config; +- authoring bundle; +- draft; +- revision; +- recipe; +- compiled config; +- materialization; +- dataset release; +- publication. + +That is genuine architectural sprawl, not just a file-organization problem. + +--- + +# 12. Recommended target architecture + +The restructuring should be radical at the boundary but conservative in proven internals. + +## A. Immutable graph ingestion job + +Responsibilities: + +- validate and load concrete FHIR resources; +- create valid resource-to-resource edges; +- stage an immutable generation; +- audit structural invariants; +- activate only after validation. + +Run it as a dedicated Kubernetes Job, not via `kubectl exec` inside the Loom server pod. + +The Docker image can contain both binaries, but the Job should override the server entrypoint and own: + +- CPU request/limit; +- memory request/limit; +- `GOMEMLIMIT`; +- `GOMAXPROCS`; +- retry/backoff policy; +- temporary-storage limits. + +The Loom server should not decide these policies. + +## B. Capability snapshot compiler + +Create a generation-scoped capability document from: + +```text +generated FHIR schema +∩ valid graph relationships +∩ observed populatedness/enrichment +∩ authorization scope +∩ supported compiler operations +``` + +Every advertised node and candidate should carry explicit semantics such as: + +```json +{ + "resourceType": "Practitioner", + "rowRootEligible": true, + "supportedOperations": ["SELECT", "FILTER"], + "blockedReason": null +} +``` + +Invalid nodes may be retained for audit visibility but must not appear as selectable resources. + +A powerful invariant test then becomes possible: + +> Every advertised row root, route edge, and column candidate must compile successfully under the snapshot that advertised it. + +### The traversal Builder is the product contract + +The Explorer graph in the frontend is intended to be a real authoring surface +over Loom's FHIR graph. Loom must make that vision true. A user should be able +to choose a concrete FHIR resource as the row root, follow relationships Loom +actually stores, select fields from any occurrence along the route, and compile +that construction into an executable Arango query. + +The frontend should not need to reproduce the FHIR schema, understand Arango +edge direction, or predict dataframe cardinality rules. Those are Loom +responsibilities. + +### Current Loom gap + +The current catalog reader assembles Builder nodes, edges, and selections +directly from populated-field and populated-relationship discovery. The public +types carry only: + +- node ID and resource type; +- edge ID, source node, target node, and label; and +- candidate ID, node ID, field reference, logical type, and coarse filter/chart + flags. + +This is enough to draw a graph, but it is not enough to promise that the graph +can be compiled. In particular: + +- a node can be observed without having a supported row grain; +- a relationship can be observed without a valid generated traversal; +- a field can be observed without being a legal generated selector; +- an object or array can require a projection mode the catalog does not + describe; +- repeated resource types require occurrence-specific field binding; +- Builder direction is the inverse of stored FHIR-reference direction and must + be made unambiguous; +- the hard-coded four-hop authoring limit is not represented in the catalog; + and +- catalog completeness currently means discovery completed, not that every + returned capability passed the compiler. + +### Required meaning + +A capability snapshot must be an immutable, generation-scoped, +authorization-scoped, compiler-versioned statement of what Loom promises it can +execute. + +The generated FHIR schema and compiler define validity. Observation data only +annotates valid capabilities with populatedness, edge counts, and suggested +values. An observed fact must never create a capability the schema/compiler do +not support. + +The snapshot identity must cover: + +- canonical project identity; +- immutable dataset generation; +- authorization-scope digest; +- generated FHIR schema digest; +- relationship-catalog digest; +- field-enrichment digest or version; +- authoring protocol version; +- compiler artifact version; +- traversal policy version; and +- the canonical capability payload. + +Changing any of these produces a different snapshot token. A snapshot is never +silently modified in place. + +### Node contract + +Every node offered to the current Builder must represent a concrete FHIR +resource collection with a supported row grain: + +~~~json +{ + "nodeId": "n_...", + "resourceType": "Practitioner", + "rowRootEligible": true, + "rowGrain": "RESOURCE", + "populated": true, + "documentCount": 8124, + "blockedReason": null, + "capabilityVersion": "..." +} +~~~ + +For compatibility with the current frontend, Loom should initially omit +non-root-eligible nodes from the normal nodes array. The UI currently treats +every returned node as a selectable row start. A future frontend may render +blocked nodes through a separate collection or an eligibility property it +explicitly understands. + +Node eligibility must be decided by the same row-grain registry used during +lowering. It must not be inferred from collection existence or profiler rows. + +### Traversal-edge contract + +An advertised Builder edge must mean: + +> From an occurrence of the source node, Loom can follow this exact +> relationship in this authoring direction, under the pinned generation and +> authorization scope, and lower the step into a valid graph traversal whose +> result is an occurrence of the target node. + +The internal capability requires more information than the frontend currently +renders: + +~~~json +{ + "edgeId": "e_...", + "fromNodeId": "n_patient", + "toNodeId": "n_document_reference", + "label": "subject_Patient", + "storageDirection": "INBOUND", + "sourceResourceType": "DocumentReference", + "targetResourceType": "Patient", + "observedEdgeCount": 1002431, + "allowsRepeatedTarget": true, + "blockedReason": null +} +~~~ + +The current frontend can continue consuming only edge ID, source, target, and +label. The additional internal fields let Loom define and test the promise. + +Every edge must pass all of the following before publication: + +- both endpoints canonicalize to concrete generated FHIR resource types; +- both endpoint nodes exist in the same snapshot; +- the label resolves through the generated traversal registry; +- Builder direction maps unambiguously to stored edge direction; +- project, generation, and authorization predicates can be applied; +- the lowerer produces a one-step physical traversal plan; and +- the renderer produces valid AQL for that plan. + +Malformed historical relationships may remain visible to audit tooling, but +must never enter the Builder capability graph. + +The arbitrary four-hop policy requires an explicit decision. The current +frontend presents a traversal graph without explaining that limit. Loom should +either remove the fixed authoring limit and rely on physical plan cost/safety +policy, or publish a route policy the frontend can enforce. Quietly accepting +four steps and rejecting the fifth is not a solid contract. + +### Column-candidate contract + +A profiler record is only input evidence. Before a field becomes a Builder +candidate, Loom must resolve it through generated selector and terminal-type +metadata. + +Each internal candidate should describe: + +- canonical selector; +- owning node; +- terminal FHIR type; +- scalar/object/array cardinality; +- allowed projection modes; +- supported filter operators; +- supported chart aggregations; +- whether the field was observed; +- observed document count; +- bounded value suggestions; and +- any reason it was excluded or restricted. + +~~~json +{ + "candidateId": "s_...", + "nodeId": "n_observation", + "label": "Observation.code.coding[].code", + "logicalType": "string", + "cardinality": "MANY", + "projectionModes": ["FIRST", "ARRAY", "DISTINCT_ARRAY"], + "filterOperators": ["EQUALS", "IN", "EXISTS"], + "filterable": true, + "chartable": true, + "populated": true +} +~~~ + +For the current frontend, Loom should return only candidates safe under the +frontend's existing default projection behavior. Richer candidates can be +exposed when the frontend can choose projection modes explicitly. This ensures +every currently clickable field works while preserving richer future +capabilities. + +Candidates remain attached to node types in the snapshot. The authoring +document binds a candidate to a route occurrence. That preserves the necessary +distinction when one route visits the same resource type more than once. + +### Deterministic snapshot construction + +Loom should build a snapshot in these phases: + +1. Resolve the exact active or requested immutable generation. +2. Resolve the caller's authorization scope for that generation. +3. Enumerate concrete resource collections visible in that scope. +4. Intersect them with the compiler's supported row-grain registry. +5. Read observed relationship classes and reject any class absent from the + generated traversal registry. +6. Normalize Builder direction and create snapshot-local opaque edge IDs. +7. Read observed fields, but validate every path through generated selector and + terminal-type metadata before creating a candidate. +8. Derive projection, filter, and chart operations from compiler semantics. +9. Canonically sort and serialize nodes, edges, candidates, policies, and + version identities. +10. Hash and persist the complete immutable snapshot. + +If a required dependency fails, Loom returns an explicitly unavailable +snapshot. It must not return a partial graph that looks usable. + +### Executable invariants + +The central promise should be tested as: + +- every node compiles as a zero-hop output root; +- every edge compiles as a one-hop extension from its source node; +- every candidate compiles at an occurrence of its node using each advertised + projection mode; +- every advertised filter/chart operation passes semantic validation; +- every compiled output renders valid AQL; +- graph direction and endpoint types agree with the rendered AQL; +- opaque IDs resolve only inside the snapshot that created them; and +- incomplete or truncated snapshots never appear as usable Builder state. + +Representative integration fixtures should also run Arango EXPLAIN on generated +queries. That catches renderer, index, and direction mistakes pure compiler +tests cannot. + +This snapshot is the main mechanism for making the existing traversal UI +trustworthy. Most current Builder errors should become impossible to construct, +not merely better explained after submission. + +## C. Server-owned draft + +Use an immutable or versioned draft: + +```text +PUT draft +If-Match: draftRevision +``` + +The response produces a new draft revision. Refresh, multiple tabs, and conflicts become explicit. + +## D. Immutable compilation receipt + +```text +POST .../authoring/v2/compile + V2 document + exact capability snapshot token + +→ receiptId + normalized Builder state + public output columns +``` + +Compilation is side-effect free with respect to graph data, materialization, +publication, and active pointers. Persisting the immutable receipt is part of +compilation and must finish before Loom returns success. + +### Implemented boundary + +The production compiler now translates V2 intent directly. It does not route +through the V1 compatibility compiler. It authorizes the exact active snapshot, +translates route occurrences and candidate selections into a native recipe, +compiles the already resolved recipe without catalog discovery, creates a +versioned receipt, and persists it through the immutable receipt store. + +Preview and publication accept a receipt ID and execute the receipt's frozen +resolved recipe. They never reinterpret the authoring document, migrate it +through V1, or rediscover fields. + +### Semantic guarantee + +A receipt must mean: + +> Loom accepted this exact authoring intent against this exact capability +> snapshot, resolved every route occurrence and candidate identity, produced +> this exact output schema, and created an executable artifact that can be +> previewed or published without interpreting the authoring document again. + +The receipt must pin: + +- project and Explorer identity; +- canonical intent digest; +- capability snapshot token; +- dataset generation; +- authorization-scope digest; +- compiler and artifact-format version; +- canonical V2 document and normalized route occurrences; +- candidate-to-occurrence bindings; +- resolved recipe and schema; +- resolved-recipe and output-contract digests; +- public output schema and emitted-column identities; +- per-output fingerprint; +- deterministic warnings; and +- creation and retention metadata. + +The receipt does not persist optimized physical IR, AQL, bind variables, or +physical storage names. Those are request-scoped compiler products. Runtime +deterministically lowers the frozen resolved recipe again and verifies its +recipe digest, resolved schema digest, and output fingerprints. This +re-lowering is cheap and does not repeat semantic discovery or authoring +translation. + +### Compile operation behavior + +The compilation operation accepts authoring intent and an exact capability +snapshot. It validates, normalizes, lowers, resolves, optimizes, creates the +public bindings, persists the receipt, and returns the receipt ID. + +Compilation is side-effect free with respect to user data and publication: it +does not materialize rows, create an active Explorer revision, or move an active +pointer. Persisting the immutable receipt is necessary and is not publication. + +Compilation is idempotent. The same canonical intent, snapshot, scope, +generation, schema, receipt format, and compiler contract produces the same +compilation key and content-addressed receipt ID. Loom performs a tenant-scoped +compilation-key lookup before translating. Arango uses immutable +`INSERT ... overwriteMode: "ignore"` rather than an updating UPSERT, then reads +and validates the stored artifact. + +The receipt must be stored before Loom returns a successful Builder +reconciliation. Returning success without a retrievable artifact recreates the +current race in which preview has to repeat the work. + +### Compatibility with the current frontend + +The existing frontend can use the boundary without owning compiler internals: + +1. POST /builder compiles and persists the receipt. +2. The response includes the receipt ID and compiler-owned emitted columns. +3. Preview and publish submit that receipt ID. +4. Debounced compile plus compile-before-preview safely handles a missing or + stale local receipt. + +V1 has no production authoring route. It remains available only to migrate old +stored documents. + +### Validity and retention + +A content-addressed receipt never mutates into a different receipt. Execution +eligibility can still change: + +- the caller may lose authorization; +- the pinned generation may be retired; +- the running Loom version may not support the artifact format; +- an operator may invalidate a compromised compiler build; or +- an unreferenced ephemeral receipt may be explicitly purged. + +These cases produce explicit execution diagnostics. Loom must never silently +recompile the receipt against a newer generation or snapshot. + +Receipts referenced by published immutable revisions are retained with those +revisions. Loom exposes receipt size/count statistics and explicit orphan +purge. Automatic TTL is intentionally deferred until deployed storage +measurements justify a policy. + +### Concurrency behavior + +Receipts also make debounced frontend concurrency harmless. If several Builder +requests are in flight, each successful request produces an artifact for its +own content. The frontend may ignore an older response, but the old response +cannot overwrite the newer artifact. Previewing a receipt always refers to one +exact intent. + +## E. Preview by receipt + +```text +POST .../authoring/v2/preview + receiptId + outputId + optional limit +``` + +Preview does not accept fresh mutable intent. + +### Current behavior + +The production V2 route now loads the exact persisted receipt by project, +Explorer, and receipt ID. It does not accept an authoring bundle and does not +call the authoring compiler. + +### Required preview flow + +Receipt-based preview performs only: + +1. Load the immutable receipt. +2. Verify that it belongs to the route's project and Explorer. +3. Re-authorize the caller against the pinned project, generation, and scope. +4. Validate the receipt ID, compilation key, format/compiler versions, resolved + recipe digest, and output-contract digest. +5. Verify that outputId exists in the receipt. +6. Deterministically lower the frozen resolved recipe without catalog + discovery. +7. Verify the resolved schema digest and per-output fingerprints. +8. Apply a bounded preview window to only the requested output. +9. Render and execute with server-owned authorization bind variables. +10. Return the public columns and rows recorded by the receipt. + +It must not: + +- read a new capability snapshot; +- normalize route occurrences; +- resolve candidate IDs; +- lower authoring intent; +- rediscover dynamic fields; +- rediscover or reinterpret semantic inputs; or +- select a different generation. + +### Generation semantics + +The receipt pins an immutable generation. Preview should remain reproducible +against that generation while it is retained and the caller remains authorized, +even after a newer generation becomes active. A generation switch must not +silently change an existing receipt. + +If the pinned generation has been retired, Loom returns a specific +receipt-input-unavailable diagnostic. The frontend can then refresh Builder +capabilities and reconcile again. + +Publication may use a stricter policy and require that the receipt generation +is still the expected active generation. Preview and publication do not need +identical staleness rules. + +### Execution contract + +The receipt already contains: + +- output identity; +- public output schema; +- resolved semantic recipe; +- project, generation, and authorization-scope identity; +- resolved recipe/schema and output fingerprints; and +- deterministic diagnostics. + +Preview rebuilds request-scoped physical IR and AQL because those are compiler +implementation details, then adds the bounded row limit. It does not redo +authoring translation or schema discovery. + +Loom must enforce: + +- default and maximum row limits; +- a ten-second request deadline; +- client cancellation; +- maximum query cost or approved plan class; +- output-specific execution rather than running every output; +- authorization predicates independent of client input; and +- a 32 MiB encoded-response limit with atomic response semantics. + +The static plan gate runs before Arango execution and rejects a plan outside +the approved preview class. Representative generated plans are checked with +Arango `EXPLAIN`; passing the gate is not a promise that Arango will be +available at execution time. If the encoded response would exceed 32 MiB, +Loom returns `PREVIEW_RESPONSE_TOO_LARGE` without a partial row set. If the +deadline expires, it returns `PREVIEW_TIMEOUT`. Receipt-store dependency +failures use `RECEIPT_STORE_UNAVAILABLE`; those and timeouts are retryable. +`PLAN_TOO_EXPENSIVE` and `PREVIEW_RESPONSE_TOO_LARGE` require a smaller +request, while `CLIENT_CANCELED` is not a server outage. + +Fiber/fasthttp does not propagate a browser disconnect through the handler's +context. Preserve `CLIENT_CANCELED` when an explicit cancellable context is +terminated, but assume an aborted browser request may continue until Loom's +ten-second deadline. Never classify an empty or truncated preview by matching +error text. The browser should retain the latest Builder document and branch +on stable diagnostic codes when a response is available. + +Compilation validates lowering for every output, and representative integration +tests should render and run Arango EXPLAIN. Database execution can still fail +because Arango is unavailable, but it should not fail because Loom advertised a +traversal it could never lower. + +### Response + +The response preserves the frontend's public rows-and-columns shape and binds +it to the receipt: + +~~~json +{ + "outputId": "out_...", + "columns": [], + "rows": [], + "rowCount": 0, + "receiptId": "receipt_..." +} +~~~ + +## F. Asynchronous publication + +```text +POST /publications + compilationId + expectedActiveRevision + +→ operationId +``` + +Publication should: + +- materialize outputs; +- verify them; +- persist the immutable Explorer revision; +- atomically activate it; +- retain the previous active revision on any failure. + +The UI should poll or subscribe to an operation with a clear stage. + +## G. Typed diagnostic registry + +Every diagnostic should define: + +- stable code; +- stage; +- affected object ID; +- JSON path; +- user-facing message; +- technical details; +- retryable flag; +- recovery action. + +Recovery actions might include: + +- `REFRESH_CATALOG`; +- `REMOVE_ROUTE_STEP`; +- `CHANGE_ROW_ROOT`; +- `RESELECT_COLUMN`; +- `RECOMPILE`; +- `RETRY_PREVIEW`; +- `CONTACT_OPERATOR`. + +No layer should classify errors by searching `err.Error()`. + +### Diagnostics are a safety net + +Diagnostics are not the primary mechanism for telling the frontend what is +selectable. If the capability snapshot is correct, normal traversal authoring +should not routinely produce unsupported row-grain, stale candidate, invalid +selector, or impossible route errors. + +Failures still occur because of stale state, authorization changes, malformed +clients, query cost, dependency outages, and publication conflicts. Those +failures need one Loom-wide contract. + +### Current Loom gap + +Loom currently has two overlapping mechanisms: + +- Explorer AuthoringError and AuthoringDiagnostic; and +- the more disciplined internal dataframe UserError contract. + +The dataframe contract already provides stable codes, safe details, field +paths, retryability, cause preservation, and normalization without parsing +English text. The Explorer boundary partially bypasses it and sometimes +classifies compiler failures by searching error strings. + +Authoring should use one registry and one adapter. Schema, compiler, planner, +renderer, Arango, and publication errors are normalized once. The original +wrapped cause is retained in server logs only. + +### Wire contract + +For traversal failures, the affected identity should be as specific as +possible: + +- output ID; +- tab ID; +- route occurrence ID; +- edge ID; +- node ID; +- candidate ID; +- emission ID; or +- compilation receipt ID. + +A consistent diagnostic looks like: + +~~~json +{ + "severity": "error", + "stage": "capability|intent|compile|preview|publish", + "code": "INVALID_TRAVERSAL", + "jsonPath": "$.documents[0].routeEdgeIds[2]", + "object": { + "kind": "routeEdge", + "id": "e_..." + }, + "message": "This relationship is no longer available from Observation.", + "details": { + "fromNodeId": "n_observation", + "snapshotToken": "sha256:..." + }, + "retryable": false, + "recoveryAction": "REFRESH_CAPABILITIES", + "requestId": "..." +} +~~~ + +Severity casing must be standardized. The current Go authoring response uses +uppercase values while frontend types expect lowercase values. + +### Ordering for the current frontend + +The current frontend normally displays only the first diagnostic's message and +code. Until that changes, Loom must: + +- sort diagnostics deterministically; +- put the most actionable root cause first; +- make the first message understandable without hidden details; +- never expose a raw Go, Arango, or ClickHouse error as that message; +- attach the request ID to the first diagnostic; and +- avoid returning a generic wrapper when a specific semantic cause exists. + +Loom should still return every diagnostic so the frontend can improve without +another backend redesign. + +### Recovery actions + +Recovery actions describe what state became invalid; Loom should not silently +rewrite user intent. The registry should distinguish at least: + +- REFRESH_CAPABILITIES; +- REMOVE_ROUTE_STEP; +- CHANGE_ROW_ROOT; +- RESELECT_COLUMN; +- RECOMPILE; +- RETRY_PREVIEW; and +- CONTACT_OPERATOR. + +### Error ownership + +Each layer owns its semantic failures: + +- capability compiler: incomplete snapshot, invalid resource or relationship, + schema incompatibility; +- authoring normalizer: malformed occurrence or identity structure; +- compiler: invalid traversal, selector, cardinality, or plan cost; +- receipt store: missing or incompatible receipt; +- preview executor: timeout, cancellation, backend unavailable; +- publication: conflict, materialization failure, activation failure. + +The HTTP adapter maps the normalized error to status and wire diagnostics. It +does not infer semantics from text. + +Suggested status policy: + +- 400 for malformed protocol or JSON; +- 401/403 for authentication or authorization; +- 404 for an absent Explorer, receipt, output, or retained generation; +- 409 for a stale snapshot, revision conflict, or incompatible receipt; +- 422 for well-formed intent violating a declared semantic rule; +- 429 for a cost or concurrency limit; +- 503 for a retryable dependency failure; and +- 500 for an unknown defect with a safe generic message. + +The server log for every failure should include request ID, diagnostic code, +stage, project, Explorer, snapshot or receipt identity, and the full wrapped +cause. The client receives only the safe contract. + +### Diagnostic invariants + +Tests should guarantee: + +- every public failure has a registered code; +- each code has one stable meaning and recovery action; +- no raw backend error reaches the response; +- retryable codes and HTTP statuses agree; +- JSON paths refer to real authoring fields; +- diagnostics are deterministically ordered; +- the first diagnostic remains useful to the current frontend; and +- typed dataframe errors survive the Explorer adapter without collapsing into + INVALID_AUTHORING_INTENT. + +## H. A simple frontend state machine + +The frontend should primarily manage: + +```text +CLEAN +DIRTY +SAVING +VALIDATING +INVALID +COMPILED +PREVIEWING +PUBLISHING +PUBLISHED +CONFLICTED +``` + +A catalog selection should either be executable or visibly disabled. The browser should not need to understand Loom’s schema resolver, semantic planner, physical lowering, Arango, ClickHouse, or release lifecycle. + +--- + +# 13. What to keep, rewrite, and retire + +## Keep + +- generated FHIR schema metadata; +- generated and generic resource extraction; +- graph resource representation; +- immutable generation manifests and atomic activation; +- recipe semantic and physical compiler; +- AQL renderer; +- Arango query client; +- ClickHouse bundle publisher; +- immutable Explorer revisions; +- focused tests around compilation and failure-safe activation. + +## Rewrite or consolidate + +- Explorer authoring HTTP contract; +- capability catalog construction; +- error translation; +- draft ownership; +- compilation receipt lifecycle; +- preview/publication orchestration; +- generation-aware storage resolution; +- field enrichment scheduling. + +## Retire + +- unused legacy Explorer lifecycle/compiler paths; +- separately handwritten Go and TypeScript contract definitions; +- observation catalogs as direct authoring truth; +- endpoints that accept and recompile whole bundles for preview and publish; +- last-writer-wins activation; +- migration execution inside the server pod. + +This can remain a modular monolith. It does not require splitting Loom into a dozen network services. + +--- + +# 14. Recommended sequence + +## Phase 0: Stabilize the existing interface + +- Hide every non-concrete row root. +- Validate catalog candidates through the real selector/compiler logic before advertising them. +- Add `eligible` and `blockedReason`. +- Render all diagnostics, request IDs, stages, and recovery actions. +- Pass request IDs for preview and publication. +- Cancel superseded reconciliation calls. +- Stop silently omitting incomplete visible tables from validation. +- Deploy matching frontend/backend contract versions. + +## Phase 1: Establish a generated shared contract + +- Publish JSON Schema or OpenAPI for authoring documents and responses. +- Generate both Go validation fixtures and TypeScript types. +- Add an explicit protocol version and compiler/schema build digest. +- Fail closed when frontend and Loom do not support the same version. + +## Phase 2: Introduce drafts and compilation receipts + +- Persist drafts with CAS. +- Make compilation side-effect free. +- Preview exclusively by receipt. +- Invalidate receipts when draft or catalog snapshot changes. + +## Phase 3: Make publication asynchronous and transactional + +- Materialize from a receipt. +- Preserve the previous active release on failure. +- Expose publication stage and operation status. +- Make retries idempotent. + +## Phase 4: Separate enrichment from ingestion + +- Keep graph loading bounded. +- Run field profiling asynchronously. +- Use bounded sketches or top-K values rather than exact unbounded distinct sets. +- Never block generation activation on optional UI enrichment. + +## Phase 5: Remove the old architecture + +- Delete inactive V2 lifecycle/compiler code. +- Remove compatibility adapters once the hard cutover is proven. +- Reduce the Explorer store to clear draft, compilation, revision, publication, and active-pointer concepts. + +--- + +# 15. Testing assessment + +The focused Loom test suite passed across the server, Explorer, compiler, publication, catalog, and FHIR-schema packages. + +The targeted frontend checks also passed: + +- 7 Loom API/state tests; +- 2 Explorer contract/runtime tests; +- no-output TypeScript checks for both core and frontend packages. + +Those tests confirm local behavior, not frontend/backend compatibility. Missing coverage includes: + +- every advertised root compiles; +- every advertised relationship extends the route legally; +- every advertised candidate can be selected; +- all backend diagnostics render and identify their target; +- stale snapshot recovery preserves the draft; +- concurrent browser edits produce a conflict rather than overwrite; +- frontend/backend version skew fails clearly; +- preview and publication use the same compiled plan; +- generation activation changes authoring snapshots safely; +- invalid dependency responses such as `null` arrays cannot cross the contract; +- Arango or ClickHouse failures preserve the active Explorer revision. + +A cross-repository conformance suite is more valuable here than adding more isolated unit tests. + +--- + +# Final judgment + +A radical restructuring is warranted, but the target is specific: + +> Loom must stop exposing storage observations and compiler internals as a frontend authoring API. + +The frontend is not fundamentally asking for something unreasonable. It wants to build a dataframe by selecting a row root, walking relationships, choosing columns, previewing, and publishing. Loom currently makes that workflow cross too many partially overlapping abstractions. + +The desired boundary should be: + +```text +The backend advertises only legal actions. +The frontend submits a small versioned intent. +Compilation produces an immutable receipt. +Preview and publish consume that receipt. +Every failure has a stable recovery action. +``` + +Until that boundary exists, fixing individual errors such as `qualification`, stale candidates, null emissions, route continuity, or unsupported selectors will continue to reveal the next failure underneath. diff --git a/docs/QUICKSTART.md b/docs/QUICKSTART.md index ef9b7a53..79a1aa75 100644 --- a/docs/QUICKSTART.md +++ b/docs/QUICKSTART.md @@ -98,15 +98,21 @@ open http://127.0.0.1:8080/apollo ## 5. Inspect and author an Explorer -Explorer authoring is a REST V2 workflow. Start with the project Explorer -list/detail routes, then use the server-owned catalog compiler and preview -endpoints. The frontend migration guide has the request and response shapes: - -[`FRONTEND_EXPLORER_V2_MIGRATION.md`](FRONTEND_EXPLORER_V2_MIGRATION.md) +Current Builder authoring is the versioned REST V1 publish-only workflow. Use +the project Explorer summaries for selection, then load the selected Explorer's +combined `/authoring/v1/builder` model. Edit its canonical bundle locally and +send only that intent plus its snapshot token to preview or publish. Loom owns +catalog resolution, recipe lowering, compilation, materialization, persistence, +and diagnostics; there is no persisted browser draft or receipt protocol. + +Read [the Explorer authoring guide](EXPLORER_AUTHORING.md) for the current +request/response shapes, route rules, diagnostics, and the offline default +conversion command. The [V2 migration guide](FRONTEND_EXPLORER_V2_MIGRATION.md) +is retained only for legacy packet and ETL migration context. The workflow is deliberately not a GraphQL introspection query: Loom validates catalog selections, dataset generation, recipe compilation, preview, and -publication through the same REST capability path. +publication through the same server-owned REST capability path. ## 6. Run a sample dataframe query diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..548dfd42 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,48 @@ +# Loom documentation + +Use this page to choose the right document. The current runtime contract is +documented separately from migration notes and implementation plans. + +## Start here + +- [Quickstart](QUICKSTART.md) — run Loom locally, load sample data, and make a + first dataframe request. +- [Explorer authoring](EXPLORER_AUTHORING.md) — current V1 Builder contract, + compilation pipeline, receipts, draft/publish behavior, diagnostics, and + offline default conversion. +- [Explorer compilation architecture](EXPLORER_COMPILATION_ARCHITECTURE.md) — + the detailed intent-to-recipe-to-physical-plan-to-AQL path. +- [The Explorer recipe boundary](EXPLORER_RECIPE_BOUNDARY.md) — concrete + examples of the compiler and backend behavior the frontend does not own. +- [GraphQL API](GRAPHQL_API.md) — graph, FHIR dataframe, and published-data + GraphQL contracts. + +## Developer and operator references + +- [Developer architecture](DEVELOPER_ARCHITECTURE.md) — package boundaries, + compiler ownership, storage model, and runtime call paths. +- [Dataframer recipes](DATAFRAMER_RECIPES.md) — native recipe authoring for + repository, ETL, and developer workflows. +- [Dataframer recipe reference](DATAFRAMER_RECIPE_REFERENCE.md) — complete + recipe language and deployment runbook. +- [Code generation](CODE_GENERATION.md) — generated sources and regeneration + commands. +- [Compiler performance](COMPILER_PERFORMANCE.md) — benchmark and tuning + guidance. +- [Dataframe federation](DATAFRAME_FEDERATION.md) — published-data source + selection and cross-project reads. +- [Reliability contract](loom-reliability-contract.md) — immutable generations, + publication, selectors, and error-state guarantees. + +## Migration and planning material + +- [Historical Explorer V2 migration](FRONTEND_EXPLORER_V2_MIGRATION.md) — + retained for compatibility and ETL migration context. It is not the current + browser authoring contract; use [Explorer authoring](EXPLORER_AUTHORING.md) + for new Builder work. +- [Frontend facet performance plan](FRONTEND_DATAFRAME_FACET_PERFORMANCE_PLAN.md) + — implementation planning material, not a runtime API reference. + +Documents named `PLAN_*`, `*_PLAN`, or similar are planning artifacts when +present in a checkout. They may explain motivation or rollout history, but the +contract documents above are the source of truth for current behavior. diff --git a/docs/frontend/explorer-v2-capability-authoring.md b/docs/frontend/explorer-v2-capability-authoring.md new file mode 100644 index 00000000..3d084311 --- /dev/null +++ b/docs/frontend/explorer-v2-capability-authoring.md @@ -0,0 +1,234 @@ +# Explorer V2 capability and authoring handoff + +This handoff matches `internal/explorer/authoringv2` and +`RegisterExplorerAuthoringV2Routes`. The older +`docs/FRONTEND_EXPLORER_V2_MIGRATION.md` describes a superseded +`ExplorerConfigV2` packet and must not be used for Builder HTTP work. + +## Hard cutover + +The browser uses only `/authoring/v2` after a coordinated Loom/frontend +deployment. V1 authoring is not an HTTP compatibility surface. Loom may retain +the V1 decoder solely to migrate already-stored documents into V2; it must not +be probed, advertised, or used as a browser fallback. + +The configurable REST base is: + +```text +/api/v1/projects/{project}/explorers/{explorerId}/authoring/v2 +``` + +The reverse-proxy prefix, host, and port remain application configuration. +Requests use the existing authenticated session and project authorization. + +## Routes and exact wire shapes + +| Operation | Route | Wire shape | +| --- | --- | --- | +| Capability metadata | `GET .../capability` | supported operations, preview limits, and feature flags | +| Candidate search | `POST .../suggestions` | `{snapshotToken, nodeId, query?}` → matching candidate definitions | +| Candidate suggestions | `GET .../capabilities/{snapshotToken}/candidates/{candidateId}/suggestions` | `ExplorerCandidateSuggestions` | +| Builder read | `GET .../builder` | `ExplorerBuilderState` | +| Builder reconcile | `POST .../builder` | `{workspace, snapshotToken}` → `ExplorerBuilderReceipt` | +| Compile alias | `POST .../compile` | exact alias of POST Builder | +| Preview | `POST .../preview` | `{receiptId, outputId, limit?}` → `ExplorerBuilderPreview` | +| Publish | `POST .../publish` | `{receiptId}` → `ExplorerBuilderPublication` | + +POST bodies are strict: unknown fields, duplicate keys, trailing JSON, recipe +AST, selectors, AQL, physical identities, and generated columns are rejected. +Send the exact snapshot token returned by the catalog. Preview and publish take +only a server-owned receipt; they do not accept a mutable document. + +## Catalog, provenance, and fail-closed enrichment + +`GET builder` carries the catalog used to validate the workspace. Its wire +fields are `generation`, `authorizationScopeDigest`, optional +`resolvedSchemaDigest`, `snapshotToken`, `complete`, `nodes`, `edges`, +`candidates`, and `routePolicy`. `GET capability` is smaller metadata used for +feature discovery; it does not return the catalog. + +These fields are the wire provenance. Do not invent a separate `provenance` +object or rename `generation`. The token identifies this +exact immutable generation and authorization scope. Nodes use `nodeId`, edges +use `edgeId`, and candidates use `candidateId`; all are opaque and scoped to +the token. + +Required evidence is fail closed. Resource inventory, relationships, and field +enrichment must be available, complete, and untruncated before Loom exposes a +usable capability. A failed `GET capability` returns a stable +`CAPABILITY_UNAVAILABLE` diagnostic (normally HTTP 503); it does not return a +partial selectable graph. Observation counts and suggested values may enrich +a compiler-approved candidate but cannot create a selector capability. + +Catalog fields are intentionally small: + +- A node is `{nodeId, resourceType, rowRootEligible, rowGrain?, populated, + documentCount?}`. `documentCount` is a non-negative count when available. +- An edge is `{edgeId, fromNodeId, toNodeId, label}` in Builder direction. +- A candidate has `candidateId`, `nodeId`, `label`, `logicalType`, + `repeated`, `filterable`, `chartable`, `projectionModes`, and + `defaultProjectionMode`. + +Suggested values are intentionally not embedded in the catalog. When a field +control is opened, fetch them with the exact catalog `snapshotToken` and +`candidateId`. The response is `{apiVersion, kind, snapshotToken, candidateId, +values, complete, truncated}`. A stale token returns +`STALE_CAPABILITY_SNAPSHOT`; an unknown candidate returns `CANDIDATE_NOT_FOUND`. +`complete` and `truncated` describe only the bounded suggestion response and +must not be interpreted as capability completeness. + +Projection values are uppercase and must be copied from the candidate. The +wire vocabulary is `VALUE`, `FIRST`, and `ALL`; migration-compatible +`SCALAR`, `ARRAY`, and `DISTINCT_ARRAY` values are also accepted. There are no +`aggregate`, `pivot`, `explode`, or lower-case wire values in this V2 +implementation. + +## Document and route semantics + +An `ExplorerBuilderDocument` contains `kind`, `output` (`id` and +`title`), `rootNodeId`, `routeSteps`, `selections`, and `presentation`. +There is no `baseNodeId`, `rowNodeId`, `routeEdgeIds`, or authored +`routeOccurrences` in V2. + +`routeSteps` is an ordered finite edge path from `rootNodeId`. Each step is +`{edgeId, occurrenceId?}`. If omitted, the server derives `step-1`, `step-2`, +and so on. The root occurrence is always `base`; occurrence identities are +derived from the path and are not a second node identity. + +The route policy is explicit: `routePolicy` has `allowRepeatedEdges`, +`allowSelfLoops`, and optional `maxSteps`. When `maxSteps` is omitted, every +finite route is eligible. +There is no hidden four-hop or schema maximum. Repeated edges and self-loops +are valid when the returned policy allows them. The server still validates +edge existence and continuity. + +Each selection is `{candidateId, occurrenceId?, projectionMode}`. An omitted +occurrence selects the route tail; an explicit occurrence must be one derived +by this exact route and must have the candidate's node. The same candidate can +be selected at multiple occurrences. Duplicate `(candidateId, occurrenceId)` +pairs are rejected. `presentation` is a map from non-empty client keys to +`{label?, visible?, order?}` and contains no executable fields. + +## Builder state and receipt lifecycle + +`GET builder` returns `{apiVersion, kind, workspace?, catalog}`. `workspace` is +nullable/omitted for an unpublished Explorer; do not require a workspace before +rendering the catalog. The catalog and workspace, when present, come from one +snapshot. + +POST Builder and POST Compile validate the workspace against the exact token, +compile it, persist an immutable receipt, and return: + +```json +{ + "apiVersion": "loom.calypr.org/explorer-authoring/v2", + "kind": "ExplorerBuilderReceipt", + "builder": {"...": "ExplorerBuilderWorkspace"}, + "receiptId": "receipt_...", + "snapshotToken": "sha256:...", + "generation": "generation-...", + "intentDigest": "sha256:...", + "compilerVersion": "explorer-authoring-v2", + "outputs": [], + "diagnostics": [] +} +``` + +The receipt pins intent, snapshot, generation, authorization, the resolved +semantic recipe, and its public output contract. Request-scoped physical IR +and AQL are deterministically regenerated and are not persisted. Preview loads +that receipt and returns +`ExplorerBuilderPreview` with `receiptId`, `outputId`, emitted `columns`, +`rows`, and `rowCount`. Publish loads the same receipt and returns +`ExplorerBuilderPublication` with `receiptId`, `revisionId`, `state`, and +materialized `outputs`. Neither operation silently recompiles against a newer +snapshot. If the receipt's snapshot is stale or no longer authorized, preserve +the user's document, refresh Builder state, and require explicit recompile. + +### Preview limits and recovery + +Preview is a bounded, atomic read. Loom applies a ten-second server deadline +and rejects a response whose encoded body would exceed 32 MiB; it does not +return a partial row set. The static plan gate checks the generated plan before +execution, and representative plans are verified with Arango `EXPLAIN`. A +request that passes the gate can still fail if Arango is unavailable. + +Preview failures use stable dataframe codes. `RECEIPT_STORE_UNAVAILABLE` and +`PREVIEW_TIMEOUT` are retryable; retry the same receipt after a short delay. +`PREVIEW_RESPONSE_TOO_LARGE` is not retryable with the same request: lower the +row limit or select a narrower output. `PLAN_TOO_EXPENSIVE` is also +non-retryable until the authored output is reduced. `CLIENT_CANCELED` means +an explicit server-visible context was canceled and should not be surfaced as +a server outage. Fiber cannot currently propagate every browser disconnect, +so an aborted browser request may continue on Loom for at most the ten-second +deadline. `BACKEND_UNAVAILABLE` is retryable when the dependency is +temporarily unavailable. The browser should branch on `error.code`, preserve +the latest Builder document, and choose the documented recovery action rather +than parsing the human-readable message. + +## Stable diagnostics and recovery + +Capability failures use `CAPABILITY_UNAVAILABLE`; stale token/receipt input +uses `STALE_CAPABILITY_SNAPSHOT` or `RECEIPT_INPUT_UNAVAILABLE`; malformed +input uses `MALFORMED_AUTHORING_REQUEST`; semantic document failures use +`INVALID_AUTHORING_INTENT`; preview uses `RECEIPT_NOT_FOUND`, +`UNKNOWN_AUTHORING_OUTPUT`, `INVALID_PREVIEW_LIMIT`, `PLAN_TOO_EXPENSIVE`, +`RECEIPT_STORE_UNAVAILABLE`, `PREVIEW_TIMEOUT`, +`PREVIEW_RESPONSE_TOO_LARGE`, `CLIENT_CANCELED`, `BACKEND_UNAVAILABLE`, or +`PREVIEW_FAILED`; +old receipt contracts use `RECEIPT_RECOMPILE_REQUIRED`; publication uses +`NO_SELECTED_COLUMNS`, `PUBLICATION_CONFLICT`, `MATERIALIZATION_FAILED`, or +`MATERIALIZATION_ACTIVATION_FAILED`. + +HTTP expectations are stable: `400` malformed input, `401/403` auth failure, +`404` missing Explorer or receipt, `409` stale snapshot or publication +conflict, `413` preview response too large, `422` semantic intent or unknown +output failure, +`499` client cancellation where the deployment exposes that status, `504` +preview timeout, and `503` unavailable dependency or receipt store. Render the +safe server message and preserve the request ID; never classify by matching +prose or expose wrapped storage errors. + +## Frontend migration work package + +Target repository: `/Users/peterkor/Desktop/FFNEW/IDP-Frontend`. This is a +handoff only; this task does not edit that repository. + +- [ ] Add a configurable V2 base path and typed calls for capability, builder + GET/POST, compile alias, receipt preview, and receipt publish. +- [ ] Remove V1/GraphQL Builder calls and route probing. A missing V2 route is + a coordinated-deployment failure, not a V1 fallback. +- [ ] Generate TypeScript types/runtime validators from + `schemas/explorer-authoring-v2/openapi.yaml`; + reject unknown fields and preserve `nodeId`, `edgeId`, `candidateId`, + `snapshotToken`, and `receiptId` as opaque strings. +- [ ] Treat `workspace` in Builder state as nullable/omitted; render an empty + Builder from catalog state without fabricating a workspace. +- [ ] Author only `rootNodeId`, ordered `routeSteps`, `selections`, and + presentation. Remove `baseNodeId`, `rowNodeId`, `routeEdgeIds`, and + `routeOccurrences` from frontend state and payloads. +- [ ] Derive/display occurrences from route steps. Preserve explicit + `occurrenceId`s, support omitted IDs and the derived `base`/`step-N` + identities, and do not add a hidden route cap or deduplicate repeated + edges/self-loops. +- [ ] Render only uppercase advertised projection modes. Bind selections by + candidate plus exact occurrence and handle omitted occurrence as tail. +- [ ] Render `rowRootEligible`, `rowGrain`, `populated`, and `documentCount` + from nodes; use candidate suggestion metadata to decide whether to show + a suggestions control, then fetch values through the token-pinned + suggestions route. +- [ ] Fail closed when capability is incomplete/truncated or enrichment is + unavailable; never synthesize fields from observed data. +- [ ] Debounce/cancel Builder POSTs, retain the latest document locally, and + store only server-returned receipt/emission identities. +- [ ] Preview exclusively by `{receiptId, outputId, limit?}` and publish + exclusively by `{receiptId}`. Replace local publication state from the + returned response and retain the prior active view on failure. +- [ ] Handle stale snapshot/receipt diagnostics by retaining edits, refreshing + Builder state, and requiring explicit recompile. +- [ ] Add conformance tests for empty Builder state, zero-hop routes, derived + occurrences, long finite repeated/self-loop routes, omitted selection + occurrences, duplicate selections, uppercase projection modes, stale + tokens, receipt reuse, and fail-closed incomplete catalogs. +- [ ] Run typecheck, unit tests, and production build against a coordinated V2 + Loom deployment; verify no V1 authoring HTTP route is registered. diff --git a/go.mod b/go.mod index 72b4ff26..1170a91c 100644 --- a/go.mod +++ b/go.mod @@ -11,14 +11,17 @@ require ( github.com/bytedance/sonic v1.15.2 github.com/gofiber/fiber/v3 v3.4.0 github.com/google/uuid v1.6.0 + github.com/oapi-codegen/runtime v1.6.0 github.com/vektah/gqlparser/v2 v2.5.36 go.yaml.in/yaml/v3 v3.0.5 + golang.org/x/sync v0.22.0 ) require ( github.com/ClickHouse/ch-go v0.73.0 // indirect github.com/agnivade/levenshtein v1.2.1 // indirect github.com/andybalholm/brotli v1.2.2 // indirect + github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e // indirect github.com/bytedance/gopkg v0.1.4 // indirect github.com/bytedance/sonic/loader v0.5.1 // indirect @@ -56,7 +59,6 @@ require ( golang.org/x/arch v0.29.0 // indirect golang.org/x/crypto v0.54.0 // indirect golang.org/x/net v0.57.0 // indirect - golang.org/x/sync v0.22.0 // indirect golang.org/x/sys v0.47.0 // indirect golang.org/x/text v0.40.0 // indirect google.golang.org/protobuf v1.36.11 // indirect diff --git a/go.sum b/go.sum index 9cbc7afe..6fe94e7c 100644 --- a/go.sum +++ b/go.sum @@ -4,16 +4,20 @@ github.com/ClickHouse/ch-go v0.73.0 h1:jsHiGRbQ3sz+gekvDFJF29LWDo5dzbJm5s1h8TWVP github.com/ClickHouse/ch-go v0.73.0/go.mod h1:wkFIxrqlXeRJ9cn3r5Fz5Qen9jl5aTMPuGZeuJpANNY= github.com/ClickHouse/clickhouse-go/v2 v2.47.0 h1:ZDAzrnKSOPTIsm4tdUNfrii2yc8dk4SVRLC77BR7Z5Q= github.com/ClickHouse/clickhouse-go/v2 v2.47.0/go.mod h1:sPj7C7UYQ2MWHcfX+4eGN6nwnCqwUKfgO6PcwKpd6K8= +github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM= github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= github.com/andybalholm/brotli v1.2.2 h1:HzTuoo2ErYQqf5qvcJInB8uvqSVxRttzkFexPWtnceM= github.com/andybalholm/brotli v1.2.2/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= +github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= +github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/arangodb/go-driver/v2 v2.3.1 h1:km44FjBl6Uh+rD+0mPLLCkOv7QNOTl460Eid7jwQFMQ= github.com/arangodb/go-driver/v2 v2.3.1/go.mod h1:Mi++s/SLvrrXKmLpAy84ivZ3fuyUBPu7ydmyJo3PMlk= github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e h1:Xg+hGrY2LcQBbxd0ZFdbGSyRKTYMZCfBbw/pMJFOk1g= github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e/go.mod h1:mq7Shfa/CaixoDxiyAAc5jZ6CVBAyPaNQCGS7mkj4Ho= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= +github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bmeg/jsonschema/v6 v6.0.5 h1:GnyWf8badsqBE0KytRwiuev240HtH89aj04+CzOd6SQ= github.com/bmeg/jsonschema/v6 v6.0.5/go.mod h1:g21s8u35PcH2eGtPBjavAPmXWTwBLd40lHNyq72+ihs= github.com/bmeg/jsonschemagraph v0.0.6 h1:0lbnSPNdtRmcVLAYzbRN1YuYVDGs2qcOg2kmYW09kRo= @@ -48,8 +52,6 @@ github.com/go-faster/errors v0.8.0 h1:9T9eJrM+72dFk7n4DfhuaDDe6cyuFCSW2oNUkN77Yq github.com/go-faster/errors v0.8.0/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= -github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/gofiber/fiber/v3 v3.4.0 h1:F0aND4vwZF7dR7cbvSwFQQEpBU902XHKWxrLsFBkVqw= github.com/gofiber/fiber/v3 v3.4.0/go.mod h1:nAhJfdxUIJJph2tPWPmqWf8QDIN2iiqQiQf3lENZpdk= github.com/gofiber/schema v1.8.3 h1:06ZedxIYjngzc0095PYy7uWnFnbRflWFpikvZH61fDc= @@ -67,6 +69,7 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= github.com/kkdai/maglev v0.2.0 h1:w6DCW0kAA6fstZqXkrBrlgIC3jeIRXkjOYea/m6EK/Y= github.com/kkdai/maglev v0.2.0/go.mod h1:d+mt8Lmt3uqi9aRb/BnPjzD0fy+ETs1vVXiGRnqHVZ4= github.com/klauspost/compress v1.19.1 h1:VsB4HPswih7mmZ8WleSFQ75c/Ui1M4trX5oAsJnhSlk= @@ -77,6 +80,10 @@ github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI= github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A= +github.com/oapi-codegen/nullable v1.1.0 h1:eAh8JVc5430VtYVnq00Hrbpag9PFRGWLjxR1/3KntMs= +github.com/oapi-codegen/nullable v1.1.0/go.mod h1:KUZ3vUzkmEKY90ksAmit2+5juDIhIZhfDl+0PwOQlFY= +github.com/oapi-codegen/runtime v1.6.0 h1:7Xx+GlueD6nRuyKoCPzL434Jfi3BetbiJOrzCHp/VPU= +github.com/oapi-codegen/runtime v1.6.0/go.mod h1:GwV7hC2hviaMzj+ITfHVRESK5J2W/GefVwIND/bMGvU= github.com/paulmach/orb v0.13.0 h1:r7n7mQGGF+cj/CbcivEj9J3HGK+XR+yXnvzRdq9saIw= github.com/paulmach/orb v0.13.0/go.mod h1:6scRWINywA2Jf05dcjOfLfxrUIMECvTSG2MVbRLxu/k= github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= @@ -97,10 +104,12 @@ github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sosodev/duration v1.4.0 h1:35ed0KiVFriGHHzZZJaZLgmTEEICIyt8Sx0RQfj9IjE= github.com/sosodev/duration v1.4.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= +github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -112,8 +121,6 @@ github.com/tinylib/msgp v1.6.4 h1:mOwYbyYDLPj35mkA2BjjYejgJk9BuHxDdvRnb6v2ZcQ= github.com/tinylib/msgp v1.6.4/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/urfave/cli/v3 v3.10.1 h1:7Kx9H50hrHbRbyxgO1KP6/BcbiGRz0uYh5YyQ30JEEY= -github.com/urfave/cli/v3 v3.10.1/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.73.0 h1:ocTOORnBWtJ+P8t/6wAjdkchMzdfHmWx2VD/DPbgZ7s= @@ -134,8 +141,6 @@ golang.org/x/arch v0.29.0 h1:8sSET5wB0+exBm0FGmOtdHMqjlRdV2DRD3/IV6OZgho= golang.org/x/arch v0.29.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8= golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= -golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= -golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= @@ -144,8 +149,6 @@ golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= -golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= -golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/catalog/arango/store.go b/internal/catalog/arango/store.go index b72dd2b2..bd327dbf 100644 --- a/internal/catalog/arango/store.go +++ b/internal/catalog/arango/store.go @@ -15,6 +15,7 @@ import ( ) type client interface { + CollectionExists(context.Context, string) (bool, error) QueryRows(context.Context, string, int, map[string]any, store.RowVisitor) error InsertBatchRaw(context.Context, string, []json.RawMessage, bool, string) error ExecuteAQL(context.Context, string, map[string]any) error @@ -165,10 +166,25 @@ func (s *Store) DiscoverResourceInventory(ctx context.Context, opts catalog.Reso "auth_resource_paths_unrestricted": catalog.EffectiveAuthResourcePathsUnrestricted(opts.AuthResourcePaths, opts.AuthResourcePathsUnrestricted), } for _, resourceType := range resourceTypes { - vars["resource_collection"] = resourceType + collectionExists, err := s.client.CollectionExists(ctx, resourceType) + if err != nil { + err = fmt.Errorf("check resource collection %s: %w", resourceType, err) + result.Available, result.Complete, result.Status = false, false, catalog.EvidenceUnavailable + result.Diagnostics = append(result.Diagnostics, catalog.EvidenceDiagnostic{Code: "RESOURCE_INVENTORY_UNAVAILABLE", Message: err.Error(), ResourceType: resourceType}) + return result, err + } + if !collectionExists { + result.Values = append(result.Values, catalog.ResourceInventoryObservation{ + Project: opts.Project, DatasetGeneration: catalog.NormalizeDatasetGeneration(opts.DatasetGeneration), ResourceType: resourceType, DocumentCount: 0, + }) + continue + } + // Arango collection bind parameters use @@name in AQL and require the + // corresponding bind-var map key to retain one leading @. + vars["@resource_collection"] = resourceType vars["resource_type"] = resourceType var rowSeen bool - err := s.client.QueryRows(ctx, resourceInventoryAQL, opts.CursorBatch, vars, func(row map[string]any) error { + err = s.client.QueryRows(ctx, resourceInventoryAQL, opts.CursorBatch, vars, func(row map[string]any) error { rowSeen = true count, err := decodeInt64(row["document_count"]) if err != nil { diff --git a/internal/catalog/arango/store_test.go b/internal/catalog/arango/store_test.go index 6e25da4e..d81033cc 100644 --- a/internal/catalog/arango/store_test.go +++ b/internal/catalog/arango/store_test.go @@ -17,10 +17,25 @@ type fakeClient struct { } type evidenceClient struct { - queries []string - vars []map[string]any - rows map[string][]map[string]any - err error + queries []string + vars []map[string]any + rows map[string][]map[string]any + rowsByCollection map[string][]map[string]any + collections map[string]bool + collectionChecks []string + collectionErr error + err error +} + +func (f *evidenceClient) CollectionExists(_ context.Context, name string) (bool, error) { + f.collectionChecks = append(f.collectionChecks, name) + if f.collectionErr != nil { + return false, f.collectionErr + } + if f.collections == nil { + return true, nil + } + return f.collections[name], nil } func (f *evidenceClient) QueryRows(_ context.Context, query string, _ int, vars map[string]any, visit store.RowVisitor) error { @@ -33,7 +48,11 @@ func (f *evidenceClient) QueryRows(_ context.Context, query string, _ int, vars if f.err != nil { return f.err } - for _, row := range f.rows[query] { + rows := f.rows[query] + if query == resourceInventoryAQL && f.rowsByCollection != nil { + rows = f.rowsByCollection[stringValue(vars["@resource_collection"])] + } + for _, row := range rows { if err := visit(row); err != nil { return err } @@ -46,6 +65,8 @@ func (*evidenceClient) InsertBatchRaw(context.Context, string, []json.RawMessage func (*evidenceClient) ExecuteAQL(context.Context, string, map[string]any) error { return nil } func (*evidenceClient) Bootstrap(context.Context, store.BootstrapSpec) error { return nil } +func (*fakeClient) CollectionExists(context.Context, string) (bool, error) { return true, nil } + func (f *fakeClient) QueryRows(_ context.Context, query string, _ int, _ map[string]any, visit store.RowVisitor) error { f.queries = append(f.queries, query) if query == populatedFieldsAQL || query == relationshipAuditAQL { @@ -170,9 +191,12 @@ func TestCapabilityEvidenceInventoryBindsCollectionAndIdentity(t *testing.T) { t.Fatalf("inventory = %#v err=%v", result, err) } vars := client.vars[0] - if vars["project"] != "p" || vars["dataset_generation"] != "g" || vars["resource_collection"] != "Patient" || vars["auth_resource_paths_unrestricted"] != false { + if vars["project"] != "p" || vars["dataset_generation"] != "g" || vars["@resource_collection"] != "Patient" || vars["auth_resource_paths_unrestricted"] != false { t.Fatalf("inventory binds = %#v", vars) } + if _, exists := vars["resource_collection"]; exists { + t.Fatalf("collection bind used value-variable syntax: %#v", vars) + } for _, name := range []string{"@@resource_collection", "@project", "@dataset_generation", "@auth_resource_paths", "@auth_resource_paths_unrestricted", "COLLECT WITH COUNT"} { if !strings.Contains(client.queries[0], name) { t.Fatalf("inventory query missing %q: %s", name, client.queries[0]) @@ -180,6 +204,44 @@ func TestCapabilityEvidenceInventoryBindsCollectionAndIdentity(t *testing.T) { } } +func TestCapabilityEvidenceInventoryTreatsMissingCollectionAsEmpty(t *testing.T) { + client := &evidenceClient{ + collections: map[string]bool{"Patient": true}, + rowsByCollection: map[string][]map[string]any{"Patient": {{ + "project": "p", "dataset_generation": "g", "resource_type": "Patient", "document_count": int64(7), + }}}, + } + adapter, _ := New(client) + result, err := adapter.DiscoverResourceInventory(context.Background(), catalog.ResourceInventoryOptions{ + Project: "p", DatasetGeneration: "g", ResourceTypes: []string{"Patient", "DiagnosticReport"}, + }) + if err != nil || !result.Available || !result.Complete || len(result.Values) != 2 { + t.Fatalf("inventory = %#v err=%v", result, err) + } + counts := map[string]int64{} + for _, value := range result.Values { + counts[value.ResourceType] = value.DocumentCount + } + if counts["Patient"] != 7 || counts["DiagnosticReport"] != 0 { + t.Fatalf("inventory counts = %#v", counts) + } + if len(client.collectionChecks) != 2 || len(client.queries) != 1 { + t.Fatalf("collection checks=%#v queries=%d", client.collectionChecks, len(client.queries)) + } +} + +func TestCapabilityEvidenceInventoryCollectionLookupFailureIsUnavailable(t *testing.T) { + client := &evidenceClient{collectionErr: errors.New("database unavailable")} + adapter, _ := New(client) + result, err := adapter.DiscoverResourceInventory(context.Background(), catalog.ResourceInventoryOptions{Project: "p", ResourceTypes: []string{"Patient"}}) + if err == nil || result.Available || result.Complete || result.Status != catalog.EvidenceUnavailable { + t.Fatalf("inventory = %#v err=%v", result, err) + } + if len(result.Diagnostics) != 1 || result.Diagnostics[0].Code != "RESOURCE_INVENTORY_UNAVAILABLE" { + t.Fatalf("diagnostics = %#v", result.Diagnostics) + } +} + func TestCapabilityEvidenceFieldEmptyAndFailureAreDistinct(t *testing.T) { emptyClient := &evidenceClient{rows: map[string][]map[string]any{fieldEnrichmentAQL: nil}} emptyStore, _ := New(emptyClient) diff --git a/internal/explorer/arango/capability_snapshot_store.go b/internal/explorer/arango/capability_snapshot_store.go index 80c720ca..adc6b7cf 100644 --- a/internal/explorer/arango/capability_snapshot_store.go +++ b/internal/explorer/arango/capability_snapshot_store.go @@ -57,7 +57,6 @@ func (s *CapabilitySnapshotStore) Put(ctx context.Context, snapshot capability.S var out *capability.Snapshot err = s.client.QueryRows(ctx, capabilitySnapshotPutAQL, 1, map[string]any{ "@c": CapabilitySnapshotCollection, - "key": capabilitySnapshotKey(snapshot.Token), "doc": doc, }, func(row map[string]any) error { value, decodeErr := decode[capability.Snapshot](row) diff --git a/internal/explorer/arango/capability_snapshot_store_test.go b/internal/explorer/arango/capability_snapshot_store_test.go index 3ccd75d0..4f740db8 100644 --- a/internal/explorer/arango/capability_snapshot_store_test.go +++ b/internal/explorer/arango/capability_snapshot_store_test.go @@ -2,6 +2,7 @@ package arango import ( "context" + "regexp" "strings" "testing" @@ -44,14 +45,26 @@ func TestCapabilitySnapshotStoreBindsImmutableIdentity(t *testing.T) { t.Fatalf("calls=%d", len(client.calls)) } call := client.calls[0] + assertOnlyDeclaredCapabilityBinds(t, call) if !strings.Contains(call.query, "INSERT @doc") || !strings.Contains(call.query, `overwriteMode: "ignore"`) || strings.Contains(call.query, "UPDATE") { t.Fatalf("Put query is not immutable insert-if-absent:\n%s", call.query) } + if _, exists := call.binds["key"]; exists { + t.Fatalf("Put supplied undeclared key bind: %#v", call.binds) + } + if len(call.binds) != 2 || call.binds["@c"] != CapabilitySnapshotCollection { + t.Fatalf("Put binds = %#v", call.binds) + } doc := call.binds["doc"].(map[string]any) if doc["token"] != snapshot.Token || doc["identity"] == nil || doc["status"] != string(snapshot.Status) { t.Fatalf("canonical full document=%#v", doc) } + if _, err := adapter.GetByToken(context.Background(), snapshot.Token); err != nil { + t.Fatal(err) + } + assertOnlyDeclaredCapabilityBinds(t, client.calls[len(client.calls)-1]) + client.row, err = canonicalSnapshotDocument(snapshot, capabilitySnapshotKey(snapshot.Token)) if err != nil { t.Fatal(err) @@ -60,6 +73,7 @@ func TestCapabilitySnapshotStoreBindsImmutableIdentity(t *testing.T) { t.Fatal(err) } identityCall := client.calls[len(client.calls)-1] + assertOnlyDeclaredCapabilityBinds(t, identityCall) for _, required := range []string{ "d.identity.project == @project", "d.identity.generation == @generation", "d.identity.authorizationScopeDigest == @authorizationScopeDigest", @@ -78,6 +92,16 @@ func TestCapabilitySnapshotStoreBindsImmutableIdentity(t *testing.T) { } } +func assertOnlyDeclaredCapabilityBinds(t *testing.T, call queryCall) { + t.Helper() + for name := range call.binds { + pattern := "@" + regexp.QuoteMeta(name) + `\b` + if !regexp.MustCompile(pattern).MatchString(call.query) { + t.Errorf("bind variable %q is not declared in query", name) + } + } +} + func testCapabilitySnapshot() capability.Snapshot { return capability.NewSnapshot( capability.SnapshotIdentity{ diff --git a/internal/explorer/arango/receipt_store_test.go b/internal/explorer/arango/receipt_store_test.go index f7b66e97..efc8d86c 100644 --- a/internal/explorer/arango/receipt_store_test.go +++ b/internal/explorer/arango/receipt_store_test.go @@ -50,7 +50,7 @@ func TestReceiptArangoStoreUsesImmutableTenantScopedQueries(t *testing.T) { Project: "project-a", ExplorerID: "explorer-a", IntentDigest: "intent", SnapshotToken: "snapshot", AuthorizationScopeDigest: "scope", CapabilitySchemaDigest: "schema", SourceGeneration: "generation", RecipeDigest: "recipe", ResolvedSchemaDigest: "resolved-schema", - Bundle: bundle, PublicOutputContract: json.RawMessage(`{"outputId":"output","columns":[]}`), + Bundle: bundle, PublicOutputContract: json.RawMessage(`{"outputs":[{"outputId":"output","columns":[]}]}`), } receipt.ResolvedRecipeDigest, _ = bundle.Digest() receipt.OutputContractDigest, _ = explorer.CompilationArtifactDigest(receipt.PublicOutputContract) diff --git a/internal/explorer/authoringv2/types.go b/internal/explorer/authoringv2/types.go index 57e34989..757ea24b 100644 --- a/internal/explorer/authoringv2/types.go +++ b/internal/explorer/authoringv2/types.go @@ -10,6 +10,7 @@ import ( "encoding/json" "fmt" "io" + "net/url" "sort" "strings" ) @@ -17,6 +18,7 @@ import ( const ( APIVersion = "loom.calypr.org/explorer-authoring/v2" Kind = "ExplorerBuilderDocument" + WorkspaceKind = "ExplorerBuilderWorkspace" StateKind = "ExplorerBuilderState" CatalogKind = "ExplorerBuilderCatalog" AuthoringV2APIVersion = APIVersion @@ -30,6 +32,7 @@ const ( // names inside this package. type AuthoringDocumentV2 = Document type ExplorerBuilderDocumentV2 = Document +type ExplorerBuilderWorkspaceV2 = Workspace type BuilderStateV2 = BuilderState type ExplorerBuilderStateV2 = BuilderState type CatalogProjectionV2 = CatalogSnapshot @@ -47,7 +50,7 @@ type CatalogCandidateV2 = CatalogCandidate // path from RootNodeID. Its root occurrence is always "base" and its tail is // computed from the path; neither is a second authored node identity. type Document struct { - APIVersion string `json:"apiVersion"` + APIVersion string `json:"-"` Kind string `json:"kind"` Output Output `json:"output"` RootNodeID string `json:"rootNodeId"` @@ -72,28 +75,64 @@ type Selection struct { ProjectionMode string `json:"projectionMode"` } +// Workspace is the atomic authoring unit. Documents are independent table +// intents; tabs provide their ordered, visible runtime presentation. +type Workspace struct { + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Documents []Document `json:"documents"` + Tabs []Tab `json:"tabs"` +} + +type Tab struct { + ID string `json:"id"` + Title string `json:"title"` + OutputID string `json:"outputId"` + Order int `json:"order"` + Visible bool `json:"visible"` +} + // Presentation contains display intent only. In particular, it has no // selector, expression, physical collection, or generated-column fields. type Presentation struct { - Label string `json:"label,omitempty"` - Visible *bool `json:"visible,omitempty"` - Order *int `json:"order,omitempty"` + Label string `json:"label,omitempty"` + Visible *bool `json:"visible,omitempty"` + Order *int `json:"order,omitempty"` + Table *TablePresentation `json:"table,omitempty"` + Filter *FilterPresentation `json:"filter,omitempty"` + Chart *ChartPresentation `json:"chart,omitempty"` +} + +type TablePresentation struct { + Pinned bool `json:"pinned"` +} +type FilterPresentation struct { + Label string `json:"label,omitempty"` +} +type ChartPresentation struct { + Type string `json:"type"` + Title string `json:"title,omitempty"` +} + +func PresentationKey(candidateID, occurrenceID, projectionMode string) string { + encode := func(value string) string { return strings.ReplaceAll(url.QueryEscape(value), "+", "%20") } + return encode(candidateID) + "::" + encode(occurrenceID) + "::" + encode(projectionMode) } // CatalogSnapshot is an immutable, authorization-scoped projection. The // token identifies the exact snapshot used to validate a document. type CatalogSnapshot struct { - APIVersion string `json:"apiVersion"` - Kind string `json:"kind"` - Project string `json:"project"` - ExplorerID string `json:"explorerId"` - SourceGeneration string `json:"sourceGeneration"` + APIVersion string `json:"-"` + Kind string `json:"-"` + Project string `json:"-"` + ExplorerID string `json:"-"` + SourceGeneration string `json:"generation"` AuthorizationScopeDigest string `json:"authorizationScopeDigest"` ResolvedSchemaDigest string `json:"resolvedSchemaDigest,omitempty"` SnapshotToken string `json:"snapshotToken"` Complete bool `json:"complete"` - Truncated bool `json:"truncated"` - Diagnostics []CatalogDiagnostic `json:"diagnostics"` + Truncated bool `json:"-"` + Diagnostics []CatalogDiagnostic `json:"-"` Nodes []CatalogNode `json:"nodes"` Edges []CatalogEdge `json:"edges"` Candidates []CatalogCandidate `json:"candidates"` @@ -120,6 +159,7 @@ type CatalogEdge struct { FromNodeID string `json:"fromNodeId"` ToNodeID string `json:"toNodeId"` Label string `json:"label"` + Populated bool `json:"populated"` } type CatalogCandidate struct { @@ -127,36 +167,39 @@ type CatalogCandidate struct { NodeID string `json:"nodeId"` Label string `json:"label"` LogicalType string `json:"logicalType"` + Repeated bool `json:"repeated"` Filterable bool `json:"filterable"` Chartable bool `json:"chartable"` ProjectionModes []string `json:"projectionModes"` DefaultProjectionMode string `json:"defaultProjectionMode"` - FilterOperators []string `json:"filterOperators"` - ChartOperations []string `json:"chartOperations"` - Cardinality string `json:"cardinality,omitempty"` - Populated bool `json:"populated"` - Count *int64 `json:"count,omitempty"` - SuggestionsAvailable bool `json:"suggestionsAvailable"` - SuggestionsComplete bool `json:"suggestionsComplete"` - SuggestionsTruncated bool `json:"suggestionsTruncated"` - SuggestionCount int `json:"suggestionCount"` + FilterOperators []string `json:"-"` + ChartOperations []string `json:"-"` + Cardinality string `json:"-"` + Populated bool `json:"-"` + Count *int64 `json:"-"` + SuggestionsAvailable bool `json:"-"` + SuggestionsComplete bool `json:"-"` + SuggestionsTruncated bool `json:"-"` + SuggestionCount int `json:"-"` } // RoutePolicy has no default hop ceiling: nil MaxHops means every finite // route is valid. Repeated edges and self-loops are explicit capabilities. type RoutePolicy struct { - MaxHops *int `json:"maxHops,omitempty"` - Unbounded bool `json:"unbounded"` + MaxHops *int `json:"maxSteps"` + Unbounded bool `json:"-"` AllowRepeatedEdges bool `json:"allowRepeatedEdges"` AllowSelfLoops bool `json:"allowSelfLoops"` } -// BuilderState joins one document to the one catalog snapshot that proves it. +// BuilderState joins one workspace to the one catalog snapshot that proves it. type BuilderState struct { - APIVersion string `json:"apiVersion"` - Kind string `json:"kind"` - Document *Document `json:"document,omitempty"` - Catalog CatalogSnapshot `json:"catalog"` + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Workspace *Workspace `json:"workspace,omitempty"` + // Document is retained only as a source-compatible internal migration aid. + Document *Document `json:"-"` + Catalog CatalogSnapshot `json:"catalog"` } // RouteOccurrence is derived, never wire-authored. The first occurrence has @@ -214,7 +257,7 @@ func DerivedOccurrenceID(stepIndex int) string { } func (d Document) Validate() error { - if d.APIVersion != APIVersion || d.Kind != Kind { + if d.Kind != Kind { return fmt.Errorf("unsupported V2 document protocol or kind") } if emptyID(d.Output.ID) || strings.TrimSpace(d.Output.Title) == "" { @@ -228,6 +271,10 @@ func (d Document) Validate() error { if emptyID(step.EdgeID) { return fmt.Errorf("routeSteps[%d].edgeId is required", i) } + occurrenceID := step.OccurrenceID + if occurrenceID == "" { + occurrenceID = DerivedOccurrenceID(i) + } if step.OccurrenceID != "" { if step.OccurrenceID == RootOccurrenceID { return fmt.Errorf("routeSteps[%d] cannot author the derived base occurrence", i) @@ -235,11 +282,11 @@ func (d Document) Validate() error { if emptyID(step.OccurrenceID) { return fmt.Errorf("routeSteps[%d].occurrenceId is invalid", i) } - if seenOccurrences[step.OccurrenceID] { - return fmt.Errorf("duplicate route occurrence id %q", step.OccurrenceID) - } - seenOccurrences[step.OccurrenceID] = true } + if seenOccurrences[occurrenceID] { + return fmt.Errorf("duplicate route occurrence id %q", occurrenceID) + } + seenOccurrences[occurrenceID] = true } seenSelections := map[string]bool{} for i, selection := range d.Selections { @@ -254,7 +301,7 @@ func (d Document) Validate() error { if selection.OccurrenceID != "" && emptyID(selection.OccurrenceID) { return fmt.Errorf("selections[%d].occurrenceId is invalid", i) } - key := selection.CandidateID + "\x00" + selection.OccurrenceID + key := selection.CandidateID + "\x00" + selection.OccurrenceID + "\x00" + selection.ProjectionMode if seenSelections[key] { return fmt.Errorf("duplicate selection %q", selection.CandidateID) } @@ -271,6 +318,77 @@ func (d Document) Validate() error { return nil } +func (w Workspace) Validate() error { + if w.APIVersion != APIVersion || w.Kind != WorkspaceKind { + return fmt.Errorf("unsupported V2 workspace protocol or kind") + } + outputs, tabs, tabOutputs, orders := map[string]bool{}, map[string]bool{}, map[string]bool{}, map[int]bool{} + for i, d := range w.Documents { + if err := d.Validate(); err != nil { + return fmt.Errorf("documents[%d]: %w", i, err) + } + if outputs[d.Output.ID] { + return fmt.Errorf("DUPLICATE_OUTPUT_ID: documents[%d].output.id", i) + } + outputs[d.Output.ID] = true + } + for i, tab := range w.Tabs { + if emptyID(tab.ID) || strings.TrimSpace(tab.Title) == "" || emptyID(tab.OutputID) || tab.Order < 0 { + return fmt.Errorf("tabs[%d] is invalid", i) + } + if tabs[tab.ID] { + return fmt.Errorf("DUPLICATE_TAB_ID: tabs[%d].id", i) + } + if tabOutputs[tab.OutputID] || !outputs[tab.OutputID] { + return fmt.Errorf("INVALID_TAB_OUTPUT_MAPPING: tabs[%d].outputId", i) + } + if orders[tab.Order] { + return fmt.Errorf("INVALID_TAB_ORDER: tabs[%d].order", i) + } + tabs[tab.ID], tabOutputs[tab.OutputID], orders[tab.Order] = true, true, true + } + if len(w.Tabs) != len(w.Documents) { + return fmt.Errorf("INVALID_TAB_OUTPUT_MAPPING: exactly one tab is required per document") + } + for output := range outputs { + if !tabOutputs[output] { + return fmt.Errorf("INVALID_TAB_OUTPUT_MAPPING: output %q has no tab", output) + } + } + for i := 0; i < len(orders); i++ { + if !orders[i] { + return fmt.Errorf("INVALID_TAB_ORDER: orders must be contiguous from zero") + } + } + return nil +} + +// ValidateForPublication applies constraints that are intentionally too strict +// for mutable Builder state. Changing a table root or route temporarily clears +// its selections; that intermediate workspace remains compilable, but a visible +// table must have at least one visible column before publication. +func (w Workspace) ValidateForPublication() error { + visibleOutputs := make(map[string]bool, len(w.Tabs)) + for _, tab := range w.Tabs { + visibleOutputs[tab.OutputID] = tab.Visible + } + for i, document := range w.Documents { + if !visibleOutputs[document.Output.ID] { + continue + } + hidden := 0 + for _, presentation := range document.Presentation { + if presentation.Visible != nil && !*presentation.Visible { + hidden++ + } + } + if len(document.Selections) == 0 || hidden == len(document.Selections) { + return fmt.Errorf("NO_VISIBLE_COLUMNS: documents[%d]", i) + } + } + return nil +} + func (c CatalogSnapshot) Validate() error { if c.APIVersion != APIVersion || c.Kind != CatalogKind { return fmt.Errorf("unsupported V2 catalog protocol or kind") @@ -362,19 +480,43 @@ func (s BuilderState) Validate() error { if err := s.Catalog.Validate(); err != nil { return err } - if s.Document == nil { + workspace := s.Workspace + if workspace == nil && s.Document != nil { + workspace = &Workspace{APIVersion: APIVersion, Kind: WorkspaceKind, Documents: []Document{*s.Document}, Tabs: []Tab{{ID: s.Document.Output.ID, Title: s.Document.Output.Title, OutputID: s.Document.Output.ID, Order: 0, Visible: true}}} + } + if workspace == nil { return nil } - if err := s.Document.Validate(); err != nil { + if err := workspace.Validate(); err != nil { return err } + for i := range workspace.Documents { + document := workspace.Documents[i] + one := s + one.Workspace = nil + one.Document = &document + if err := one.validateDocument(); err != nil { + return fmt.Errorf("documents[%d]: %w", i, err) + } + } + return nil +} + +func (s BuilderState) validateDocument() error { + d := s.Document + if d == nil { + return nil + } edges, candidates, nodes := s.Catalog.edgeIndex(), s.Catalog.candidateIndex(), s.Catalog.nodeIndex() - if nodes[s.Document.RootNodeID].ID == "" { - return fmt.Errorf("document rootNodeId %q is stale", s.Document.RootNodeID) + if nodes[d.RootNodeID].ID == "" { + return fmt.Errorf("document rootNodeId %q is stale", d.RootNodeID) + } + if !nodes[d.RootNodeID].RowRootEligible { + return fmt.Errorf("ROW_ROOT_NOT_ELIGIBLE: rootNodeId %q", d.RootNodeID) } seenEdges := map[string]bool{} - current := s.Document.RootNodeID - for i, step := range s.Document.RouteSteps { + current := d.RootNodeID + for i, step := range d.RouteSteps { e, ok := edges[step.EdgeID] if !ok { return fmt.Errorf("routeSteps[%d] references stale edge %q", i, step.EdgeID) @@ -388,10 +530,10 @@ func (s BuilderState) Validate() error { seenEdges[e.ID] = true current = e.ToNodeID } - if s.Catalog.RoutePolicy.MaxHops != nil && len(s.Document.RouteSteps) > *s.Catalog.RoutePolicy.MaxHops { + if s.Catalog.RoutePolicy.MaxHops != nil && len(d.RouteSteps) > *s.Catalog.RoutePolicy.MaxHops { return fmt.Errorf("route exceeds routePolicy.maxHops") } - occ, err := s.Document.Occurrences(s.Catalog) + occ, err := d.Occurrences(s.Catalog) if err != nil { return err } @@ -399,7 +541,7 @@ func (s BuilderState) Validate() error { for _, item := range occ { occByID[item.ID] = item } - for i, selection := range s.Document.Selections { + for i, selection := range d.Selections { candidate, ok := candidates[selection.CandidateID] if !ok { return fmt.Errorf("selections[%d] references stale candidate %q", i, selection.CandidateID) @@ -426,9 +568,50 @@ func (s BuilderState) Validate() error { return fmt.Errorf("selection %q projection mode %q is not advertised", selection.CandidateID, selection.ProjectionMode) } } + seenResolvedSelections := map[string]bool{} + for i, selection := range d.Selections { + occurrenceID := effectiveOccurrence(*d, s.Catalog, selection.OccurrenceID) + key := selection.CandidateID + "\x00" + occurrenceID + "\x00" + selection.ProjectionMode + if seenResolvedSelections[key] { + return fmt.Errorf("duplicate selection at selections[%d]", i) + } + seenResolvedSelections[key] = true + } + selectionKeys := map[string]bool{} + for _, selection := range d.Selections { + selectionKeys[PresentationKey(selection.CandidateID, effectiveOccurrence(*d, s.Catalog, selection.OccurrenceID), selection.ProjectionMode)] = true + } + for key, p := range d.Presentation { + if !selectionKeys[key] { + return fmt.Errorf("presentation %q does not resolve to a selection", key) + } + for _, selection := range d.Selections { + if PresentationKey(selection.CandidateID, effectiveOccurrence(*d, s.Catalog, selection.OccurrenceID), selection.ProjectionMode) != key { + continue + } + candidate := candidates[selection.CandidateID] + if p.Filter != nil && !candidate.Filterable { + return fmt.Errorf("UNSUPPORTED_FILTER: presentation %q", key) + } + if p.Chart != nil && !candidate.Chartable { + return fmt.Errorf("UNSUPPORTED_CHART: presentation %q", key) + } + } + } return nil } +func effectiveOccurrence(d Document, c CatalogSnapshot, authored string) string { + if authored != "" { + return authored + } + occ, err := d.Occurrences(c) + if err != nil || len(occ) == 0 { + return authored + } + return occ[len(occ)-1].ID +} + func (c CatalogSnapshot) nodeIndex() map[string]CatalogNode { out := map[string]CatalogNode{} for _, n := range c.Nodes { @@ -482,6 +665,49 @@ func (d Document) CanonicalJSON() ([]byte, error) { return json.Marshal(n) } +func (w Workspace) CanonicalJSON() ([]byte, error) { + if err := w.Validate(); err != nil { + return nil, err + } + n := w + n.Documents = append([]Document(nil), w.Documents...) + for i := range n.Documents { + n.Documents[i].APIVersion = "" + n.Documents[i].Selections = append([]Selection(nil), n.Documents[i].Selections...) + sort.SliceStable(n.Documents[i].Selections, func(a, b int) bool { + left := n.Documents[i].Selections[a] + right := n.Documents[i].Selections[b] + return left.CandidateID+"\x00"+left.OccurrenceID+"\x00"+left.ProjectionMode < right.CandidateID+"\x00"+right.OccurrenceID+"\x00"+right.ProjectionMode + }) + if n.Documents[i].RouteSteps == nil { + n.Documents[i].RouteSteps = []RouteStep{} + } + if n.Documents[i].Selections == nil { + n.Documents[i].Selections = []Selection{} + } + if n.Documents[i].Presentation == nil { + n.Documents[i].Presentation = map[string]Presentation{} + } + } + n.Tabs = append([]Tab(nil), w.Tabs...) + if n.Documents == nil { + n.Documents = []Document{} + } + if n.Tabs == nil { + n.Tabs = []Tab{} + } + return json.Marshal(n) +} + +func (w Workspace) Digest() (string, error) { + raw, err := w.CanonicalJSON() + if err != nil { + return "", err + } + sum := sha256.Sum256(raw) + return "sha256:" + hex.EncodeToString(sum[:]), nil +} + func (d Document) Digest() (string, error) { raw, err := d.CanonicalJSON() if err != nil { @@ -533,12 +759,12 @@ func (s BuilderState) CanonicalJSON() ([]byte, error) { if err := s.Validate(); err != nil { return nil, err } - var document []byte + var workspace []byte var err error - if s.Document == nil { - document = []byte("null") + if s.Workspace == nil { + workspace = []byte("null") } else { - document, err = s.Document.CanonicalJSON() + workspace, err = s.Workspace.CanonicalJSON() if err != nil { return nil, err } @@ -550,9 +776,9 @@ func (s BuilderState) CanonicalJSON() ([]byte, error) { return json.Marshal(struct { APIVersion string `json:"apiVersion"` Kind string `json:"kind"` - Document json.RawMessage `json:"document"` + Workspace json.RawMessage `json:"workspace"` Catalog json.RawMessage `json:"catalog"` - }{s.APIVersion, s.Kind, document, catalog}) + }{s.APIVersion, s.Kind, workspace, catalog}) } func (s BuilderState) Digest() (string, error) { @@ -565,7 +791,27 @@ func (s BuilderState) Digest() (string, error) { } func DecodeDocument(raw []byte) (Document, error) { - var out Document + var wire struct { + APIVersion string `json:"apiVersion,omitempty"` + Kind string `json:"kind"` + Output Output `json:"output"` + RootNodeID string `json:"rootNodeId"` + RouteSteps []RouteStep `json:"routeSteps"` + Selections []Selection `json:"selections"` + Presentation map[string]Presentation `json:"presentation"` + } + if err := strictDecode(raw, &wire); err != nil { + return Document{}, err + } + out := Document{APIVersion: wire.APIVersion, Kind: wire.Kind, Output: wire.Output, RootNodeID: wire.RootNodeID, RouteSteps: wire.RouteSteps, Selections: wire.Selections, Presentation: wire.Presentation} + if err := out.Validate(); err != nil { + return out, err + } + return out, nil +} + +func DecodeWorkspace(raw []byte) (Workspace, error) { + var out Workspace if err := strictDecode(raw, &out); err != nil { return out, err } diff --git a/internal/explorer/authoringv2/types_test.go b/internal/explorer/authoringv2/types_test.go index b5ef3f31..5d86f1bf 100644 --- a/internal/explorer/authoringv2/types_test.go +++ b/internal/explorer/authoringv2/types_test.go @@ -7,8 +7,8 @@ import ( func testCatalog() CatalogSnapshot { nodes := []CatalogNode{ - {ID: "patient", ResourceType: "Patient"}, - {ID: "encounter", ResourceType: "Encounter"}, + {ID: "patient", ResourceType: "Patient", RowRootEligible: true}, + {ID: "encounter", ResourceType: "Encounter", RowRootEligible: true}, } edges := []CatalogEdge{ {ID: "patient-encounter", FromNodeID: "patient", ToNodeID: "encounter", Label: "encounters"}, @@ -31,7 +31,7 @@ func testDocument() Document { APIVersion: APIVersion, Kind: Kind, Output: Output{ID: "out", Title: "Patients"}, RootNodeID: "patient", RouteSteps: []RouteStep{{EdgeID: "patient-encounter", OccurrenceID: "first"}, {EdgeID: "encounter-self", OccurrenceID: "second"}, {EdgeID: "encounter-self", OccurrenceID: "third"}}, Selections: []Selection{{CandidateID: "patient-id", OccurrenceID: "base", ProjectionMode: "SCALAR"}, {CandidateID: "encounter-id", OccurrenceID: "third", ProjectionMode: "SCALAR"}}, - Presentation: map[string]Presentation{"patient-id": {Label: "Patient ID"}}, + Presentation: map[string]Presentation{PresentationKey("patient-id", "base", "SCALAR"): {Label: "Patient ID"}}, } } @@ -89,8 +89,8 @@ func TestCanonicalizationAndDigestAreStableAcrossUnorderedCollections(t *testing first := testDocument() second := testDocument() first.Selections = []Selection{first.Selections[1], first.Selections[0]} - second.Presentation = map[string]Presentation{"patient-id": {Label: "Patient ID"}} - first.Presentation = map[string]Presentation{"patient-id": {Label: "Patient ID"}} + second.Presentation = map[string]Presentation{PresentationKey("patient-id", "base", "SCALAR"): {Label: "Patient ID"}} + first.Presentation = map[string]Presentation{PresentationKey("patient-id", "base", "SCALAR"): {Label: "Patient ID"}} a, err := first.CanonicalJSON() if err != nil { t.Fatal(err) diff --git a/internal/explorer/authoringv2/workspace_test.go b/internal/explorer/authoringv2/workspace_test.go new file mode 100644 index 00000000..d224b577 --- /dev/null +++ b/internal/explorer/authoringv2/workspace_test.go @@ -0,0 +1,119 @@ +package authoringv2 + +import ( + "fmt" + "strings" + "testing" +) + +func workspaceDocument(id string) Document { + return Document{Kind: Kind, Output: Output{ID: id, Title: id}, RootNodeID: "patient", RouteSteps: []RouteStep{}, Selections: []Selection{{CandidateID: "patient-id", OccurrenceID: RootOccurrenceID, ProjectionMode: "SCALAR"}}, Presentation: map[string]Presentation{}} +} + +func fiveTableWorkspace() Workspace { + w := Workspace{APIVersion: APIVersion, Kind: WorkspaceKind, Documents: []Document{}, Tabs: []Tab{}} + for i := 0; i < 5; i++ { + id := fmt.Sprintf("output-%d", i) + w.Documents = append(w.Documents, workspaceDocument(id)) + w.Tabs = append(w.Tabs, Tab{ID: "tab-" + id, Title: id, OutputID: id, Order: i, Visible: true}) + } + return w +} + +func TestWorkspaceValidatesFiveOrderedDocumentsAndTabs(t *testing.T) { + w := fiveTableWorkspace() + state := BuilderState{APIVersion: APIVersion, Kind: StateKind, Workspace: &w, Catalog: testCatalog()} + if err := state.Validate(); err != nil { + t.Fatal(err) + } + raw, err := w.CanonicalJSON() + if err != nil { + t.Fatal(err) + } + if strings.Contains(string(raw), `"apiVersion":"`+APIVersion+`","kind":"ExplorerBuilderDocument"`) { + t.Fatalf("documents must not carry apiVersion: %s", raw) + } +} + +func TestWorkspaceRejectsDuplicateAndMissingMappings(t *testing.T) { + tests := []struct { + name, code string + mutate func(*Workspace) + }{ + {"duplicate output", "DUPLICATE_OUTPUT_ID", func(w *Workspace) { w.Documents[1].Output.ID = w.Documents[0].Output.ID }}, + {"duplicate tab", "DUPLICATE_TAB_ID", func(w *Workspace) { w.Tabs[1].ID = w.Tabs[0].ID }}, + {"duplicate mapping", "INVALID_TAB_OUTPUT_MAPPING", func(w *Workspace) { w.Tabs[1].OutputID = w.Tabs[0].OutputID }}, + {"missing mapping", "INVALID_TAB_OUTPUT_MAPPING", func(w *Workspace) { w.Tabs = w.Tabs[:4] }}, + {"duplicate order", "INVALID_TAB_ORDER", func(w *Workspace) { w.Tabs[1].Order = 0 }}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + w := fiveTableWorkspace() + tt.mutate(&w) + if err := w.Validate(); err == nil || !strings.Contains(err.Error(), tt.code) { + t.Fatalf("error=%v, want %s", err, tt.code) + } + }) + } +} + +func TestDerivedOccurrencesStayOmittedAndAreUnique(t *testing.T) { + d := workspaceDocument("out") + d.RouteSteps = []RouteStep{{EdgeID: "patient-encounter"}, {EdgeID: "encounter-self"}} + occ, err := d.Occurrences(testCatalog()) + if err != nil { + t.Fatal(err) + } + if occ[1].ID != "step-1" || occ[2].ID != "step-2" || d.RouteSteps[0].OccurrenceID != "" { + t.Fatalf("occurrences=%#v document=%#v", occ, d) + } + d.RouteSteps[1].OccurrenceID = "step-1" + if err := d.Validate(); err == nil || !strings.Contains(err.Error(), "duplicate route occurrence") { + t.Fatalf("error=%v", err) + } +} + +func TestWorkspacePresentationCapabilitiesAndVisibleColumns(t *testing.T) { + w := fiveTableWorkspace() + catalog := testCatalog() + catalog.Candidates[0].Filterable = false + catalog.Candidates[0].Chartable = false + key := PresentationKey("patient-id", "base", "SCALAR") + w.Documents[0].Presentation[key] = Presentation{Filter: &FilterPresentation{Label: "ID"}} + state := BuilderState{APIVersion: APIVersion, Kind: StateKind, Workspace: &w, Catalog: catalog} + if err := state.Validate(); err == nil || !strings.Contains(err.Error(), "UNSUPPORTED_FILTER") { + t.Fatalf("error=%v", err) + } + w.Documents[0].Presentation[key] = Presentation{Chart: &ChartPresentation{Type: "bar"}} + if err := state.Validate(); err == nil || !strings.Contains(err.Error(), "UNSUPPORTED_CHART") { + t.Fatalf("error=%v", err) + } + hidden := false + w.Documents[0].Presentation[key] = Presentation{Visible: &hidden} + if err := state.Validate(); err != nil { + t.Fatalf("mutable Builder state rejected an all-hidden table: %v", err) + } + if err := w.ValidateForPublication(); err == nil || !strings.Contains(err.Error(), "NO_VISIBLE_COLUMNS") { + t.Fatalf("publication validation error=%v", err) + } +} + +func TestBuilderAllowsVisibleTableWithNoSelectionsUntilPublication(t *testing.T) { + w := fiveTableWorkspace() + w.Documents[0].Selections = []Selection{} + w.Documents[0].Presentation = map[string]Presentation{} + state := BuilderState{APIVersion: APIVersion, Kind: StateKind, Workspace: &w, Catalog: testCatalog()} + if err := state.Validate(); err != nil { + t.Fatalf("transitional empty table rejected by Builder: %v", err) + } + if err := w.ValidateForPublication(); err == nil || !strings.Contains(err.Error(), "NO_VISIBLE_COLUMNS: documents[0]") { + t.Fatalf("publication validation error=%v", err) + } +} + +func TestDecodeWorkspaceRejectsUnknownFields(t *testing.T) { + raw := `{"apiVersion":"` + APIVersion + `","kind":"` + WorkspaceKind + `","documents":[],"tabs":[],"recipe":{}}` + if _, err := DecodeWorkspace([]byte(raw)); err == nil || !strings.Contains(err.Error(), "unknown field") { + t.Fatalf("error=%v", err) + } +} diff --git a/internal/explorer/compilation.go b/internal/explorer/compilation.go index 72fea38c..8a437017 100644 --- a/internal/explorer/compilation.go +++ b/internal/explorer/compilation.go @@ -17,16 +17,18 @@ type Compilation struct { } type EmittedColumn struct { - EmissionID string `json:"emissionId"` - OutputID string `json:"outputId"` - NodeID string `json:"nodeId,omitempty"` - SelectionID string `json:"selectionId,omitempty"` - CandidateID string `json:"candidateId,omitempty"` - OccurrenceID string `json:"occurrenceId,omitempty"` - PublicColumn string `json:"publicColumn"` - LogicalType string `json:"logicalType"` - Filterable bool `json:"filterable"` - Chartable bool `json:"chartable"` + EmissionID string `json:"emissionId"` + OutputID string `json:"outputId"` + NodeID string `json:"nodeId,omitempty"` + SelectionID string `json:"selectionId,omitempty"` + CandidateID string `json:"candidateId,omitempty"` + OccurrenceID string `json:"occurrenceId,omitempty"` + ProjectionMode string `json:"projectionMode,omitempty"` + PublicColumn string `json:"publicColumn"` + Label string `json:"label,omitempty"` + LogicalType string `json:"logicalType"` + Filterable bool `json:"filterable"` + Chartable bool `json:"chartable"` } func OpaqueID(prefix, identity string) string { diff --git a/internal/explorer/compilation/translate.go b/internal/explorer/compilation/translate.go index 1d128d53..2f0bce5b 100644 --- a/internal/explorer/compilation/translate.go +++ b/internal/explorer/compilation/translate.go @@ -15,6 +15,7 @@ import ( "github.com/calypr/loom/internal/dataframe/recipe" "github.com/calypr/loom/internal/dataframe/spec" + "github.com/calypr/loom/internal/explorer" "github.com/calypr/loom/internal/explorer/authoringv2" "github.com/calypr/loom/internal/explorer/capability" ) @@ -57,22 +58,25 @@ func fail(stage, code, path, message string, details map[string]any, cause error // one candidate occurrence. It intentionally mirrors the useful subset of // explorer.EmittedColumn without importing the parent Explorer package. type EmittedColumn struct { - EmissionID string `json:"emissionId"` - OutputID string `json:"outputId"` - NodeID string `json:"nodeId,omitempty"` - SelectionID string `json:"selectionId,omitempty"` - CandidateID string `json:"candidateId,omitempty"` - OccurrenceID string `json:"occurrenceId,omitempty"` - PublicColumn string `json:"publicColumn"` - LogicalType string `json:"logicalType"` - Filterable bool `json:"filterable"` - Chartable bool `json:"chartable"` + EmissionID string `json:"emissionId"` + OutputID string `json:"outputId"` + NodeID string `json:"nodeId,omitempty"` + SelectionID string `json:"selectionId,omitempty"` + CandidateID string `json:"candidateId,omitempty"` + OccurrenceID string `json:"occurrenceId,omitempty"` + ProjectionMode string `json:"projectionMode"` + PublicColumn string `json:"publicColumn"` + LogicalType string `json:"logicalType"` + Filterable bool `json:"filterable"` + Chartable bool `json:"chartable"` } type IdentityMapping struct { - CandidateID string `json:"candidateId"` - OccurrenceID string `json:"occurrenceId"` - EmissionIDs []string `json:"emissionIds"` + OutputID string `json:"outputId"` + CandidateID string `json:"candidateId"` + OccurrenceID string `json:"occurrenceId"` + ProjectionMode string `json:"projectionMode"` + EmissionIDs []string `json:"emissionIds"` } // PresentationConfig is compiler-owned presentation data. The Builder may @@ -88,21 +92,14 @@ type PresentationColumn struct { Label string `json:"label"` Visible bool `json:"visible"` Order int `json:"order"` + Pinned bool `json:"pinned"` + FilterLabel string `json:"filterLabel,omitempty"` + ChartType string `json:"chartType,omitempty"` + ChartTitle string `json:"chartTitle,omitempty"` } -type OutputColumn struct { - EmissionID string `json:"emissionId"` - PublicColumn string `json:"publicColumn"` - CandidateID string `json:"candidateId"` - OccurrenceID string `json:"occurrenceId"` - LogicalType string `json:"logicalType"` - Filterable bool `json:"filterable"` - Chartable bool `json:"chartable"` -} -type OutputContract struct { - OutputID string `json:"outputId"` - Columns []OutputColumn `json:"columns"` -} +type OutputColumn = explorer.PublicOutputColumn +type OutputContract = explorer.PublicOutputContract // Result is a complete, deterministic native compilation artifact. type Result struct { @@ -114,6 +111,71 @@ type Result struct { OutputContract OutputContract } +type WorkspaceResult struct { + Bundle recipe.Bundle + RecipeDigest string + EmittedColumns []EmittedColumn + IdentityMappings []IdentityMapping + Presentations []PresentationConfig + OutputContracts []OutputContract + Workspace authoringv2.Workspace +} + +func CompileWorkspace(ctx context.Context, project, explorerID string, workspace authoringv2.Workspace, snapshot capability.Snapshot) (WorkspaceResult, error) { + wire := catalogFromCapability(snapshot, explorerID) + if err := (authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, Workspace: &workspace, Catalog: wire}).Validate(); err != nil { + return WorkspaceResult{}, fail("intent", "INVALID_AUTHORING_INTENT", "$.workspace", err.Error(), nil, err) + } + result := WorkspaceResult{Workspace: workspace, Bundle: recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "explorer_" + safeName(project) + "_" + safeName(explorerID), TranslationVersion: TranslationVersion}, EmittedColumns: []EmittedColumn{}, IdentityMappings: []IdentityMapping{}, Presentations: []PresentationConfig{}, OutputContracts: []OutputContract{}} + for i, document := range workspace.Documents { + compiled, err := Compile(ctx, project, explorerID, document, snapshot) + if err != nil { + return WorkspaceResult{}, fail("compile", "DOCUMENT_COMPILE_FAILED", fmt.Sprintf("$.workspace.documents[%d]", i), err.Error(), nil, err) + } + result.Bundle.Outputs = append(result.Bundle.Outputs, compiled.Bundle.Outputs...) + result.EmittedColumns = append(result.EmittedColumns, compiled.EmittedColumns...) + result.IdentityMappings = append(result.IdentityMappings, compiled.IdentityMappings...) + result.Presentations = append(result.Presentations, compiled.Presentation) + result.OutputContracts = append(result.OutputContracts, compiled.OutputContract) + } + if err := result.Bundle.Validate(); err != nil { + return WorkspaceResult{}, err + } + digest, err := result.Bundle.Digest() + if err != nil { + return WorkspaceResult{}, err + } + result.RecipeDigest = digest + return result, nil +} + +func catalogFromCapability(snapshot capability.Snapshot, explorerID string) authoringv2.CatalogSnapshot { + c := authoringv2.CatalogSnapshot{APIVersion: authoringv2.APIVersion, Kind: authoringv2.CatalogKind, Project: snapshot.Identity.Project, ExplorerID: explorerID, SourceGeneration: snapshot.Identity.Generation, AuthorizationScopeDigest: snapshot.Identity.AuthorizationScopeDigest, ResolvedSchemaDigest: snapshot.Identity.SchemaDigest, SnapshotToken: snapshot.Token, Complete: snapshot.Complete, RoutePolicy: authoringv2.RoutePolicy{Unbounded: snapshot.Policy.Route.MaxHops == 0, AllowRepeatedEdges: snapshot.Policy.Route.AllowsRepeatedEdges, AllowSelfLoops: snapshot.Policy.Route.AllowsSelfLoops}} + if snapshot.Policy.Route.MaxHops > 0 { + max := snapshot.Policy.Route.MaxHops + c.RoutePolicy.MaxHops = &max + } + for _, n := range snapshot.Nodes { + count := n.DocumentCount + c.Nodes = append(c.Nodes, authoringv2.CatalogNode{ID: n.ID, ResourceType: n.ResourceType, RowRootEligible: n.RowRootEligible, RowGrain: n.RowGrain, Populated: n.Populated, DocumentCount: &count}) + } + for _, e := range snapshot.Edges { + c.Edges = append(c.Edges, authoringv2.CatalogEdge{ID: e.ID, FromNodeID: e.FromNodeID, ToNodeID: e.ToNodeID, Label: e.Label, Populated: e.ObservedEdgeCount > 0}) + } + for _, candidate := range snapshot.Candidates { + modes := make([]string, len(candidate.ProjectionModes)) + for i, mode := range candidate.ProjectionModes { + modes[i] = wireProjectionMode(mode) + } + defaultMode := "" + if len(modes) > 0 { + defaultMode = modes[0] + } + c.Candidates = append(c.Candidates, authoringv2.CatalogCandidate{ID: candidate.ID, NodeID: candidate.NodeID, Label: candidate.Label, LogicalType: candidate.LogicalType, Repeated: candidate.Cardinality != "scalar", Filterable: supportsOperation(candidate.SupportedOperations, capability.OperationFilter), Chartable: supportsOperation(candidate.SupportedOperations, capability.OperationChart), ProjectionModes: modes, DefaultProjectionMode: defaultMode, Populated: candidate.Populated}) + } + return c +} + // Compilation is a descriptive alias for callers that use the domain term // rather than the translation verb. type Compilation = Result @@ -165,7 +227,7 @@ func Compile(ctx context.Context, project, explorerID string, document authoring occurrenceID = occurrences[len(occurrences)-1].ID } candidate, _ := snapshot.Candidate(selection.CandidateID) - key := selection.CandidateID + "\x00" + occurrenceID + key := selection.CandidateID + "\x00" + occurrenceID + "\x00" + strings.ToUpper(selection.ProjectionMode) if seenPairs[key] { return Result{}, fail("intent", "DUPLICATE_SELECTION", fmt.Sprintf("$.selections[%d]", i), "candidate occurrence is selected more than once", map[string]any{"candidateId": selection.CandidateID, "occurrenceId": occurrenceID}, nil) } @@ -187,13 +249,21 @@ func Compile(ctx context.Context, project, explorerID string, document authoring byPair := map[string]*IdentityMapping{} fieldsByOccurrence := map[string][]recipe.Field{} for _, a := range assignments { - public := generatedID("c_", a.Candidate.ID+"\x00"+a.OccurrenceID) - emission := generatedID("em_", document.Output.ID+"\x00"+a.OccurrenceID+"\x00"+a.Candidate.ID) - column := EmittedColumn{EmissionID: emission, OutputID: document.Output.ID, NodeID: a.Candidate.NodeID, SelectionID: a.Candidate.ID, CandidateID: a.Candidate.ID, OccurrenceID: a.OccurrenceID, PublicColumn: public, LogicalType: a.Candidate.LogicalType, Filterable: supportsOperation(a.Candidate.SupportedOperations, capability.OperationFilter), Chartable: supportsOperation(a.Candidate.SupportedOperations, capability.OperationChart)} + fieldName := generatedID("c_", a.Candidate.ID+"\x00"+a.OccurrenceID+"\x00"+a.Selection.ProjectionMode) + public := fieldName + if occurrence := occurrenceIndex(occurrences, a.OccurrenceID); occurrence > 0 { + aliases := make([]string, occurrence) + for i := range aliases { + aliases[i] = routeAlias(i) + } + public = strings.Join(aliases, "__") + "__" + fieldName + } + emission := generatedID("em_", document.Output.ID+"\x00"+a.OccurrenceID+"\x00"+a.Candidate.ID+"\x00"+a.Selection.ProjectionMode) + column := EmittedColumn{EmissionID: emission, OutputID: document.Output.ID, NodeID: a.Candidate.NodeID, SelectionID: a.Candidate.ID, CandidateID: a.Candidate.ID, OccurrenceID: a.OccurrenceID, ProjectionMode: a.Selection.ProjectionMode, PublicColumn: public, LogicalType: a.Candidate.LogicalType, Filterable: supportsOperation(a.Candidate.SupportedOperations, capability.OperationFilter), Chartable: supportsOperation(a.Candidate.SupportedOperations, capability.OperationChart)} emitted = append(emitted, column) - pair := a.Candidate.ID + "\x00" + a.OccurrenceID + pair := a.Candidate.ID + "\x00" + a.OccurrenceID + "\x00" + a.Selection.ProjectionMode if byPair[pair] == nil { - mappings = append(mappings, IdentityMapping{CandidateID: a.Candidate.ID, OccurrenceID: a.OccurrenceID}) + mappings = append(mappings, IdentityMapping{OutputID: document.Output.ID, CandidateID: a.Candidate.ID, OccurrenceID: a.OccurrenceID, ProjectionMode: a.Selection.ProjectionMode}) byPair[pair] = &mappings[len(mappings)-1] } byPair[pair].EmissionIDs = append(byPair[pair].EmissionIDs, emission) @@ -202,7 +272,7 @@ func Compile(ctx context.Context, project, explorerID string, document authoring alias = routeAlias(idx - 1) } fieldPath := strings.TrimPrefix(strings.TrimSpace(a.Candidate.FieldPath), "root.") - fieldsByOccurrence[a.OccurrenceID] = append(fieldsByOccurrence[a.OccurrenceID], recipe.Field{Name: public, FieldRef: a.Candidate.FieldPath, Expr: recipe.Expression{Select: alias + "." + fieldPath}, ValueMode: projectionValueMode(a.Selection.ProjectionMode)}) + fieldsByOccurrence[a.OccurrenceID] = append(fieldsByOccurrence[a.OccurrenceID], recipe.Field{Name: fieldName, FieldRef: a.Candidate.FieldPath, Expr: recipe.Expression{Select: alias + "." + fieldPath}, ValueMode: projectionValueMode(a.Selection.ProjectionMode)}) } output := recipe.Output{Name: document.Output.ID, RootResourceType: root.ResourceType, RowGrain: string(rowGrain), Fields: fieldsByOccurrence[authoringv2.RootOccurrenceID]} @@ -230,13 +300,13 @@ func Compile(ctx context.Context, project, explorerID string, document authoring if err != nil { return Result{}, fail("lower", "RECIPE_DIGEST_FAILED", "$.recipe", "recipe digest could not be calculated", nil, err) } - presentation, err := makePresentation(document, emitted) + presentation, err := makePresentation(document, emitted, snapshot) if err != nil { return Result{}, err } contract := OutputContract{OutputID: document.Output.ID} for _, c := range emitted { - contract.Columns = append(contract.Columns, OutputColumn{EmissionID: c.EmissionID, PublicColumn: c.PublicColumn, CandidateID: c.CandidateID, OccurrenceID: c.OccurrenceID, LogicalType: c.LogicalType, Filterable: c.Filterable, Chartable: c.Chartable}) + contract.Columns = append(contract.Columns, OutputColumn{EmissionID: c.EmissionID, PublicColumn: c.PublicColumn, CandidateID: c.CandidateID, OccurrenceID: c.OccurrenceID, ProjectionMode: c.ProjectionMode, Label: presentation.Columns[len(contract.Columns)].Label, LogicalType: c.LogicalType, Filterable: c.Filterable, Chartable: c.Chartable}) } return Result{Bundle: bundle, RecipeDigest: digest, EmittedColumns: emitted, IdentityMappings: mappings, Presentation: presentation, OutputContract: contract}, nil } @@ -368,7 +438,7 @@ func validateSelections(d authoringv2.Document, s capability.Snapshot, occ []occ } allowed := false for _, m := range c.ProjectionModes { - if strings.EqualFold(string(m), sel.ProjectionMode) { + if strings.EqualFold(wireProjectionMode(m), sel.ProjectionMode) || strings.EqualFold(string(m), sel.ProjectionMode) { allowed = true break } @@ -401,7 +471,7 @@ func projectionValueMode(mode string) recipe.ValueMode { switch strings.ToUpper(strings.TrimSpace(mode)) { case string(capability.ProjectionFirst): return recipe.ValueModeFirst - case string(capability.ProjectionArray): + case "ALL", string(capability.ProjectionArray): return recipe.ValueModeAll case string(capability.ProjectionDistinctArray): return recipe.ValueModeDistinct @@ -410,6 +480,17 @@ func projectionValueMode(mode string) recipe.ValueMode { } } +func wireProjectionMode(mode capability.ProjectionMode) string { + switch mode { + case capability.ProjectionScalar: + return "VALUE" + case capability.ProjectionArray, capability.ProjectionDistinctArray: + return "ALL" + default: + return string(mode) + } +} + var namePattern = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*$`) func recipeName(label, id string) string { @@ -441,6 +522,16 @@ func shortHash(s string) string { return hex.EncodeToString(sum[:])[:16] } func generatedID(prefix, s string) string { return prefix + shortHash(s) } + +func firstNonEmpty(values ...string) string { + for _, value := range values { + if value = strings.TrimSpace(value); value != "" { + return value + } + } + return "" +} + func contextErr(ctx context.Context) error { if ctx == nil { return nil @@ -453,27 +544,22 @@ func contextErr(ctx context.Context) error { } } -func makePresentation(d authoringv2.Document, emitted []EmittedColumn) (PresentationConfig, error) { - result := PresentationConfig{OutputID: d.Output.ID, Title: d.Output.Title, Columns: make([]PresentationColumn, 0, len(emitted))} - byKey := map[string][]int{} - for i, c := range emitted { - byKey[c.EmissionID] = append(byKey[c.EmissionID], i) - byKey[c.CandidateID] = append(byKey[c.CandidateID], i) - byKey[c.CandidateID+"\x00"+c.OccurrenceID] = append(byKey[c.CandidateID+"\x00"+c.OccurrenceID], i) +func makePresentation(d authoringv2.Document, emitted []EmittedColumn, snapshot capability.Snapshot) (PresentationConfig, error) { + candidates := make(map[string]capability.Candidate, len(snapshot.Candidates)) + for _, candidate := range snapshot.Candidates { + candidates[candidate.ID] = candidate } + result := PresentationConfig{OutputID: d.Output.ID, Title: d.Output.Title, Columns: make([]PresentationColumn, 0, len(emitted))} for i, c := range emitted { p := authoringv2.Presentation{} - if raw, ok := d.Presentation[c.EmissionID]; ok { - p = raw - } else if raw, ok := d.Presentation[c.CandidateID+"\x00"+c.OccurrenceID]; ok { - p = raw - } else if raw, ok := d.Presentation[c.CandidateID]; ok { - if len(byKey[c.CandidateID]) > 1 { - return PresentationConfig{}, fail("presentation", "AMBIGUOUS_PRESENTATION", "$.presentation."+c.CandidateID, "presentation key matches multiple candidate occurrences", nil, nil) - } + key := authoringv2.PresentationKey(c.CandidateID, c.OccurrenceID, c.ProjectionMode) + if raw, ok := d.Presentation[key]; ok { p = raw } label := c.PublicColumn + if candidate, ok := candidates[c.CandidateID]; ok { + label = firstNonEmpty(candidate.Label, candidate.FieldPath, label) + } if strings.TrimSpace(p.Label) != "" { label = p.Label } @@ -485,12 +571,22 @@ func makePresentation(d authoringv2.Document, emitted []EmittedColumn) (Presenta if p.Order != nil { order = *p.Order } - result.Columns = append(result.Columns, PresentationColumn{EmissionID: c.EmissionID, PublicColumn: c.PublicColumn, Label: label, Visible: visible, Order: order}) + column := PresentationColumn{EmissionID: c.EmissionID, PublicColumn: c.PublicColumn, Label: label, Visible: visible, Order: order} + if p.Table != nil { + column.Pinned = p.Table.Pinned + } + if p.Filter != nil { + column.FilterLabel = p.Filter.Label + } + if p.Chart != nil { + column.ChartType, column.ChartTitle = p.Chart.Type, p.Chart.Title + } + result.Columns = append(result.Columns, column) } for key := range d.Presentation { found := false for _, c := range emitted { - if key == c.EmissionID || key == c.CandidateID || key == c.CandidateID+"\x00"+c.OccurrenceID { + if key == authoringv2.PresentationKey(c.CandidateID, c.OccurrenceID, c.ProjectionMode) { found = true break } diff --git a/internal/explorer/compilation/translate_test.go b/internal/explorer/compilation/translate_test.go index ddf908b7..341ede32 100644 --- a/internal/explorer/compilation/translate_test.go +++ b/internal/explorer/compilation/translate_test.go @@ -17,7 +17,7 @@ func fixtureSnapshot() capability.Snapshot { nodes := []capability.Node{{ID: "n_patient", ResourceType: "Patient", RowRootEligible: true, RowGrain: "patient"}, {ID: "n_encounter", ResourceType: "Encounter", RowRootEligible: true, RowGrain: "resource"}} edges := []capability.Edge{{ID: "e_encounter", FromNodeID: "n_patient", ToNodeID: "n_encounter", Label: "encounters"}, {ID: "e_self", FromNodeID: "n_encounter", ToNodeID: "n_encounter", Label: "revisits"}} ops := []capability.Operation{capability.OperationSelect, capability.OperationFilter, capability.OperationChart} - candidates := []capability.Candidate{{ID: "c_patient_id", NodeID: "n_patient", ResourceType: "Patient", FieldPath: "id", LogicalType: "string", ProjectionModes: []capability.ProjectionMode{capability.ProjectionScalar}, SupportedOperations: ops}, {ID: "c_encounter_code", NodeID: "n_encounter", ResourceType: "Encounter", FieldPath: "code.coding[].code", LogicalType: "string", ProjectionModes: []capability.ProjectionMode{capability.ProjectionFirst, capability.ProjectionArray, capability.ProjectionDistinctArray}, SupportedOperations: ops}} + candidates := []capability.Candidate{{ID: "c_patient_id", NodeID: "n_patient", ResourceType: "Patient", FieldPath: "id", Label: "Patient.id", LogicalType: "string", ProjectionModes: []capability.ProjectionMode{capability.ProjectionScalar}, SupportedOperations: ops}, {ID: "c_encounter_code", NodeID: "n_encounter", ResourceType: "Encounter", FieldPath: "code.coding[].code", Label: "Encounter.code.coding[].code", LogicalType: "string", ProjectionModes: []capability.ProjectionMode{capability.ProjectionFirst, capability.ProjectionArray, capability.ProjectionDistinctArray}, SupportedOperations: ops}} return capability.NewSnapshot(identity, policy, capability.StatusReady, true, false, nodes, edges, candidates, nil) } @@ -55,7 +55,7 @@ func BenchmarkCompileRepresentativeBuilderState(b *testing.B) { } func fixtureDocument() authoringv2.Document { - return authoringv2.Document{APIVersion: authoringv2.APIVersion, Kind: authoringv2.Kind, Output: authoringv2.Output{ID: "patient_output", Title: "Patients"}, RootNodeID: "n_patient", RouteSteps: []authoringv2.RouteStep{{EdgeID: "e_encounter", OccurrenceID: "encounter"}, {EdgeID: "e_self", OccurrenceID: "encounter_again"}}, Selections: []authoringv2.Selection{{CandidateID: "c_patient_id", OccurrenceID: "base", ProjectionMode: "SCALAR"}, {CandidateID: "c_encounter_code", OccurrenceID: "encounter_again", ProjectionMode: "DISTINCT_ARRAY"}}, Presentation: map[string]authoringv2.Presentation{"c_patient_id": {Label: "Patient ID"}}} + return authoringv2.Document{APIVersion: authoringv2.APIVersion, Kind: authoringv2.Kind, Output: authoringv2.Output{ID: "patient_output", Title: "Patients"}, RootNodeID: "n_patient", RouteSteps: []authoringv2.RouteStep{{EdgeID: "e_encounter", OccurrenceID: "encounter"}, {EdgeID: "e_self", OccurrenceID: "encounter_again"}}, Selections: []authoringv2.Selection{{CandidateID: "c_patient_id", OccurrenceID: "base", ProjectionMode: "SCALAR"}, {CandidateID: "c_encounter_code", OccurrenceID: "encounter_again", ProjectionMode: "DISTINCT_ARRAY"}}, Presentation: map[string]authoringv2.Presentation{authoringv2.PresentationKey("c_patient_id", "base", "SCALAR"): {Label: "Patient ID"}}} } func TestCompileNativeV2BuildsNestedRouteAndStableColumns(t *testing.T) { @@ -73,6 +73,10 @@ func TestCompileNativeV2BuildsNestedRouteAndStableColumns(t *testing.T) { if len(result.EmittedColumns) != 2 || result.EmittedColumns[0].EmissionID == result.EmittedColumns[1].EmissionID { t.Fatalf("emissions=%#v", result.EmittedColumns) } + nestedField := result.Bundle.Outputs[0].Traversals[0].Traversals[0].Fields[0].Name + if got, want := result.EmittedColumns[1].PublicColumn, "route_0__route_1__"+nestedField; got != want { + t.Fatalf("nested public column=%q, want engine-flattened name %q", got, want) + } if result.Presentation.Columns[0].Label != "Patient ID" || !result.Presentation.Columns[0].Visible { t.Fatalf("presentation=%#v", result.Presentation) } @@ -82,6 +86,21 @@ func TestCompileNativeV2BuildsNestedRouteAndStableColumns(t *testing.T) { } } +func TestCompileNativeV2DefaultsPresentationToCandidateLabel(t *testing.T) { + document := fixtureDocument() + document.Presentation = map[string]authoringv2.Presentation{} + result, err := Compile(context.Background(), "project-a", "explorer-a", document, fixtureSnapshot()) + if err != nil { + t.Fatal(err) + } + if got, want := result.Presentation.Columns[0].Label, "Patient.id"; got != want { + t.Fatalf("default presentation label=%q, want candidate label %q", got, want) + } + if got, want := result.Presentation.Columns[1].Label, "Encounter.code.coding[].code"; got != want { + t.Fatalf("nested default presentation label=%q, want candidate label %q", got, want) + } +} + func TestCompileAllowsRepeatedSelfLoopAndLongFiniteRoutes(t *testing.T) { snapshot := fixtureSnapshot() document := fixtureDocument() diff --git a/internal/explorer/compilation/workspace_test.go b/internal/explorer/compilation/workspace_test.go new file mode 100644 index 00000000..8cbc2169 --- /dev/null +++ b/internal/explorer/compilation/workspace_test.go @@ -0,0 +1,34 @@ +package compilation + +import ( + "context" + "fmt" + "testing" + + "github.com/calypr/loom/internal/explorer/authoringv2" +) + +func TestCompileWorkspaceProducesOneArtifactWithFiveOutputs(t *testing.T) { + workspace := authoringv2.Workspace{APIVersion: authoringv2.APIVersion, Kind: authoringv2.WorkspaceKind, Documents: []authoringv2.Document{}, Tabs: []authoringv2.Tab{}} + for i := 0; i < 5; i++ { + id := fmt.Sprintf("output_%d", i) + workspace.Documents = append(workspace.Documents, authoringv2.Document{Kind: authoringv2.Kind, Output: authoringv2.Output{ID: id, Title: id}, RootNodeID: "n_patient", RouteSteps: []authoringv2.RouteStep{}, Selections: []authoringv2.Selection{{CandidateID: "c_patient_id", OccurrenceID: "base", ProjectionMode: "VALUE"}}, Presentation: map[string]authoringv2.Presentation{}}) + workspace.Tabs = append(workspace.Tabs, authoringv2.Tab{ID: fmt.Sprintf("tab-%d", i), Title: id, OutputID: id, Order: i, Visible: true}) + } + result, err := CompileWorkspace(context.Background(), "project-a", "explorer-a", workspace, fixtureSnapshot()) + if err != nil { + t.Fatal(err) + } + if len(result.Bundle.Outputs) != 5 || len(result.EmittedColumns) != 5 || len(result.OutputContracts) != 5 { + t.Fatalf("outputs=%d emissions=%d contracts=%d", len(result.Bundle.Outputs), len(result.EmittedColumns), len(result.OutputContracts)) + } + for i, emission := range result.EmittedColumns { + if emission.OutputID != fmt.Sprintf("output_%d", i) || emission.ProjectionMode != "VALUE" { + t.Fatalf("emission[%d]=%#v", i, emission) + } + contract := result.OutputContracts[i] + if contract.OutputID != emission.OutputID || len(contract.Columns) != 1 || contract.Columns[0].ProjectionMode != emission.ProjectionMode || contract.Columns[0].Label == "" { + t.Fatalf("contract[%d]=%#v emission=%#v", i, contract, emission) + } + } +} diff --git a/internal/explorer/compilation_receipt.go b/internal/explorer/compilation_receipt.go index ce14c078..dc7716d3 100644 --- a/internal/explorer/compilation_receipt.go +++ b/internal/explorer/compilation_receipt.go @@ -20,10 +20,10 @@ import ( const ( // CompilationReceiptFormatVersion changes when the persisted receipt shape // or its execution invariants change incompatibly. - CompilationReceiptFormatVersion = 1 + CompilationReceiptFormatVersion = 2 // CompilationReceiptCompilerContractVersion changes when compilation // semantics change in a way that can alter a resolved receipt. - CompilationReceiptCompilerContractVersion = "loom.explorer.compiler/v2" + CompilationReceiptCompilerContractVersion = "loom.explorer.compiler/v4" // Short aliases make the current contract convenient for repositories and // callers that do not need to distinguish the receipt prefix. @@ -84,9 +84,11 @@ type CompilationReceipt struct { } type IdentityMapping struct { - CandidateID string `json:"candidateId"` - OccurrenceID string `json:"occurrenceId"` - EmissionIDs []string `json:"emissionIds"` + OutputID string `json:"outputId,omitempty"` + CandidateID string `json:"candidateId"` + OccurrenceID string `json:"occurrenceId"` + ProjectionMode string `json:"projectionMode,omitempty"` + EmissionIDs []string `json:"emissionIds"` } // CompilationWarning is the deterministic, request-independent diagnostic @@ -250,7 +252,7 @@ func (r CompilationReceipt) Validate() error { if r.ResolvedRecipeDigest != resolvedDigest { return fmt.Errorf("receipt resolved recipe digest mismatch: got %q want %q", r.ResolvedRecipeDigest, resolvedDigest) } - contract, contractErr := DecodePublicOutputContract(r.PublicOutputContract) + contract, contractErr := DecodePublicOutputContracts(r.PublicOutputContract) if contractErr != nil { return contractErr } diff --git a/internal/explorer/compilation_receipt_test.go b/internal/explorer/compilation_receipt_test.go index eaae127b..bf2de860 100644 --- a/internal/explorer/compilation_receipt_test.go +++ b/internal/explorer/compilation_receipt_test.go @@ -25,7 +25,7 @@ func testReceipt() CompilationReceipt { NormalizedBundle: json.RawMessage(`{"documents":[]}`), Bundle: recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "receipt-test", TranslationVersion: "test", Outputs: []recipe.Output{{Name: "out", RootResourceType: "Patient", RowGrain: "patient"}}}, CompiledConfig: json.RawMessage(`{"views":[]}`), - PublicOutputContract: json.RawMessage(`{"outputId":"out","columns":[]}`), + PublicOutputContract: json.RawMessage(`{"outputs":[{"outputId":"out","columns":[]}]}`), Warnings: []CompilationWarning{{Code: "EMPTY_OUTPUT", Message: "output has no selected fields"}}, } r.ResolvedRecipeDigest, _ = r.Bundle.Digest() diff --git a/internal/explorer/config_v2.go b/internal/explorer/config_v2.go index d3f71fb5..7c8a8b80 100644 --- a/internal/explorer/config_v2.go +++ b/internal/explorer/config_v2.go @@ -68,6 +68,7 @@ type ConfigColumn struct { Column string `json:"column"` Label string `json:"label,omitempty"` Visible bool `json:"visible"` + Pinned bool `json:"pinned,omitempty"` } type ConfigFilter struct { Column string `json:"column"` diff --git a/internal/explorer/output_contract.go b/internal/explorer/output_contract.go index 042da3e4..dd639a9c 100644 --- a/internal/explorer/output_contract.go +++ b/internal/explorer/output_contract.go @@ -11,78 +11,141 @@ import ( "github.com/calypr/loom/internal/dataframe/recipe" ) -// PublicOutputContract is the current, transport-neutral public output -// contract persisted inside a compilation receipt. It describes the one -// output selected by the V2 Builder; executable selectors and physical names -// are deliberately absent. +// PublicOutputContracts is the current, transport-neutral public output +// contract persisted inside a compilation receipt. Outputs retain workspace +// order; executable selectors and physical names are deliberately absent. +type PublicOutputContracts struct { + Outputs []PublicOutputContract `json:"outputs"` +} + +// PublicOutputContract describes one compiled workspace output. type PublicOutputContract struct { OutputID string `json:"outputId"` Columns []PublicOutputColumn `json:"columns"` } type PublicOutputColumn struct { - EmissionID string `json:"emissionId"` - PublicColumn string `json:"publicColumn"` - CandidateID string `json:"candidateId,omitempty"` - OccurrenceID string `json:"occurrenceId,omitempty"` - LogicalType string `json:"logicalType"` - Filterable bool `json:"filterable"` - Chartable bool `json:"chartable"` + EmissionID string `json:"emissionId"` + PublicColumn string `json:"publicColumn"` + CandidateID string `json:"candidateId"` + OccurrenceID string `json:"occurrenceId"` + ProjectionMode string `json:"projectionMode"` + Label string `json:"label"` + LogicalType string `json:"logicalType"` + Filterable bool `json:"filterable"` + Chartable bool `json:"chartable"` } -// DecodePublicOutputContract strictly decodes the current contract shape. +// DecodePublicOutputContracts strictly decodes the current contract shape. // Null columns are accepted because an empty V2 selection is a valid mutable // editor state and the current compiler serializes its nil slice as null. -// Missing columns, unknown fields, duplicate keys, and trailing JSON are not -// accepted. -func DecodePublicOutputContract(raw json.RawMessage) (PublicOutputContract, error) { +// Missing fields, unknown fields, duplicate keys, and trailing JSON are not accepted. +func DecodePublicOutputContracts(raw json.RawMessage) (PublicOutputContracts, error) { if len(bytes.TrimSpace(raw)) == 0 || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { - return PublicOutputContract{}, invalidOutputContract("contract is required") + return PublicOutputContracts{}, invalidOutputContract("contract is required") } if err := rejectDuplicateJSONKeys(raw); err != nil { - return PublicOutputContract{}, invalidOutputContract("duplicate or malformed JSON key: %v", err) + return PublicOutputContracts{}, invalidOutputContract("duplicate or malformed JSON key: %v", err) } var fields map[string]json.RawMessage if err := json.Unmarshal(raw, &fields); err != nil || fields == nil { if err == nil { err = errors.New("contract must be a JSON object") } - return PublicOutputContract{}, invalidOutputContract("malformed JSON object: %v", err) + return PublicOutputContracts{}, invalidOutputContract("malformed JSON object: %v", err) + } + if _, ok := fields["outputs"]; !ok { + return PublicOutputContracts{}, invalidOutputContract("outputs is required") } - if _, ok := fields["outputId"]; !ok { - return PublicOutputContract{}, invalidOutputContract("outputId is required") + if bytes.Equal(bytes.TrimSpace(fields["outputs"]), []byte("null")) { + return PublicOutputContracts{}, invalidOutputContract("outputs must be an array") } - if _, ok := fields["columns"]; !ok { - return PublicOutputContract{}, invalidOutputContract("columns is required") + var outputFields []map[string]json.RawMessage + if err := json.Unmarshal(fields["outputs"], &outputFields); err != nil { + return PublicOutputContracts{}, invalidOutputContract("outputs must be an array: %v", err) + } + for i, output := range outputFields { + if _, ok := output["outputId"]; !ok { + return PublicOutputContracts{}, invalidOutputContract("outputs[%d].outputId is required", i) + } + if _, ok := output["columns"]; !ok { + return PublicOutputContracts{}, invalidOutputContract("outputs[%d].columns is required", i) + } } - var contract PublicOutputContract + var contracts PublicOutputContracts decoder := json.NewDecoder(bytes.NewReader(raw)) decoder.DisallowUnknownFields() - if err := decoder.Decode(&contract); err != nil { - return PublicOutputContract{}, invalidOutputContract("decode failed: %v", err) + if err := decoder.Decode(&contracts); err != nil { + return PublicOutputContracts{}, invalidOutputContract("decode failed: %v", err) } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { err = errors.New("trailing JSON value") } - return PublicOutputContract{}, invalidOutputContract("trailing JSON: %v", err) + return PublicOutputContracts{}, invalidOutputContract("trailing JSON: %v", err) + } + seen := make(map[string]struct{}, len(contracts.Outputs)) + for outputIndex, contract := range contracts.Outputs { + if strings.TrimSpace(contract.OutputID) == "" { + return PublicOutputContracts{}, invalidOutputContract("outputs[%d].outputId is required", outputIndex) + } + if _, exists := seen[contract.OutputID]; exists { + return PublicOutputContracts{}, invalidOutputContract("duplicate outputId %q", contract.OutputID) + } + seen[contract.OutputID] = struct{}{} + for columnIndex, column := range contract.Columns { + path := fmt.Sprintf("outputs[%d].columns[%d]", outputIndex, columnIndex) + for _, field := range []struct{ name, value string }{ + {"emissionId", column.EmissionID}, {"publicColumn", column.PublicColumn}, + {"candidateId", column.CandidateID}, {"occurrenceId", column.OccurrenceID}, + {"projectionMode", column.ProjectionMode}, {"label", column.Label}, + {"logicalType", column.LogicalType}, + } { + if strings.TrimSpace(field.value) == "" { + return PublicOutputContracts{}, invalidOutputContract("%s.%s is required", path, field.name) + } + } + } } - if strings.TrimSpace(contract.OutputID) == "" { - return PublicOutputContract{}, invalidOutputContract("outputId is required") + return contracts, nil +} + +func (c PublicOutputContracts) Output(outputID string) (PublicOutputContract, bool) { + for _, output := range c.Outputs { + if output.OutputID == outputID { + return output, true + } + } + return PublicOutputContract{}, false +} + +// ValidateAgainst proves that the ordered contract set exactly matches the +// recipe outputs and each output's ordered emitted columns. +func (c PublicOutputContracts) ValidateAgainst(bundle recipe.Bundle, emitted []EmittedColumn) error { + if len(c.Outputs) != len(bundle.Outputs) { + return invalidOutputContract("output count %d does not match recipe output count %d", len(c.Outputs), len(bundle.Outputs)) } - for i, column := range contract.Columns { - if strings.TrimSpace(column.EmissionID) == "" { - return PublicOutputContract{}, invalidOutputContract("columns[%d].emissionId is required", i) + emittedByOutput := make(map[string][]EmittedColumn, len(c.Outputs)) + for i, column := range emitted { + if strings.TrimSpace(column.OutputID) == "" { + return invalidOutputContract("emittedColumns[%d].outputId is required", i) } - if strings.TrimSpace(column.PublicColumn) == "" { - return PublicOutputContract{}, invalidOutputContract("columns[%d].publicColumn is required", i) + emittedByOutput[column.OutputID] = append(emittedByOutput[column.OutputID], column) + } + for i, contract := range c.Outputs { + if contract.OutputID != bundle.Outputs[i].Name { + return invalidOutputContract("outputs[%d].outputId %q does not match recipe output %q", i, contract.OutputID, bundle.Outputs[i].Name) } - if strings.TrimSpace(column.LogicalType) == "" { - return PublicOutputContract{}, invalidOutputContract("columns[%d].logicalType is required", i) + if err := contract.ValidateAgainst(bundle, emittedByOutput[contract.OutputID]); err != nil { + return err } + delete(emittedByOutput, contract.OutputID) } - return contract, nil + for outputID := range emittedByOutput { + return invalidOutputContract("emitted columns reference unknown output %q", outputID) + } + return nil } // ValidateAgainst proves that the typed public contract is exactly the @@ -124,7 +187,7 @@ func (c PublicOutputContract) ValidateAgainst(bundle recipe.Bundle, emitted []Em seenEmission[column.EmissionID] = struct{}{} seenPublic[column.PublicColumn] = struct{}{} actual := c.Columns[i] - if actual.EmissionID != column.EmissionID || actual.PublicColumn != column.PublicColumn || actual.CandidateID != column.CandidateID || actual.OccurrenceID != column.OccurrenceID || actual.LogicalType != column.LogicalType || actual.Filterable != column.Filterable || actual.Chartable != column.Chartable { + if actual.EmissionID != column.EmissionID || actual.PublicColumn != column.PublicColumn || actual.CandidateID != column.CandidateID || actual.OccurrenceID != column.OccurrenceID || actual.ProjectionMode != column.ProjectionMode || actual.Label != column.Label || actual.LogicalType != column.LogicalType || actual.Filterable != column.Filterable || actual.Chartable != column.Chartable { return invalidOutputContract("columns[%d] does not match emittedColumns[%d]", i, i) } } diff --git a/internal/explorer/output_contract_test.go b/internal/explorer/output_contract_test.go index 9340181c..fb8ab83a 100644 --- a/internal/explorer/output_contract_test.go +++ b/internal/explorer/output_contract_test.go @@ -8,60 +8,83 @@ import ( "github.com/calypr/loom/internal/dataframe/recipe" ) -func contractFixture() (recipe.Bundle, []EmittedColumn, PublicOutputContract) { - bundle := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "contract-test", TranslationVersion: "test", Outputs: []recipe.Output{{Name: "patients", RootResourceType: "Patient", RowGrain: "patient"}}} +func contractFixture() (recipe.Bundle, []EmittedColumn, PublicOutputContracts) { + bundle := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "contract-test", TranslationVersion: "test", Outputs: []recipe.Output{{Name: "patients", RootResourceType: "Patient", RowGrain: "patient"}, {Name: "specimens", RootResourceType: "Specimen", RowGrain: "specimen"}}} emitted := []EmittedColumn{ - {EmissionID: "em_id", OutputID: "patients", CandidateID: "c_id", OccurrenceID: "base", PublicColumn: "c_id_base", LogicalType: "string", Filterable: true, Chartable: false}, - {EmissionID: "em_name", OutputID: "patients", CandidateID: "c_name", OccurrenceID: "base", PublicColumn: "c_name_base", LogicalType: "string", Filterable: false, Chartable: true}, + {EmissionID: "em_id", OutputID: "patients", CandidateID: "c_id", OccurrenceID: "base", ProjectionMode: "VALUE", PublicColumn: "c_id_base", Label: "Patient ID", LogicalType: "string", Filterable: true, Chartable: false}, + {EmissionID: "em_name", OutputID: "patients", CandidateID: "c_name", OccurrenceID: "base", ProjectionMode: "FIRST", PublicColumn: "c_name_base", Label: "Patient name", LogicalType: "string", Filterable: false, Chartable: true}, + {EmissionID: "em_specimen", OutputID: "specimens", CandidateID: "c_specimen", OccurrenceID: "base", ProjectionMode: "VALUE", PublicColumn: "c_specimen_base", Label: "Specimen ID", LogicalType: "string", Filterable: true, Chartable: true}, } - contract := PublicOutputContract{OutputID: "patients", Columns: []PublicOutputColumn{ - {EmissionID: "em_id", PublicColumn: "c_id_base", CandidateID: "c_id", OccurrenceID: "base", LogicalType: "string", Filterable: true, Chartable: false}, - {EmissionID: "em_name", PublicColumn: "c_name_base", CandidateID: "c_name", OccurrenceID: "base", LogicalType: "string", Filterable: false, Chartable: true}, + contract := PublicOutputContracts{Outputs: []PublicOutputContract{ + {OutputID: "patients", Columns: []PublicOutputColumn{ + {EmissionID: "em_id", PublicColumn: "c_id_base", CandidateID: "c_id", OccurrenceID: "base", ProjectionMode: "VALUE", Label: "Patient ID", LogicalType: "string", Filterable: true, Chartable: false}, + {EmissionID: "em_name", PublicColumn: "c_name_base", CandidateID: "c_name", OccurrenceID: "base", ProjectionMode: "FIRST", Label: "Patient name", LogicalType: "string", Filterable: false, Chartable: true}, + }}, + {OutputID: "specimens", Columns: []PublicOutputColumn{ + {EmissionID: "em_specimen", PublicColumn: "c_specimen_base", CandidateID: "c_specimen", OccurrenceID: "base", ProjectionMode: "VALUE", Label: "Specimen ID", LogicalType: "string", Filterable: true, Chartable: true}, + }}, }} return bundle, emitted, contract } -func TestDecodePublicOutputContractIsStrict(t *testing.T) { - valid := json.RawMessage(`{"outputId":"patients","columns":[]}`) - if _, err := DecodePublicOutputContract(valid); err != nil { +func TestDecodePublicOutputContractsIsStrict(t *testing.T) { + valid := json.RawMessage(`{"outputs":[{"outputId":"patients","columns":[]}]}`) + if _, err := DecodePublicOutputContracts(valid); err != nil { t.Fatal(err) } for name, raw := range map[string]json.RawMessage{ - "missing columns": []byte(`{"outputId":"patients"}`), - "unknown field": []byte(`{"outputId":"patients","columns":[],"aql":"for x in c return x"}`), - "duplicate field": []byte(`{"outputId":"patients","columns":[],"columns":[]}`), - "trailing value": []byte(`{"outputId":"patients","columns":[]} {}`), - "not object": []byte(`[]`), + "legacy singular contract": []byte(`{"outputId":"patients","columns":[]}`), + "missing outputs": []byte(`{}`), + "null outputs": []byte(`{"outputs":null}`), + "missing columns": []byte(`{"outputs":[{"outputId":"patients"}]}`), + "unknown field": []byte(`{"outputs":[],"aql":"for x in c return x"}`), + "duplicate field": []byte(`{"outputs":[],"outputs":[]}`), + "duplicate output": []byte(`{"outputs":[{"outputId":"patients","columns":[]},{"outputId":"patients","columns":[]}]}`), + "trailing value": []byte(`{"outputs":[]} {}`), + "not object": []byte(`[]`), } { t.Run(name, func(t *testing.T) { - if _, err := DecodePublicOutputContract(raw); !errors.Is(err, ErrReceiptRecompileRequired) { + if _, err := DecodePublicOutputContracts(raw); !errors.Is(err, ErrReceiptRecompileRequired) { t.Fatalf("error=%v, want ErrReceiptRecompileRequired", err) } }) } } -func TestPublicOutputContractMatchesBundleAndOrderedEmissions(t *testing.T) { +func TestPublicOutputContractsMatchBundleAndOrderedEmissions(t *testing.T) { bundle, emitted, contract := contractFixture() if err := contract.ValidateAgainst(bundle, emitted); err != nil { t.Fatal(err) } - for name, mutate := range map[string]func(*recipe.Bundle, []EmittedColumn, *PublicOutputContract){ - "output identity": func(b *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContract) { c.OutputID = "missing" }, - "column order": func(_ *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContract) { - c.Columns[0], c.Columns[1] = c.Columns[1], c.Columns[0] + for name, mutate := range map[string]func(*recipe.Bundle, []EmittedColumn, *PublicOutputContracts){ + "output identity": func(_ *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContracts) { c.Outputs[0].OutputID = "missing" }, + "output order": func(_ *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContracts) { + c.Outputs[0], c.Outputs[1] = c.Outputs[1], c.Outputs[0] }, - "emission metadata": func(_ *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContract) { c.Columns[0].Filterable = false }, - "column count": func(_ *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContract) { c.Columns = c.Columns[:1] }, - "duplicate emission": func(_ *recipe.Bundle, e []EmittedColumn, _ *PublicOutputContract) { e[1].EmissionID = e[0].EmissionID }, - "duplicate public column": func(_ *recipe.Bundle, e []EmittedColumn, _ *PublicOutputContract) { + "column order": func(_ *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContracts) { + c.Outputs[0].Columns[0], c.Outputs[0].Columns[1] = c.Outputs[0].Columns[1], c.Outputs[0].Columns[0] + }, + "projection metadata": func(_ *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContracts) { + c.Outputs[0].Columns[0].ProjectionMode = "FIRST" + }, + "label metadata": func(_ *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContracts) { + c.Outputs[0].Columns[0].Label = "forged" + }, + "column count": func(_ *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContracts) { + c.Outputs[0].Columns = c.Outputs[0].Columns[:1] + }, + "duplicate emission": func(_ *recipe.Bundle, e []EmittedColumn, _ *PublicOutputContracts) { e[1].EmissionID = e[0].EmissionID }, + "duplicate public column": func(_ *recipe.Bundle, e []EmittedColumn, _ *PublicOutputContracts) { e[1].PublicColumn = e[0].PublicColumn }, - "foreign emitted output": func(_ *recipe.Bundle, e []EmittedColumn, _ *PublicOutputContract) { e[0].OutputID = "other" }, + "foreign emitted output": func(_ *recipe.Bundle, e []EmittedColumn, _ *PublicOutputContracts) { e[0].OutputID = "other" }, } { t.Run(name, func(t *testing.T) { b, e, c := bundle, append([]EmittedColumn(nil), emitted...), contract - c.Columns = append([]PublicOutputColumn(nil), contract.Columns...) + c.Outputs = append([]PublicOutputContract(nil), contract.Outputs...) + for i := range c.Outputs { + c.Outputs[i].Columns = append([]PublicOutputColumn(nil), contract.Outputs[i].Columns...) + } mutate(&b, e, &c) if err := c.ValidateAgainst(b, e); !errors.Is(err, ErrReceiptRecompileRequired) { t.Fatalf("error=%v, want ErrReceiptRecompileRequired", err) @@ -72,7 +95,7 @@ func TestPublicOutputContractMatchesBundleAndOrderedEmissions(t *testing.T) { func TestCompilationReceiptValidateRejectsMismatchedPublicContract(t *testing.T) { r := testReceipt() - r.PublicOutputContract = json.RawMessage(`{"outputId":"out","columns":[{"emissionId":"em_bad","publicColumn":"c_bad","logicalType":"string","filterable":false,"chartable":false}]}`) + r.PublicOutputContract = json.RawMessage(`{"outputs":[{"outputId":"out","columns":[{"emissionId":"em_bad","publicColumn":"c_bad","candidateId":"c_bad","occurrenceId":"base","projectionMode":"VALUE","label":"Bad","logicalType":"string","filterable":false,"chartable":false}]}]}`) r.OutputContractDigest, _ = CompilationArtifactDigest(r.PublicOutputContract) r.CompilationKey, _ = CompilationKey(r) r.ID = "" @@ -80,3 +103,34 @@ func TestCompilationReceiptValidateRejectsMismatchedPublicContract(t *testing.T) t.Fatalf("error=%v, want ErrReceiptRecompileRequired", err) } } + +func TestCompilationReceiptValidateAcceptsCurrentMultiOutputContract(t *testing.T) { + bundle, emitted, contracts := contractFixture() + raw, err := json.Marshal(contracts) + if err != nil { + t.Fatal(err) + } + r := testReceipt() + r.Bundle = bundle + r.EmittedColumns = emitted + r.PublicOutputContract = raw + r.ResolvedRecipeDigest, err = bundle.Digest() + if err != nil { + t.Fatal(err) + } + r.OutputContractDigest, err = CompilationArtifactDigest(raw) + if err != nil { + t.Fatal(err) + } + r.CompilationKey, err = CompilationKey(r) + if err != nil { + t.Fatal(err) + } + r.ID, err = ReceiptID(r) + if err != nil { + t.Fatal(err) + } + if err := r.Validate(); err != nil { + t.Fatal(err) + } +} diff --git a/internal/server/explorer_authoring_error_logging_test.go b/internal/server/explorer_authoring_error_logging_test.go new file mode 100644 index 00000000..6654a0fe --- /dev/null +++ b/internal/server/explorer_authoring_error_logging_test.go @@ -0,0 +1,71 @@ +package server + +import ( + "bytes" + "encoding/json" + "fmt" + "log/slog" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/gofiber/fiber/v3" +) + +func TestAuthoringHTTPErrorLogsGenericCauseWithoutExposingIt(t *testing.T) { + var logs bytes.Buffer + previousLogger := slog.Default() + slog.SetDefault(slog.New(slog.NewJSONHandler(&logs, nil))) + t.Cleanup(func() { slog.SetDefault(previousLogger) }) + + app := fiber.New() + app.Get("/api/v1/projects/:project/explorers/:explorerId", func(c fiber.Ctx) error { + c.Locals("request_id", "builder-log-test") + cause := fmt.Errorf("compile receipt: %w", fmt.Errorf("semantic lowering exploded")) + return authoringHTTPError(c, cause) + }) + + response, err := app.Test(httptest.NewRequest(http.MethodGet, "/api/v1/projects/HTAN_INT%252FBForePC/explorers/default", nil)) + if err != nil { + t.Fatal(err) + } + defer response.Body.Close() + if response.StatusCode != http.StatusInternalServerError { + t.Fatalf("status = %d, want %d", response.StatusCode, http.StatusInternalServerError) + } + var body map[string]any + if err := json.NewDecoder(response.Body).Decode(&body); err != nil { + t.Fatal(err) + } + if body["code"] != "INTERNAL_ERROR" || body["message"] != "internal server error" { + t.Fatalf("response = %#v", body) + } + if encoded, err := json.Marshal(body); err != nil { + t.Fatal(err) + } else if strings.Contains(string(encoded), "semantic lowering exploded") { + t.Fatalf("response exposed internal cause: %s", encoded) + } + + var entry map[string]any + if err := json.Unmarshal(logs.Bytes(), &entry); err != nil { + t.Fatalf("decode log entry: %v\n%s", err, logs.String()) + } + for key, want := range map[string]any{ + "msg": "Explorer authoring request failed", + "request_id": "builder-log-test", + "method": http.MethodGet, + "path": "/api/v1/projects/HTAN_INT%252FBForePC/explorers/default", + "status": float64(http.StatusInternalServerError), + "project": "HTAN_INT/BForePC", + "explorer_id": "default", + "stage": "internal", + "code": "INTERNAL_ERROR", + "cause": "compile receipt: semantic lowering exploded", + "cause_type": "*fmt.wrapError", + } { + if got := entry[key]; got != want { + t.Errorf("log[%q] = %#v, want %#v; log=%s", key, got, want, logs.String()) + } + } +} diff --git a/internal/server/explorer_authoring_migration.go b/internal/server/explorer_authoring_migration.go index 8b4d6344..e27bfa1b 100644 --- a/internal/server/explorer_authoring_migration.go +++ b/internal/server/explorer_authoring_migration.go @@ -73,8 +73,15 @@ func MigrateLegacyExplorerAuthoring(ctx context.Context, service *explorer.Servi if options.RequestID == "" { options.RequestID = "loom-authoring-migration-" + options.Project + "-" + options.ExplorerID } - if service == nil || capabilities.Catalog == nil || capabilities.AuthoringCompile == nil || capabilities.Materialize == nil || capabilities.ValidateReleaseGeneration == nil || capabilities.ActivateRelease == nil { - return ExplorerAuthoringMigrationReport{}, errors.New("Explorer authoring migration requires catalog, compiler, materializer, generation validator, and release activation") + if service == nil || capabilities.Catalog == nil || capabilities.ValidateReleaseGeneration == nil || capabilities.ActivateRelease == nil { + return ExplorerAuthoringMigrationReport{}, errors.New("Explorer authoring migration requires catalog, generation validator, and release activation") + } + if options.AuditOnly { + if capabilities.AuthoringCompile == nil { + return ExplorerAuthoringMigrationReport{}, errors.New("Explorer authoring migration audit requires the legacy intent compiler") + } + } else if capabilities.Capability == nil || capabilities.CompileReceipt == nil || capabilities.MaterializeReceipt == nil { + return ExplorerAuthoringMigrationReport{}, errors.New("Explorer authoring migration requires the native V2 capability compiler and receipt materializer") } mode := "apply" @@ -98,9 +105,11 @@ func MigrateLegacyExplorerAuthoring(ctx context.Context, service *explorer.Servi report.SourceGeneration = snapshot.Generation var activeBundle json.RawMessage + var activeRevision *explorer.Revision if owner.ActiveRevisionID != "" { - if activeRevision, revisionErr := service.Revision(ctx, owner.ActiveRevisionID); revisionErr == nil { - activeBundle = activeRevision.AuthoringBundle + if storedRevision, revisionErr := service.Revision(ctx, owner.ActiveRevisionID); revisionErr == nil { + activeRevision = storedRevision + activeBundle = storedRevision.AuthoringBundle } } var migrationDiagnostics []string @@ -114,11 +123,42 @@ func MigrateLegacyExplorerAuthoring(ctx context.Context, service *explorer.Servi report.TabCount = len(bundle.AuthoringTabs()) report.OutputCount = len(bundle.AuthoringDocuments()) - compiled, err := capabilities.AuthoringCompile(ctx, ExplorerAuthoringV1CompileRequest{Bundle: bundle, SnapshotToken: snapshot.Token, RequestID: options.RequestID}) - if err != nil { - return report, fmt.Errorf("compile migrated Explorer authoring intent: %w", err) + var receipt explorer.CompilationReceipt + if options.AuditOnly { + compiled, compileErr := capabilities.AuthoringCompile(ctx, ExplorerAuthoringV1CompileRequest{Bundle: bundle, SnapshotToken: snapshot.Token, RequestID: options.RequestID}) + if compileErr != nil { + return report, fmt.Errorf("audit migrated Explorer authoring intent: %w", compileErr) + } + receipt = compiled.Receipt + } else { + capabilitySnapshot, capabilityErr := capabilities.Capability(ctx, options.Project, options.ExplorerID, snapshot.Generation) + if capabilityErr != nil { + return report, fmt.Errorf("load native V2 capability snapshot: %w", capabilityErr) + } + if !capabilitySnapshot.Usable() || capabilitySnapshot.Identity.Generation != snapshot.Generation { + return report, fmt.Errorf("native V2 capability snapshot does not match migration generation %q", snapshot.Generation) + } + wire := authoringV2Catalog(capabilitySnapshot, options.ExplorerID) + emitted := []explorer.EmittedColumn(nil) + if activeRevision != nil { + emitted = activeRevision.EmittedColumns + } + workspace, migrateErr := migrateV1WorkspaceToCapability(bundle, capabilitySnapshot, wire, emitted) + if migrateErr != nil { + return report, fmt.Errorf("convert stored V1 workspace to V2: %w", migrateErr) + } + compiled, compileErr := capabilities.CompileReceipt(ctx, ExplorerV2ReceiptCompileRequest{ + Project: options.Project, ExplorerID: options.ExplorerID, Workspace: workspace, + SnapshotToken: capabilitySnapshot.Token, RequestID: options.RequestID, + }) + if compileErr != nil { + return report, fmt.Errorf("compile migrated V2 workspace: %w", compileErr) + } + if compiled == nil { + return report, errors.New("compile migrated V2 workspace: compiler returned no receipt") + } + receipt = *compiled } - receipt := compiled.Receipt report.IntentDigest, report.ReceiptID = receipt.IntentDigest, receipt.ID if options.AuditOnly { return report, nil @@ -147,7 +187,7 @@ func MigrateLegacyExplorerAuthoring(ctx context.Context, service *explorer.Servi if err := capabilities.ValidateReleaseGeneration(ctx, storageProject, receipt.SourceGeneration); err != nil { return report, fmt.Errorf("validate migrated Explorer generation: %w", err) } - execution, err := capabilities.Materialize(ctx, receipt.Bundle, recipe.RuntimeBindings{Project: storageProject, DatasetGeneration: receipt.SourceGeneration}) + execution, err := capabilities.MaterializeReceipt(ctx, &receipt, recipe.RuntimeBindings{Project: storageProject, DatasetGeneration: receipt.SourceGeneration}) if err != nil { return report, fmt.Errorf("materialize migrated Explorer receipt: %w", err) } diff --git a/internal/server/explorer_authoring_migration_test.go b/internal/server/explorer_authoring_migration_test.go index 8983b0a4..296bf3de 100644 --- a/internal/server/explorer_authoring_migration_test.go +++ b/internal/server/explorer_authoring_migration_test.go @@ -5,7 +5,12 @@ import ( "encoding/json" "testing" + graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataset" "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/explorer/authoringv2" + "github.com/calypr/loom/internal/explorer/capability" ) func TestMappingAuthoringBundleCanonicalizesIdentityAndDigest(t *testing.T) { @@ -187,6 +192,100 @@ func TestResolvedAuthoringBindingSerializesEmptyCandidateEmissionsAsArray(t *tes } } +func TestMigrationPublishesNativeV2WorkspaceRevision(t *testing.T) { + ctx := context.Background() + store := explorer.NewMemoryStore() + service, err := explorer.NewService(store) + if err != nil { + t.Fatal(err) + } + owner, err := service.EnsureRepositoryExplorer(ctx, "project-a", "default", "Default", "test") + if err != nil { + t.Fatal(err) + } + legacyCandidateID := explorer.OpaqueID("s_", "Patient\x00id") + visible := true + order := 0 + legacyBundle := explorer.ExplorerAuthoringBundleV1{ + APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, + Project: "project-a", ExplorerID: "default", Title: "Default", + Documents: []explorer.ExplorerBuilderDocumentV1{{ + Kind: explorer.ExplorerBuilderV1Kind, + Output: explorer.ExplorerOutputIdentityV1{ID: "patients", Title: "Patients"}, + BaseNodeID: explorer.OpaqueID("n_", "Patient"), RowNodeID: explorer.OpaqueID("n_", "Patient"), + CandidateIDs: []string{legacyCandidateID}, + CandidateOccurrences: []explorer.ExplorerCandidateOccurrenceV1{{CandidateID: legacyCandidateID, OccurrenceID: "base", ProjectionMode: "SCALAR"}}, + Presentation: map[string]explorer.ExplorerPresentationBindingV1{legacyCandidateID + "\x00base": {Label: "Identifier", Visible: &visible, Order: &order}}, + }}, + Tabs: []explorer.ExplorerTabV1{{ID: "patients-tab", Title: "Patients", OutputID: "patients", Order: 0, Visible: &visible}}, + } + legacyRaw := mustAuthoringJSON(t, legacyBundle) + if _, err := service.PublishAuthoring(ctx, + explorer.CompilationReceipt{ID: "legacy-receipt", Project: "project-a", ExplorerID: "default", NormalizedBundle: legacyRaw}, + explorer.Revision{ID: "legacy-revision", Project: owner.Project, ExplorerID: "default", CompilationReceiptID: "legacy-receipt", IntentDigest: "legacy-intent", AuthoringBundle: legacyRaw, Status: explorer.RevisionReady}, + ); err != nil { + t.Fatal(err) + } + rawMapping, err := json.Marshal(map[string]any{"bundle": legacyBundle}) + if err != nil { + t.Fatal(err) + } + legacyCatalog := explorer.Catalog{ + Nodes: []explorer.CatalogNode{{ID: explorer.OpaqueID("n_", "Patient"), ResourceType: "Patient"}}, + Selections: map[string]explorer.CatalogSelection{legacyCandidateID: {ID: legacyCandidateID, NodeID: explorer.OpaqueID("n_", "Patient"), FieldRef: "Patient.id", Select: "id", ProjectionModes: []string{"SCALAR"}, DefaultProjectionMode: "SCALAR"}}, + } + legacySnapshot := explorer.CatalogSnapshot{Project: "project-a", Generation: "generation-a", AuthorizationScopeDigest: "scope-a", Catalog: legacyCatalog, Complete: true, Token: "legacy-snapshot"} + nativeSnapshot := capability.Snapshot{ + Identity: capability.SnapshotIdentity{Project: "project-a", Generation: "generation-a", AuthorizationScopeDigest: "scope-a"}, + Policy: capability.Policy{Route: capability.RoutePolicy{AllowsRepeatedEdges: true, AllowsSelfLoops: true}}, + Status: capability.StatusReady, Complete: true, Token: "native-snapshot", + Nodes: []capability.Node{{ID: "patient-node", ResourceType: "Patient", RowRootEligible: true, RowGrain: "patient", Populated: true, DocumentCount: 1}}, + Candidates: []capability.Candidate{{ID: "patient-id", NodeID: "patient-node", ResourceType: "Patient", FieldPath: "id", Label: "Identifier", LogicalType: "string", Cardinality: "scalar", ProjectionModes: []capability.ProjectionMode{capability.ProjectionScalar}, Populated: true}}, + } + compiledWorkspace := authoringv2.Workspace{} + config := ExplorerV2LifecycleConfig{ + Catalog: func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { + return legacySnapshot, nil + }, + Capability: func(context.Context, string, string, string) (capability.Snapshot, error) { return nativeSnapshot, nil }, + CompileReceipt: func(_ context.Context, request ExplorerV2ReceiptCompileRequest) (*explorer.CompilationReceipt, error) { + compiledWorkspace = request.Workspace + normalized, marshalErr := request.Workspace.CanonicalJSON() + if marshalErr != nil { + return nil, marshalErr + } + return &explorer.CompilationReceipt{ + ID: "native-v2-receipt", Project: "project-a", ExplorerID: "default", IntentDigest: "v2-intent", + SnapshotToken: nativeSnapshot.Token, SourceGeneration: "generation-a", NormalizedBundle: normalized, + Bundle: recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "migrated", Outputs: []recipe.Output{{Name: "patients", RootResourceType: "Patient", RowGrain: "patient"}}}, + }, nil + }, + MaterializeReceipt: func(context.Context, *explorer.CompilationReceipt, recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { + return graphresolver.RecipeExecution{ID: "migration-execution", SourceGeneration: "generation-a", State: "PUBLISHED", Outputs: []graphresolver.RecipeExecutionOutput{{Name: "patients", State: "PUBLISHED"}}}, nil + }, + ValidateReleaseGeneration: func(context.Context, string, string) error { return nil }, + ActivateRelease: func(context.Context, string, string, []dataset.DataframeSelector) error { return nil }, + } + report, err := MigrateLegacyExplorerAuthoring(ctx, service, config, ExplorerAuthoringMigrationOptions{Project: "project-a", ExplorerID: "default", LegacyMapping: rawMapping}) + if err != nil { + t.Fatal(err) + } + if report.ExplorerActivated == false || len(compiledWorkspace.Documents) != 1 { + t.Fatalf("report=%#v workspace=%#v", report, compiledWorkspace) + } + active, err := service.ActiveRevision(ctx, "project-a", "default") + if err != nil { + t.Fatal(err) + } + storedWorkspace, err := authoringv2.DecodeWorkspace(active.AuthoringBundle) + if err != nil { + t.Fatalf("active authoring bundle is not V2: %v\n%s", err, active.AuthoringBundle) + } + if len(storedWorkspace.Documents) != 1 || storedWorkspace.Documents[0].Selections[0].CandidateID != "patient-id" { + t.Fatalf("stored workspace=%#v", storedWorkspace) + } +} + func mustAuthoringJSON(t *testing.T, bundle explorer.ExplorerAuthoringBundleV1) []byte { t.Helper() raw, err := bundle.CanonicalJSON() diff --git a/internal/server/explorer_authoring_v1_routes.go b/internal/server/explorer_authoring_v1_routes.go index 0b29c058..a1fc829a 100644 --- a/internal/server/explorer_authoring_v1_routes.go +++ b/internal/server/explorer_authoring_v1_routes.go @@ -493,11 +493,41 @@ func authoringHTTPError(c fiber.Ctx, err error) error { var value *explorer.AuthoringError if errors.As(err, &value) { value.Diagnostic.RequestID = requestID - slog.Error("Explorer authoring request failed", "request_id", requestID, "project", explorerProjectParam(c), "explorer_id", strings.TrimSpace(c.Params("explorerId")), "stage", value.Diagnostic.Stage, "code", value.Diagnostic.Code, "json_path", value.Diagnostic.JSONPath, "message", value.Diagnostic.Message, "details", value.Diagnostic.Details, "cause", value.Cause) - return c.Status(value.Status).JSON(fiber.Map{"error": fiber.Map{"code": value.Diagnostic.Code, "message": value.Diagnostic.Message, "requestId": requestID, "diagnostic": value.Diagnostic}, "diagnostics": []explorer.AuthoringDiagnostic{value.Diagnostic}}) + cause := value.Cause + if cause == nil { + cause = err + } + logAuthoringRequestFailure(c, requestID, value.Status, value.Diagnostic.Stage, value.Diagnostic.Code, value.Diagnostic.JSONPath, value.Diagnostic.Message, value.Diagnostic.Details, cause) + details := value.Diagnostic.Details + if details == nil { + details = map[string]any{} + } + diagnostic := fiber.Map{"severity": strings.ToLower(value.Diagnostic.Severity), "stage": value.Diagnostic.Stage, "code": value.Diagnostic.Code, "path": value.Diagnostic.JSONPath, "message": value.Diagnostic.Message, "requestId": requestID} + return c.Status(value.Status).JSON(fiber.Map{"code": value.Diagnostic.Code, "message": value.Diagnostic.Message, "diagnostics": []fiber.Map{diagnostic}, "requestId": requestID, "details": details}) } if errors.Is(err, explorer.ErrNotFound) { - return c.Status(404).JSON(fiber.Map{"error": fiber.Map{"code": "NOT_FOUND", "message": "Explorer resource not found", "requestId": requestID}}) + return c.Status(404).JSON(fiber.Map{"code": "NOT_FOUND", "message": "Explorer resource not found", "diagnostics": []any{}, "requestId": requestID, "details": fiber.Map{}}) + } + logAuthoringRequestFailure(c, requestID, 500, "internal", "INTERNAL_ERROR", "", "internal server error", nil, err) + return c.Status(500).JSON(fiber.Map{"code": "INTERNAL_ERROR", "message": "internal server error", "diagnostics": []any{}, "requestId": requestID, "details": fiber.Map{}}) +} + +func logAuthoringRequestFailure(c fiber.Ctx, requestID string, status int, stage, code, jsonPath, message string, details map[string]any, cause error) { + attrs := []any{ + "request_id", requestID, + "method", c.Method(), + "path", c.Path(), + "status", status, + "project", explorerProjectParam(c), + "explorer_id", strings.TrimSpace(c.Params("explorerId")), + "stage", stage, + "code", code, + "json_path", jsonPath, + "message", message, + "details", details, + } + if cause != nil { + attrs = append(attrs, "cause", cause, "cause_type", fmt.Sprintf("%T", cause)) } - return c.Status(500).JSON(fiber.Map{"error": fiber.Map{"code": "INTERNAL_ERROR", "message": "internal server error", "requestId": requestID}}) + slog.Error("Explorer authoring request failed", attrs...) } diff --git a/internal/server/explorer_authoring_v2_migration_test.go b/internal/server/explorer_authoring_v2_migration_test.go new file mode 100644 index 00000000..ed23979a --- /dev/null +++ b/internal/server/explorer_authoring_v2_migration_test.go @@ -0,0 +1,63 @@ +package server + +import ( + "testing" + + "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/explorer/authoringv2" + "github.com/calypr/loom/internal/explorer/capability" +) + +func TestMigrateV1WorkspaceMapsLegacyCandidateOccurrencePresentation(t *testing.T) { + visible := true + order := 0 + legacyCandidateID := explorer.OpaqueID("s_", "Patient\x00id") + snapshot := capability.Snapshot{ + Identity: capability.SnapshotIdentity{Project: "project-a", Generation: "generation-a", AuthorizationScopeDigest: "scope-a"}, + Policy: capability.Policy{Route: capability.RoutePolicy{AllowsRepeatedEdges: true, AllowsSelfLoops: true}}, + Status: capability.StatusReady, Complete: true, Token: "snapshot-a", + Nodes: []capability.Node{{ID: "patient-node", ResourceType: "Patient", RowRootEligible: true, RowGrain: "patient", Populated: true, DocumentCount: 3}}, + Candidates: []capability.Candidate{{ + ID: "patient-id", NodeID: "patient-node", ResourceType: "Patient", FieldPath: "id", Label: "Identifier", LogicalType: "string", Cardinality: "scalar", + ProjectionModes: []capability.ProjectionMode{capability.ProjectionScalar}, FilterOperators: []capability.FilterOperator{capability.FilterEquals}, ChartAggregations: []capability.ChartAggregation{capability.ChartCount}, Populated: true, + }}, + } + wire := authoringV2Catalog(snapshot, "default") + bundle := explorer.ExplorerAuthoringBundleV1{ + APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, + Project: "project-a", ExplorerID: "default", Title: "Default", + Documents: []explorer.ExplorerBuilderDocumentV1{{ + Kind: explorer.ExplorerBuilderV1Kind, + Output: explorer.ExplorerOutputIdentityV1{ID: "patients", Title: "Patients"}, + BaseNodeID: explorer.OpaqueID("n_", "Patient"), RowNodeID: explorer.OpaqueID("n_", "Patient"), + CandidateIDs: []string{legacyCandidateID}, + CandidateOccurrences: []explorer.ExplorerCandidateOccurrenceV1{{CandidateID: legacyCandidateID, OccurrenceID: "base", ProjectionMode: "SCALAR"}}, + Presentation: map[string]explorer.ExplorerPresentationBindingV1{ + legacyCandidateID + "\x00base": { + Label: "Patient identifier", Visible: &visible, Order: &order, + Table: &explorer.ExplorerTableBindingV1{Pinned: true}, + Filter: &explorer.ExplorerFilterBindingV1{Label: "Patient ID"}, + Chart: &explorer.ExplorerChartBindingV1{Type: "bar", Title: "Patients"}, + }, + }, + }}, + Tabs: []explorer.ExplorerTabV1{{ID: "patients-tab", Title: "Patients", OutputID: "patients", Order: 0, Visible: &visible}}, + } + + workspace, err := migrateV1WorkspaceToCapability(bundle, snapshot, wire, nil) + if err != nil { + t.Fatal(err) + } + if len(workspace.Documents) != 1 || len(workspace.Tabs) != 1 { + t.Fatalf("workspace = %#v", workspace) + } + document := workspace.Documents[0] + if len(document.Selections) != 1 || document.Selections[0].CandidateID != "patient-id" || document.Selections[0].ProjectionMode != "VALUE" { + t.Fatalf("selections = %#v", document.Selections) + } + key := authoringv2.PresentationKey("patient-id", "base", "VALUE") + presentation, ok := document.Presentation[key] + if !ok || presentation.Label != "Patient identifier" || presentation.Table == nil || !presentation.Table.Pinned || presentation.Filter == nil || presentation.Filter.Label != "Patient ID" || presentation.Chart == nil || presentation.Chart.Type != "bar" || presentation.Chart.Title != "Patients" { + t.Fatalf("presentation = %#v", document.Presentation) + } +} diff --git a/internal/server/explorer_authoring_v2_routes.go b/internal/server/explorer_authoring_v2_routes.go index a213fc7d..417cff40 100644 --- a/internal/server/explorer_authoring_v2_routes.go +++ b/internal/server/explorer_authoring_v2_routes.go @@ -8,6 +8,7 @@ import ( "strings" "time" + explorerv2api "github.com/calypr/loom/generated/explorerv2" graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" "github.com/calypr/loom/internal/authscope" "github.com/calypr/loom/internal/dataframe/recipe" @@ -15,6 +16,7 @@ import ( "github.com/calypr/loom/internal/explorer" "github.com/calypr/loom/internal/explorer/authoringv2" "github.com/calypr/loom/internal/explorer/capability" + explorercompilation "github.com/calypr/loom/internal/explorer/compilation" "github.com/calypr/loom/internal/projectid" "github.com/gofiber/fiber/v3" ) @@ -47,11 +49,45 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth if err := authoringRead(c, authorizeRead); err != nil { return err } - _, wire, err := readCapability(c) - if err != nil { - return authoringHTTPError(c, err) + return c.JSON(explorerv2api.AuthoringCapability{ + ApiVersion: explorerv2api.LoomCalyprOrgexplorerAuthoringv2, + Kind: explorerv2api.ExplorerAuthoringCapabilities, + Operations: []explorerv2api.AuthoringCapabilityOperations{explorerv2api.Builder, explorerv2api.Compile, explorerv2api.Suggestions, explorerv2api.Preview, explorerv2api.Publish}, + PreviewLimits: []int{10, 25, 50, 100}, + Features: explorerv2api.AuthoringFeatures{EmissionFilters: true, EmissionCharts: true}, + }) + }) + + app.Post(prefix+"/suggestions", func(c fiber.Ctx) error { + if err := authoringRead(c, authorizeRead); err != nil { + return err + } + var request explorerv2api.CandidateSearchRequest + if err := decodeAuthoringStrict(c.Body(), &request); err != nil || strings.TrimSpace(request.SnapshotToken) == "" || strings.TrimSpace(request.NodeId) == "" { + if err == nil { + err = fmt.Errorf("snapshotToken and nodeId are required") + } + return authoringHTTPError(c, malformedRouteError("suggestions", err)) + } + if capabilities.CapabilityToken == nil { + return authoringHTTPError(c, explorerUnavailable("suggestions", "CAPABILITY_UNAVAILABLE", "Explorer capability lookup is not configured")) } - return c.JSON(wire) + snapshot, err := capabilities.CapabilityToken(c.Context(), explorerProjectParam(c), request.SnapshotToken) + if err != nil || snapshot.ValidateToken(request.SnapshotToken) != nil { + return authoringHTTPError(c, explorerConflict("suggestions", "STALE_CATALOG_SNAPSHOT", "the catalog snapshot is stale", nil)) + } + query := "" + if request.Query != nil { + query = strings.ToLower(strings.TrimSpace(*request.Query)) + } + candidates := []authoringv2.CatalogCandidate{} + wire := authoringV2Catalog(snapshot, strings.TrimSpace(c.Params("explorerId"))) + for _, candidate := range wire.Candidates { + if candidate.NodeID == request.NodeId && (query == "" || strings.Contains(strings.ToLower(candidate.Label), query) || strings.Contains(strings.ToLower(candidate.ID), query)) { + candidates = append(candidates, candidate) + } + } + return c.JSON(fiber.Map{"apiVersion": authoringv2.APIVersion, "kind": "ExplorerBuilderCandidateSuggestions", "snapshotToken": request.SnapshotToken, "nodeId": request.NodeId, "candidates": candidates, "diagnostics": []any{}}) }) // Suggested values stay out of the main capability document. They are @@ -72,17 +108,18 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth } snapshot, err := capabilities.CapabilityToken(c.Context(), project, token) if err != nil { - return authoringHTTPError(c, explorerConflict("capability", "STALE_CAPABILITY_SNAPSHOT", "the capability snapshot is stale or unavailable", map[string]any{"snapshotToken": token})) + return authoringHTTPError(c, explorerConflict("capability", "STALE_CATALOG_SNAPSHOT", "the capability snapshot is stale or unavailable", map[string]any{"snapshotToken": token})) } for _, candidate := range snapshot.Candidates { if candidate.ID != candidateID { continue } - return c.JSON(fiber.Map{ - "apiVersion": authoringv2.APIVersion, "kind": "ExplorerCandidateSuggestions", - "snapshotToken": token, "candidateId": candidateID, - "values": append([]string(nil), candidate.SuggestedValues...), - "complete": candidate.SuggestionsComplete, "truncated": candidate.SuggestionsTruncated, + return c.JSON(explorerv2api.CandidateSuggestions{ + ApiVersion: explorerv2api.LoomCalyprOrgexplorerAuthoringv2, + Kind: explorerv2api.ExplorerCandidateSuggestions, + SnapshotToken: token, CandidateId: candidateID, + Values: append([]string(nil), candidate.SuggestedValues...), + Complete: candidate.SuggestionsComplete, Truncated: candidate.SuggestionsTruncated, }) } return authoringHTTPError(c, &explorer.AuthoringError{Status: http.StatusNotFound, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "capability", Code: "CANDIDATE_NOT_FOUND", Message: "candidate is not present in the capability snapshot"}}) @@ -104,14 +141,18 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth _ = owner state := authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, Catalog: wire} if active, activeErr := explorers.ActiveRevision(c.Context(), project, id); activeErr == nil && len(active.AuthoringBundle) != 0 { - if document, decodeErr := authoringv2.DecodeDocument(active.AuthoringBundle); decodeErr == nil { - state.Document = &document + if workspace, decodeErr := authoringv2.DecodeWorkspace(active.AuthoringBundle); decodeErr == nil { + state.Workspace = &workspace + } else if document, decodeErr := authoringv2.DecodeDocument(active.AuthoringBundle); decodeErr == nil { + document.APIVersion = "" + workspace := authoringv2.Workspace{APIVersion: authoringv2.APIVersion, Kind: authoringv2.WorkspaceKind, Documents: []authoringv2.Document{document}, Tabs: []authoringv2.Tab{{ID: document.Output.ID, Title: document.Output.Title, OutputID: document.Output.ID, Order: 0, Visible: true}}} + state.Workspace = &workspace } else if bundle, decodeErr := explorer.DecodeAuthoringBundleV1ForMigration(active.AuthoringBundle); decodeErr == nil { - if documents := bundle.AuthoringDocuments(); len(documents) > 0 { - if document, migrateErr := migrateV1DocumentToCapability(documents[0], snapshot, wire); migrateErr == nil { - state.Document = &document - } + workspace, migrateErr := migrateV1WorkspaceToCapability(bundle, snapshot, wire, active.EmittedColumns) + if migrateErr != nil { + return authoringHTTPError(c, authoringSemanticRoute("migration", "$", "MIGRATION_FAILED", migrateErr.Error(), nil)) } + state.Workspace = &workspace } } else if activeErr != nil && !errors.Is(activeErr, explorer.ErrNotFound) { return authoringHTTPError(c, activeErr) @@ -126,10 +167,7 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth if err := authoringWrite(c, authorizer); err != nil { return err } - var request struct { - Document authoringv2.Document `json:"document"` - SnapshotToken string `json:"snapshotToken"` - } + var request explorerv2api.CompileRequest if err := decodeAuthoringStrict(c.Body(), &request); err != nil { return authoringHTTPError(c, malformedRouteError("intent", err)) } @@ -147,21 +185,21 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth snapshot, err = capabilities.CapabilityToken(c.Context(), project, request.SnapshotToken) } if err != nil { - return authoringHTTPError(c, explorerConflict("capability", "STALE_CAPABILITY_SNAPSHOT", "the capability snapshot is stale or unavailable", map[string]any{"snapshotToken": request.SnapshotToken})) + return authoringHTTPError(c, explorerConflict("capability", "STALE_CATALOG_SNAPSHOT", "the capability snapshot is stale or unavailable", map[string]any{"snapshotToken": request.SnapshotToken})) } wire := authoringV2Catalog(snapshot, id) - state := authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, Document: &request.Document, Catalog: wire} + state := authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, Workspace: &request.Workspace, Catalog: wire} if err := state.Validate(); err != nil { - return authoringHTTPError(c, authoringSemanticRoute("intent", "$", "INVALID_AUTHORING_INTENT", err.Error(), nil)) + return authoringHTTPError(c, authoringSemanticRoute("intent", "$", workspaceValidationCode(err), err.Error(), nil)) } var stored *explorer.CompilationReceipt nativeReceipt := capabilities.CompileReceipt != nil if nativeReceipt { - stored, err = capabilities.CompileReceipt(c.Context(), ExplorerV2ReceiptCompileRequest{Project: project, ExplorerID: id, Document: request.Document, SnapshotToken: snapshot.Token, RequestID: requestIDFromFiber(c), Authorized: authorized}) + stored, err = capabilities.CompileReceipt(c.Context(), ExplorerV2ReceiptCompileRequest{Project: project, ExplorerID: id, Workspace: request.Workspace, SnapshotToken: snapshot.Token, RequestID: requestIDFromFiber(c), Authorized: authorized}) } else { // Compatibility path for migration-only callers. Production wiring // supplies CompileReceipt and never enters this V1 adapter. - bundle, bundleErr := authoringV2Bundle(project, id, request.Document, wire) + bundle, bundleErr := authoringV2WorkspaceBundle(project, id, request.Workspace, wire) if bundleErr != nil { return authoringHTTPError(c, authoringSemanticRoute("intent", "$", "INVALID_AUTHORING_INTENT", bundleErr.Error(), nil)) } @@ -172,6 +210,10 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth err = compileErr } if err != nil { + var compileErr *explorercompilation.Error + if errors.As(err, &compileErr) { + return authoringHTTPError(c, authoringSemanticRoute(compileErr.Stage, compileErr.Path, compilationErrorCode(compileErr.Code), compileErr.Message, compileErr.Details)) + } return authoringHTTPError(c, err) } if stored == nil || strings.TrimSpace(stored.ID) == "" { @@ -186,12 +228,7 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth return authoringHTTPError(c, explorerUnavailable("compile", "COMPILATION_RECEIPT_STORE_FAILED", "compiled authoring receipt could not be persisted")) } } - return c.JSON(fiber.Map{ - "apiVersion": authoringv2.APIVersion, "kind": "ExplorerCompileResult", - "builder": state, "receiptId": stored.ID, "snapshotToken": snapshot.Token, - "sourceGeneration": stored.SourceGeneration, "resolvedSchemaDigest": stored.ResolvedSchemaDigest, - "emittedColumns": stored.EmittedColumns, - }) + return c.JSON(v2ReceiptResponse(stored, request.Workspace)) } app.Post(prefix+"/builder", compileHandler) app.Post(prefix+"/compile", compileHandler) @@ -213,22 +250,19 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth if err := authoringRead(c, authorizeRead); err != nil { return err } - var request struct { - ReceiptID string `json:"receiptId"` - OutputID string `json:"outputId"` - Limit int `json:"limit,omitempty"` - } - if err := decodeAuthoringStrict(c.Body(), &request); err != nil || strings.TrimSpace(request.ReceiptID) == "" || strings.TrimSpace(request.OutputID) == "" { + var request explorerv2api.PreviewRequest + if err := decodeAuthoringStrict(c.Body(), &request); err != nil || strings.TrimSpace(request.ReceiptId) == "" || strings.TrimSpace(request.OutputId) == "" { if err == nil { err = fmt.Errorf("receiptId and outputId are required") } return authoringHTTPError(c, malformedRouteError("preview", err)) } - logReceiptID, logOutputID = request.ReceiptID, request.OutputID - if request.Limit == 0 { - request.Limit = engine.DefaultPreviewLimit + logReceiptID, logOutputID = request.ReceiptId, request.OutputId + limit := engine.DefaultPreviewLimit + if request.Limit != nil { + limit = *request.Limit } - if request.Limit < 1 || request.Limit > engine.MaxPreviewLimit { + if limit < 1 || limit > engine.MaxPreviewLimit { return authoringHTTPError(c, authoringSemanticRoute("preview", "$.limit", "INVALID_PREVIEW_LIMIT", "limit must be between 1 and 1000", nil)) } nativeReceiptPreview := capabilities.PreviewReceipt != nil @@ -239,7 +273,7 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth return authoringHTTPError(c, explorerUnavailable("preview", "PREVIEW_UNAVAILABLE", "Explorer preview is not configured")) } lookupStarted := time.Now() - receipt, err := lookupV2Receipt(previewCtx, explorers, capabilities, explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")), request.ReceiptID) + receipt, err := lookupV2Receipt(previewCtx, explorers, capabilities, explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")), request.ReceiptId) lookupDuration = time.Since(lookupStarted) if err != nil { return authoringHTTPError(c, receiptRouteError("preview", err)) @@ -252,34 +286,34 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth authorizationDuration = time.Since(authorizationStarted) snapshot := authorized.Snapshot if err != nil || snapshot.ValidateToken(receipt.SnapshotToken) != nil || strings.TrimSpace(snapshot.Identity.Generation) != strings.TrimSpace(receipt.SourceGeneration) { - return authoringHTTPError(c, explorerConflict("preview", "RECEIPT_INPUT_UNAVAILABLE", "the receipt's capability snapshot is no longer authorized or retained", nil)) + return authoringHTTPError(c, explorerConflict("preview", "RECEIPT_STALE", "the receipt's capability snapshot is no longer authorized or retained", nil)) } if capabilities.PreviewReceipt != nil { if err := validateAuthorizedReceiptExecution(receipt, authorized); err != nil { - return authoringHTTPError(c, explorerConflict("preview", "RECEIPT_INPUT_UNAVAILABLE", "the receipt's capability snapshot is no longer authorized or retained", nil)) + return authoringHTTPError(c, explorerConflict("preview", "RECEIPT_STALE", "the receipt's capability snapshot is no longer authorized or retained", nil)) } } if nativeReceiptPreview { - if !receiptHasOutput(receipt.Bundle, request.OutputID) { + if !receiptHasOutput(receipt.Bundle, request.OutputId) { return authoringHTTPError(c, authoringSemanticRoute("preview", "$.outputId", "UNKNOWN_AUTHORING_OUTPUT", "outputId is not in the receipt", nil)) } - if err := validateReceiptOutputContract(receipt, request.OutputID); err != nil { + if err := validateReceiptOutputContract(receipt, request.OutputId); err != nil { return authoringHTTPError(c, authoringSemanticRoute("preview", "$.outputId", "UNKNOWN_AUTHORING_OUTPUT", "outputId is not in the receipt", nil)) } - } else if !receiptHasOutput(receipt.Bundle, request.OutputID) { + } else if !receiptHasOutput(receipt.Bundle, request.OutputId) { return authoringHTTPError(c, authoringSemanticRoute("preview", "$.outputId", "UNKNOWN_AUTHORING_OUTPUT", "outputId is not in the receipt", nil)) } - bindings := recipe.RuntimeBindings{Project: projectid.Legacy(receipt.Project), DatasetGeneration: receipt.SourceGeneration, PreviewLimit: request.Limit, OutputNames: []string{request.OutputID}} + bindings := recipe.RuntimeBindings{Project: projectid.Legacy(receipt.Project), DatasetGeneration: receipt.SourceGeneration, PreviewLimit: limit, OutputNames: []string{request.OutputId}} applyAuthorizedScope(&bindings, authorized, false) columns := make([]explorer.EmittedColumn, 0) for _, column := range receipt.EmittedColumns { - if column.OutputID == request.OutputID { + if column.OutputID == request.OutputId { columns = append(columns, column) } } var encoded []byte if capabilities.PreviewReceipt != nil { - encoder, encoderErr := newPreviewResponseEncoder(receipt, request.OutputID, columns, maxExplorerPreviewResponseBytes) + encoder, encoderErr := newPreviewResponseEncoder(receipt, request.OutputId, columns, maxExplorerPreviewResponseBytes) if encoderErr != nil { return previewRouteFailure(c, encoderErr) } @@ -294,8 +328,8 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth var rows map[string][]map[string]any rows, err = capabilities.Preview(previewCtx, receipt.Bundle, bindings) if err == nil { - responseRows = len(rows[request.OutputID]) - encoded, err = encodeExplorerPreviewResponse(receipt, request.OutputID, columns, rows[request.OutputID], maxExplorerPreviewResponseBytes) + responseRows = len(rows[request.OutputId]) + encoded, err = encodeExplorerPreviewResponse(receipt, request.OutputId, columns, rows[request.OutputId], maxExplorerPreviewResponseBytes) } } if err != nil { @@ -311,10 +345,8 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth if err := authoringWrite(c, authorizer); err != nil { return err } - var request struct { - ReceiptID string `json:"receiptId"` - } - if err := decodeAuthoringStrict(c.Body(), &request); err != nil || strings.TrimSpace(request.ReceiptID) == "" { + var request explorerv2api.PublishRequest + if err := decodeAuthoringStrict(c.Body(), &request); err != nil || strings.TrimSpace(request.ReceiptId) == "" { if err == nil { err = fmt.Errorf("receiptId is required") } @@ -323,7 +355,7 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth if (capabilities.Materialize == nil && capabilities.MaterializeReceipt == nil) || capabilities.ActivateRelease == nil || capabilities.ValidateReleaseGeneration == nil || (capabilities.CapabilityToken == nil && capabilities.AuthorizedCapabilityExecution == nil) { return authoringHTTPError(c, explorerUnavailable("publish", "PUBLICATION_UNAVAILABLE", "Explorer publication is not configured")) } - receipt, err := lookupV2Receipt(c.Context(), explorers, capabilities, explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")), request.ReceiptID) + receipt, err := lookupV2Receipt(c.Context(), explorers, capabilities, explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")), request.ReceiptId) if err != nil { return authoringHTTPError(c, receiptRouteError("publish", err)) } @@ -339,18 +371,27 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth snapshot, err = capabilities.CapabilityToken(c.Context(), receipt.Project, receipt.SnapshotToken) } if err != nil || strings.TrimSpace(snapshot.Identity.Generation) != strings.TrimSpace(receipt.SourceGeneration) { - return authoringHTTPError(c, explorerConflict("publish", "RECEIPT_INPUT_UNAVAILABLE", "the receipt's capability snapshot is no longer authorized or retained", nil)) + return authoringHTTPError(c, explorerConflict("publish", "RECEIPT_STALE", "the receipt's capability snapshot is no longer authorized or retained", nil)) } if capabilities.CompileReceipt != nil { if err := validateReceiptCapability(receipt, snapshot); err != nil { - return authoringHTTPError(c, explorerConflict("publish", "RECEIPT_INPUT_UNAVAILABLE", err.Error(), nil)) + return authoringHTTPError(c, explorerConflict("publish", "RECEIPT_STALE", err.Error(), nil)) } } if len(receipt.EmittedColumns) == 0 || len(receipt.CompiledConfig) == 0 { return authoringHTTPError(c, authoringSemanticRoute("publish", "$.receiptId", "NO_SELECTED_COLUMNS", "select at least one output column before publishing", nil)) } + if capabilities.CompileReceipt != nil { + workspace, decodeErr := authoringv2.DecodeWorkspace(receipt.NormalizedBundle) + if decodeErr != nil { + return authoringHTTPError(c, explorerConflict("publish", "RECEIPT_RECOMPILE_REQUIRED", "the compilation receipt contains invalid authoring intent", nil)) + } + if err := workspace.ValidateForPublication(); err != nil { + return authoringHTTPError(c, authoringSemanticRoute("publish", "$.receiptId", "NO_SELECTED_COLUMNS", "select at least one visible output column for every visible table before publishing", nil)) + } + } if err := capabilities.ValidateReleaseGeneration(c.Context(), projectid.Legacy(receipt.Project), receipt.SourceGeneration); err != nil { - return authoringHTTPError(c, explorerConflict("publish", "RECEIPT_INPUT_UNAVAILABLE", "the receipt generation is no longer active", map[string]any{"generation": receipt.SourceGeneration})) + return authoringHTTPError(c, explorerConflict("publish", "RECEIPT_STALE", "the receipt generation is no longer active", map[string]any{"generation": receipt.SourceGeneration})) } bindings := recipe.RuntimeBindings{Project: projectid.Legacy(receipt.Project), DatasetGeneration: receipt.SourceGeneration} applyAuthorizedScope(&bindings, authorized, true) @@ -375,13 +416,25 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth if err != nil { return authoringHTTPError(c, err) } - return c.JSON(fiber.Map{"apiVersion": authoringv2.APIVersion, "kind": "ExplorerPublishResult", "receiptId": receipt.ID, "revisionId": revision.ID, "state": revision.Status, "sourceGeneration": revision.SourceGeneration}) + outputs := make([]explorerv2api.PublicationOutput, 0, len(revision.Materializations)) + for _, materialization := range revision.Materializations { + outputs = append(outputs, explorerv2api.PublicationOutput{OutputId: firstNonEmpty(materialization.OutputID, materialization.Output), State: "READY", MaterializationId: materialization.MaterializationID}) + } + return c.JSON(explorerv2api.PublishResponse{ + ApiVersion: explorerv2api.LoomCalyprOrgexplorerAuthoringv2, + Kind: explorerv2api.ExplorerBuilderPublication, + ReceiptId: receipt.ID, + RevisionId: revision.ID, + State: string(revision.Status), + Outputs: outputs, + Diagnostics: []explorerv2api.Diagnostic{}, + }) }) } func validateV2ReceiptRoute(c fiber.Ctx, receipt *explorer.CompilationReceipt, capabilities ExplorerV2LifecycleConfig) error { if receipt == nil || receipt.Project != explorerProjectParam(c) || receipt.ExplorerID != strings.TrimSpace(c.Params("explorerId")) { - return &explorer.AuthoringError{Status: http.StatusNotFound, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "receipt", Code: "RECEIPT_NOT_FOUND", Message: "compilation receipt was not found"}} + return &explorer.AuthoringError{Status: http.StatusNotFound, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "receipt", Code: "COMPILE_RECEIPT_NOT_FOUND", Message: "compilation receipt was not found"}} } if strings.TrimSpace(receipt.ID) == "" || strings.TrimSpace(receipt.RecipeDigest) == "" || len(receipt.Bundle.Outputs) == 0 { return explorerConflict("receipt", "RECEIPT_RECOMPILE_REQUIRED", "the compilation receipt is from an unsupported or incomplete compiler contract", nil) @@ -410,7 +463,7 @@ func lookupV2Receipt(ctx context.Context, explorers *explorer.Service, capabilit func receiptRouteError(stage string, err error) error { if errors.Is(err, explorer.ErrNotFound) { - return &explorer.AuthoringError{Status: http.StatusNotFound, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: "RECEIPT_NOT_FOUND", Message: "compilation receipt was not found"}} + return &explorer.AuthoringError{Status: http.StatusNotFound, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: "COMPILE_RECEIPT_NOT_FOUND", Message: "compilation receipt was not found"}} } if errors.Is(err, explorer.ErrReceiptRecompileRequired) { return explorerConflict(stage, "RECEIPT_RECOMPILE_REQUIRED", "the compilation receipt is from an unsupported compiler contract", nil) @@ -418,6 +471,50 @@ func receiptRouteError(stage string, err error) error { return explorerUnavailable(stage, "RECEIPT_STORE_UNAVAILABLE", "the compilation receipt store is unavailable") } +func workspaceValidationCode(err error) string { + message := err.Error() + for _, code := range []string{"DUPLICATE_OUTPUT_ID", "DUPLICATE_TAB_ID", "INVALID_TAB_OUTPUT_MAPPING", "INVALID_TAB_ORDER", "ROW_ROOT_NOT_ELIGIBLE", "UNSUPPORTED_FILTER", "UNSUPPORTED_CHART", "NO_VISIBLE_COLUMNS"} { + if strings.Contains(message, code) { + return code + } + } + switch { + case strings.Contains(message, "rootNodeId"): + return "INVALID_ROOT_NODE" + case strings.Contains(message, "route") || strings.Contains(message, "edge"): + return "INVALID_ROUTE" + case strings.Contains(message, "occurrence"): + return "INVALID_OCCURRENCE" + case strings.Contains(message, "projection mode"): + return "INVALID_PROJECTION_MODE" + case strings.Contains(message, "duplicate selection"): + return "DUPLICATE_SELECTION" + default: + return "INVALID_AUTHORING_INTENT" + } +} + +func compilationErrorCode(code string) string { + switch code { + case "STALE_ROOT_NODE": + return "INVALID_ROOT_NODE" + case "ROOT_NOT_ELIGIBLE", "UNSUPPORTED_ROW_ROOT": + return "ROW_ROOT_NOT_ELIGIBLE" + case "STALE_EDGE": + return "STALE_EDGE_ID" + case "DISCONNECTED_ROUTE", "REPEATED_EDGE_NOT_ALLOWED", "SELF_LOOP_NOT_ALLOWED", "ROUTE_TOO_LONG": + return "INVALID_ROUTE" + case "STALE_CANDIDATE": + return "STALE_CANDIDATE_ID" + case "STALE_OCCURRENCE", "DUPLICATE_OCCURRENCE": + return "INVALID_OCCURRENCE" + case "UNSUPPORTED_PROJECTION_MODE": + return "INVALID_PROJECTION_MODE" + default: + return code + } +} + func applyAuthorizedScope(bindings *recipe.RuntimeBindings, authorized AuthorizedCapability, includeAuthResourcePath bool) { if bindings == nil { return @@ -462,6 +559,91 @@ func authoringV2Bundle(project, explorerID string, document authoringv2.Document return explorer.ExplorerAuthoringBundleV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, Project: projectid.Canonical(project), ExplorerID: explorerID, Title: document.Output.Title, Documents: []explorer.ExplorerBuilderDocumentV1{v1}, Tabs: []explorer.ExplorerTabV1{}}, nil } +func authoringV2WorkspaceBundle(project, explorerID string, workspace authoringv2.Workspace, catalog authoringv2.CatalogSnapshot) (explorer.ExplorerAuthoringBundleV1, error) { + result := explorer.ExplorerAuthoringBundleV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, Project: projectid.Canonical(project), ExplorerID: explorerID, Documents: []explorer.ExplorerBuilderDocumentV1{}, Tabs: []explorer.ExplorerTabV1{}} + for _, document := range workspace.Documents { + one, err := authoringV2Bundle(project, explorerID, document, catalog) + if err != nil { + return result, err + } + result.Documents = append(result.Documents, one.Documents...) + } + for _, tab := range workspace.Tabs { + visible := tab.Visible + result.Tabs = append(result.Tabs, explorer.ExplorerTabV1{ID: tab.ID, Title: tab.Title, OutputID: tab.OutputID, Order: tab.Order, Visible: &visible}) + } + return result, nil +} + +func migrateV1WorkspaceToCapability(bundle explorer.ExplorerAuthoringBundleV1, snapshot capability.Snapshot, wire authoringv2.CatalogSnapshot, emitted []explorer.EmittedColumn) (authoringv2.Workspace, error) { + workspace := authoringv2.Workspace{APIVersion: authoringv2.APIVersion, Kind: authoringv2.WorkspaceKind, Documents: []authoringv2.Document{}, Tabs: []authoringv2.Tab{}} + for i, input := range bundle.AuthoringDocuments() { + if len(input.Presentation) > 0 { + mapped := make(map[string]explorer.ExplorerPresentationBindingV1, len(input.Presentation)) + for key, binding := range input.Presentation { + mappedKey := key + for _, emission := range emitted { + if emission.OutputID == input.Output.ID && emission.EmissionID == key { + mappedKey = emission.CandidateID + "\x00" + emission.OccurrenceID + break + } + } + mapped[mappedKey] = binding + } + input.Presentation = mapped + } + document, err := migrateV1DocumentToCapability(input, snapshot, wire) + if err != nil { + return workspace, fmt.Errorf("documents[%d]: %w", i, err) + } + workspace.Documents = append(workspace.Documents, document) + } + for _, input := range bundle.AuthoringTabs() { + visible := true + if input.Visible != nil { + visible = *input.Visible + } + workspace.Tabs = append(workspace.Tabs, authoringv2.Tab{ID: input.ID, Title: input.Title, OutputID: input.OutputID, Order: input.Order, Visible: visible}) + } + if err := (authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, Workspace: &workspace, Catalog: wire}).Validate(); err != nil { + return workspace, err + } + return workspace, nil +} + +func v2ReceiptResponse(receipt *explorer.CompilationReceipt, workspace authoringv2.Workspace) explorerv2api.CompileResponse { + outputs := make([]explorerv2api.ReceiptOutput, 0, len(workspace.Documents)) + for _, document := range workspace.Documents { + rowGrain := "" + for _, output := range receipt.Bundle.Outputs { + if output.Name == document.Output.ID { + rowGrain = output.RowGrain + break + } + } + emissions := []explorerv2api.Emission{} + for _, column := range receipt.EmittedColumns { + if column.OutputID != document.Output.ID { + continue + } + mode, label := column.ProjectionMode, column.Label + if label == "" { + label = column.PublicColumn + } + emissions = append(emissions, explorerv2api.Emission{OutputId: column.OutputID, CandidateId: column.CandidateID, OccurrenceId: column.OccurrenceID, ProjectionMode: mode, EmissionId: column.EmissionID, PublicColumn: column.PublicColumn, Label: label, LogicalType: column.LogicalType, Filterable: column.Filterable, Chartable: column.Chartable}) + } + outputs = append(outputs, explorerv2api.ReceiptOutput{OutputId: document.Output.ID, Title: document.Output.Title, RowGrain: rowGrain, Emissions: emissions}) + } + return explorerv2api.CompileResponse{ + ApiVersion: explorerv2api.LoomCalyprOrgexplorerAuthoringv2, + Kind: explorerv2api.ExplorerBuilderReceipt, + ReceiptId: receipt.ID, SnapshotToken: receipt.SnapshotToken, + Generation: receipt.SourceGeneration, IntentDigest: receipt.IntentDigest, + CompilerVersion: "explorer-authoring-v2", Builder: workspace, + Outputs: outputs, Diagnostics: []explorerv2api.Diagnostic{}, + } +} + func migrateV1DocumentToCapability(input explorer.ExplorerBuilderDocumentV1, snapshot capability.Snapshot, wire authoringv2.CatalogSnapshot) (authoringv2.Document, error) { nodeIDs := map[string]string{} for _, node := range snapshot.Nodes { @@ -487,6 +669,7 @@ func migrateV1DocumentToCapability(input explorer.ExplorerBuilderDocumentV1, sna title = input.Output.ID } document := authoringv2.Document{APIVersion: authoringv2.APIVersion, Kind: authoringv2.Kind, Output: authoringv2.Output{ID: input.Output.ID, Title: title}, RootNodeID: root, RouteSteps: []authoringv2.RouteStep{}, Selections: []authoringv2.Selection{}, Presentation: map[string]authoringv2.Presentation{}} + document.APIVersion = "" for i, oldEdgeID := range input.RouteEdgeIDs { edgeID := edgeIDs[oldEdgeID] if edgeID == "" { @@ -506,10 +689,33 @@ func migrateV1DocumentToCapability(input explorer.ExplorerBuilderDocumentV1, sna for _, candidate := range wire.Candidates { candidates[candidate.ID] = candidate } - for _, reference := range input.CandidateOccurrences { + references := append([]explorer.ExplorerCandidateOccurrenceV1(nil), input.CandidateOccurrences...) + if len(references) == 0 { + occurrences, err := document.Occurrences(wire) + if err != nil { + return authoringv2.Document{}, err + } + for _, oldCandidateID := range input.CandidateIDs { + candidateID := candidateIDs[oldCandidateID] + if candidateID == "" { + return authoringv2.Document{}, fmt.Errorf("stored candidate %q is not present in the current capability snapshot", oldCandidateID) + } + matches := []string{} + for _, occurrence := range occurrences { + if occurrence.NodeID == candidates[candidateID].NodeID { + matches = append(matches, occurrence.ID) + } + } + if len(matches) != 1 { + return authoringv2.Document{}, fmt.Errorf("stored candidate %q cannot be mapped to exactly one route occurrence", oldCandidateID) + } + references = append(references, explorer.ExplorerCandidateOccurrenceV1{CandidateID: oldCandidateID, OccurrenceID: matches[0]}) + } + } + for _, reference := range references { candidateID := candidateIDs[reference.CandidateID] if candidateID == "" { - continue + return authoringv2.Document{}, fmt.Errorf("stored candidate %q is not present in the current capability snapshot", reference.CandidateID) } mode := reference.ProjectionMode if mode == "" || !containsString(candidates[candidateID].ProjectionModes, mode) { @@ -517,8 +723,70 @@ func migrateV1DocumentToCapability(input explorer.ExplorerBuilderDocumentV1, sna } document.Selections = append(document.Selections, authoringv2.Selection{CandidateID: candidateID, OccurrenceID: reference.OccurrenceID, ProjectionMode: mode}) } + for oldKey, binding := range input.Presentation { + matchedKey := "" + for _, selection := range document.Selections { + occurrence := selection.OccurrenceID + if occurrence == "" { + occurrence = authoringv2.RootOccurrenceID + if len(document.RouteSteps) > 0 { + occurrence = authoringv2.DerivedOccurrenceID(len(document.RouteSteps) - 1) + } + } + newKey := authoringv2.PresentationKey(selection.CandidateID, occurrence, selection.ProjectionMode) + if !legacyPresentationKeyMatches(oldKey, input.Output.ID, selection.CandidateID, occurrence, newKey, references, candidateIDs) { + continue + } + if matchedKey != "" && matchedKey != newKey { + return authoringv2.Document{}, fmt.Errorf("stored presentation %q maps to more than one selection", oldKey) + } + matchedKey = newKey + } + if matchedKey == "" { + return authoringv2.Document{}, fmt.Errorf("stored presentation %q cannot be mapped exactly", oldKey) + } + if _, exists := document.Presentation[matchedKey]; exists { + return authoringv2.Document{}, fmt.Errorf("multiple stored presentations map to selection %q", matchedKey) + } + presentation := authoringv2.Presentation{Label: binding.Label, Visible: binding.Visible, Order: binding.Order} + if binding.Table != nil { + presentation.Table = &authoringv2.TablePresentation{Pinned: binding.Table.Pinned} + } + if binding.Filter != nil { + presentation.Filter = &authoringv2.FilterPresentation{Label: binding.Filter.Label} + } + if binding.Chart != nil { + presentation.Chart = &authoringv2.ChartPresentation{Type: binding.Chart.Type, Title: binding.Chart.Title} + } + document.Presentation[matchedKey] = presentation + } if err := (authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, Document: &document, Catalog: wire}).Validate(); err != nil { return authoringv2.Document{}, err } return document, nil } + +func legacyPresentationKeyMatches(oldKey, outputID, currentCandidateID, occurrenceID, newKey string, references []explorer.ExplorerCandidateOccurrenceV1, ids map[string]string) bool { + aliases := map[string]bool{ + currentCandidateID: true, + currentCandidateID + "\x00" + occurrenceID: true, + explorer.OpaqueID("em_", outputID+"\x00"+occurrenceID+"\x00"+currentCandidateID): true, + newKey: true, + } + for _, reference := range references { + if ids[reference.CandidateID] != currentCandidateID { + continue + } + referenceOccurrence := reference.OccurrenceID + if referenceOccurrence == "" { + referenceOccurrence = occurrenceID + } + if referenceOccurrence != occurrenceID { + continue + } + aliases[reference.CandidateID] = true + aliases[reference.CandidateID+"\x00"+occurrenceID] = true + aliases[explorer.OpaqueID("em_", outputID+"\x00"+occurrenceID+"\x00"+reference.CandidateID)] = true + } + return aliases[oldKey] || ids[oldKey] == currentCandidateID +} diff --git a/internal/server/explorer_capability.go b/internal/server/explorer_capability.go index 850aee58..67676610 100644 --- a/internal/server/explorer_capability.go +++ b/internal/server/explorer_capability.go @@ -493,14 +493,14 @@ func authoringV2Catalog(snapshot capability.Snapshot, explorerID string) authori }) } for _, edge := range snapshot.Edges { - result.Edges = append(result.Edges, authoringv2.CatalogEdge{ID: edge.ID, FromNodeID: edge.FromNodeID, ToNodeID: edge.ToNodeID, Label: edge.Label}) + result.Edges = append(result.Edges, authoringv2.CatalogEdge{ID: edge.ID, FromNodeID: edge.FromNodeID, ToNodeID: edge.ToNodeID, Label: edge.Label, Populated: edge.ObservedEdgeCount > 0}) } for _, candidate := range snapshot.Candidates { projectionModes := stringProjectionModes(candidate.ProjectionModes) count := candidate.ObservedDocumentCount wire := authoringv2.CatalogCandidate{ ID: candidate.ID, NodeID: candidate.NodeID, Label: candidate.Label, - LogicalType: candidate.LogicalType, Cardinality: candidate.Cardinality, + LogicalType: candidate.LogicalType, Cardinality: candidate.Cardinality, Repeated: candidate.Cardinality != "scalar", Filterable: len(candidate.FilterOperators) > 0, Chartable: len(candidate.ChartAggregations) > 0, ProjectionModes: projectionModes, DefaultProjectionMode: defaultProjectionMode(projectionModes), FilterOperators: stringFilterOperators(candidate.FilterOperators), ChartOperations: stringChartOperations(candidate.ChartAggregations), @@ -525,7 +525,14 @@ func authoringV2Catalog(snapshot capability.Snapshot, explorerID string) authori func stringProjectionModes(values []capability.ProjectionMode) []string { out := make([]string, len(values)) for i, value := range values { - out[i] = string(value) + switch value { + case capability.ProjectionScalar: + out[i] = "VALUE" + case capability.ProjectionArray, capability.ProjectionDistinctArray: + out[i] = "ALL" + default: + out[i] = string(value) + } } return out } @@ -544,7 +551,7 @@ func stringChartOperations(values []capability.ChartAggregation) []string { return out } func defaultProjectionMode(values []string) string { - for _, preferred := range []string{string(capability.ProjectionScalar), string(capability.ProjectionFirst), string(capability.ProjectionArray), string(capability.ProjectionDistinctArray)} { + for _, preferred := range []string{"VALUE", "FIRST", "ALL", "COUNT"} { for _, value := range values { if value == preferred { return value diff --git a/internal/server/explorer_capability_test.go b/internal/server/explorer_capability_test.go index 2ccffd02..ef076dc5 100644 --- a/internal/server/explorer_capability_test.go +++ b/internal/server/explorer_capability_test.go @@ -282,7 +282,7 @@ func TestExplorerAuthoringV2HardCutCompilesAndPreviewsReceipt(t *testing.T) { if suggestions.StatusCode != http.StatusOK || !strings.Contains(suggestions.Body, `"patient-1"`) { t.Fatalf("candidate suggestions status=%d body=%s", suggestions.StatusCode, suggestions.Body) } - body := `{"document":{"apiVersion":"` + authoringv2.APIVersion + `","kind":"` + authoringv2.Kind + `","output":{"id":"patients","title":"Patients"},"rootNodeId":"n_patient","routeSteps":[],"selections":[{"candidateId":"c_patient_id","occurrenceId":"base","projectionMode":"FIRST"}],"presentation":{}},"snapshotToken":"` + snapshot.Token + `"}` + body := `{"workspace":{"apiVersion":"` + authoringv2.APIVersion + `","kind":"` + authoringv2.WorkspaceKind + `","documents":[{"kind":"` + authoringv2.Kind + `","output":{"id":"patients","title":"Patients"},"rootNodeId":"n_patient","routeSteps":[],"selections":[{"candidateId":"c_patient_id","occurrenceId":"base","projectionMode":"FIRST"}],"presentation":{}}],"tabs":[{"id":"patients-tab","title":"Patients","outputId":"patients","order":0,"visible":true}]},"snapshotToken":"` + snapshot.Token + `"}` compiled := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/builder", body) if compiled.StatusCode != http.StatusOK { t.Fatalf("POST builder status=%d body=%s", compiled.StatusCode, compiled.Body) diff --git a/internal/server/explorer_preview_response.go b/internal/server/explorer_preview_response.go index 126b4fb4..56b00ee3 100644 --- a/internal/server/explorer_preview_response.go +++ b/internal/server/explorer_preview_response.go @@ -6,8 +6,10 @@ import ( "encoding/json" "errors" "fmt" + "net/http" "time" + explorerv2api "github.com/calypr/loom/generated/explorerv2" dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" "github.com/calypr/loom/internal/explorer" "github.com/gofiber/fiber/v3" @@ -27,7 +29,7 @@ func (e *receiptPreviewResolutionError) Unwrap() error { return e.Err } func previewRouteFailure(c fiber.Ctx, err error) error { if errors.Is(err, ErrPreviewResponseTooLarge) { - return authoringHTTPError(c, &explorer.AuthoringError{Status: 413, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "preview", Code: "PREVIEW_RESPONSE_TOO_LARGE", Message: "preview response exceeds the maximum size"}, Cause: err}) + return authoringHTTPError(c, &explorer.AuthoringError{Status: 413, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "preview", Code: "RESPONSE_TOO_LARGE", Message: "preview response exceeds the maximum size"}, Cause: err}) } if errors.Is(err, context.DeadlineExceeded) { return authoringHTTPError(c, &explorer.AuthoringError{Status: 504, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "preview", Code: "PREVIEW_TIMEOUT", Message: "preview exceeded its execution deadline"}, Cause: err}) @@ -48,21 +50,54 @@ func previewRouteFailure(c fiber.Ctx, err error) error { case string(dataframeerrors.CodeBackendUnavailable), string(dataframeerrors.CodeReceiptStoreUnavailable): return authoringHTTPError(c, &explorer.AuthoringError{Status: 503, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "preview", Code: userErr.Code(), Message: dataframeerrors.PublicMessage(err)}, Cause: err}) case string(dataframeerrors.CodeRecipeContractViolation), string(dataframeerrors.CodeDynamicSchemaDrift): - return authoringHTTPError(c, explorerConflict("preview", "RECEIPT_RECOMPILE_REQUIRED", "receipt deterministic lowering no longer matches the stored artifact", nil)) + return authoringHTTPError(c, receiptPreviewConflict(err)) default: return authoringHTTPError(c, &explorer.AuthoringError{Status: 500, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "preview", Code: "PREVIEW_FAILED", Message: "receipt preview failed"}, Cause: err}) } } if errors.As(err, new(*receiptPreviewResolutionError)) { - return authoringHTTPError(c, explorerConflict("preview", "RECEIPT_RECOMPILE_REQUIRED", "receipt deterministic lowering no longer matches the stored artifact", nil)) + return authoringHTTPError(c, receiptPreviewConflict(err)) } return authoringHTTPError(c, &explorer.AuthoringError{Status: 500, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "preview", Code: "PREVIEW_FAILED", Message: "receipt preview failed"}, Cause: err}) } +func receiptPreviewConflict(cause error) error { + return &explorer.AuthoringError{ + Status: http.StatusConflict, + Diagnostic: explorer.AuthoringDiagnostic{ + Severity: "ERROR", + Stage: "preview", + Code: "RECEIPT_RECOMPILE_REQUIRED", + Message: "receipt deterministic lowering no longer matches the stored artifact", + }, + Cause: cause, + } +} + type previewResponseTooLargeError struct { Limit int } +type v2EmissionWire = explorerv2api.Emission + +func v2EmissionColumns(columns []explorer.EmittedColumn) []v2EmissionWire { + out := make([]v2EmissionWire, 0, len(columns)) + for _, column := range columns { + label := column.Label + if label == "" { + label = column.PublicColumn + } + out = append(out, v2EmissionWire{ + OutputId: column.OutputID, CandidateId: column.CandidateID, + OccurrenceId: column.OccurrenceID, ProjectionMode: column.ProjectionMode, + EmissionId: column.EmissionID, PublicColumn: column.PublicColumn, + Label: label, LogicalType: column.LogicalType, + Filterable: column.Filterable, Chartable: column.Chartable, + }) + } + return out +} + func (e *previewResponseTooLargeError) Error() string { if e == nil || e.Limit <= 0 { return ErrPreviewResponseTooLarge.Error() @@ -94,7 +129,7 @@ func encodeExplorerPreviewResponse(receipt *explorer.CompilationReceipt, outputI } return write(raw) } - if err := write([]byte(`{"apiVersion":"loom.calypr.org/explorer-authoring/v2","kind":"ExplorerPreviewResult","receiptId":`)); err != nil { + if err := write([]byte(`{"apiVersion":"loom.calypr.org/explorer-authoring/v2","kind":"ExplorerBuilderPreview","receiptId":`)); err != nil { return nil, err } if err := writeString(receipt.ID); err != nil { @@ -106,7 +141,7 @@ func encodeExplorerPreviewResponse(receipt *explorer.CompilationReceipt, outputI if err := writeString(outputID); err != nil { return nil, err } - encodedColumns, err := json.Marshal(columns) + encodedColumns, err := json.Marshal(v2EmissionColumns(columns)) if err != nil { return nil, err } @@ -143,7 +178,7 @@ func encodeExplorerPreviewResponse(receipt *explorer.CompilationReceipt, outputI if err := write(count); err != nil { return nil, err } - if err := write([]byte("}")); err != nil { + if err := write([]byte(`,"diagnostics":[]}`)); err != nil { return nil, err } return out.Bytes(), nil @@ -162,7 +197,7 @@ func newPreviewResponseEncoder(receipt *explorer.CompilationReceipt, outputID st encoder := &previewResponseEncoder{firstRow: true} encoder.out.limit = limit write := func(raw []byte) error { _, err := encoder.out.Write(raw); return err } - if err := write([]byte(`{"apiVersion":"loom.calypr.org/explorer-authoring/v2","kind":"ExplorerPreviewResult","receiptId":`)); err != nil { + if err := write([]byte(`{"apiVersion":"loom.calypr.org/explorer-authoring/v2","kind":"ExplorerBuilderPreview","receiptId":`)); err != nil { return nil, err } receiptID, err := json.Marshal(receipt.ID) @@ -182,7 +217,7 @@ func newPreviewResponseEncoder(receipt *explorer.CompilationReceipt, outputID st if err := write(outputRaw); err != nil { return nil, err } - encodedColumns, err := json.Marshal(columns) + encodedColumns, err := json.Marshal(v2EmissionColumns(columns)) if err != nil { return nil, err } @@ -230,7 +265,7 @@ func (e *previewResponseEncoder) Finish() ([]byte, error) { if _, err := e.out.Write(count); err != nil { return nil, err } - if _, err := e.out.Write([]byte("}")); err != nil { + if _, err := e.out.Write([]byte(`,"diagnostics":[]}`)); err != nil { return nil, err } return e.out.Bytes(), nil diff --git a/internal/server/explorer_preview_response_test.go b/internal/server/explorer_preview_response_test.go index 384c1dea..3e6cb85f 100644 --- a/internal/server/explorer_preview_response_test.go +++ b/internal/server/explorer_preview_response_test.go @@ -65,7 +65,7 @@ func TestPreviewRouteFailurePreservesStableClassifications(t *testing.T) { }{ {"timeout", context.DeadlineExceeded, http.StatusGatewayTimeout, "PREVIEW_TIMEOUT"}, {"canceled", context.Canceled, 499, "CLIENT_CANCELED"}, - {"oversized", &previewResponseTooLargeError{Limit: 32}, http.StatusRequestEntityTooLarge, "PREVIEW_RESPONSE_TOO_LARGE"}, + {"oversized", &previewResponseTooLargeError{Limit: 32}, http.StatusRequestEntityTooLarge, "RESPONSE_TOO_LARGE"}, {"plan", dataframeerrors.NewError(dataframeerrors.CodePlanTooExpensive, "private"), http.StatusTooManyRequests, "PLAN_TOO_EXPENSIVE"}, {"backend", dataframeerrors.NewError(dataframeerrors.CodeBackendUnavailable, "private", dataframeerrors.WithRetryable(true)), http.StatusServiceUnavailable, "BACKEND_UNAVAILABLE"}, {"receipt", &receiptPreviewResolutionError{Err: errors.New("private")}, http.StatusConflict, "RECEIPT_RECOMPILE_REQUIRED"}, diff --git a/internal/server/explorer_preview_security.go b/internal/server/explorer_preview_security.go index ba8ae29a..51103a91 100644 --- a/internal/server/explorer_preview_security.go +++ b/internal/server/explorer_preview_security.go @@ -1,7 +1,6 @@ package server import ( - "encoding/json" "errors" "fmt" "strings" @@ -82,13 +81,11 @@ func validateReceiptOutputContract(receipt *explorer.CompilationReceipt, outputI if outputID == "" { return receiptExecutionContractError("output is required") } - var contract struct { - OutputID string `json:"outputId"` - } - if err := json.Unmarshal(receipt.PublicOutputContract, &contract); err != nil { + contract, err := explorer.DecodePublicOutputContracts(receipt.PublicOutputContract) + if err != nil { return receiptExecutionContractError("public output contract is invalid: %v", err) } - if strings.TrimSpace(contract.OutputID) != outputID { + if _, ok := contract.Output(outputID); !ok { return receiptExecutionContractError("requested output %q is not in the receipt public contract", outputID) } for _, output := range receipt.Bundle.Outputs { diff --git a/internal/server/explorer_preview_security_test.go b/internal/server/explorer_preview_security_test.go index 9039af97..13cab928 100644 --- a/internal/server/explorer_preview_security_test.go +++ b/internal/server/explorer_preview_security_test.go @@ -74,11 +74,24 @@ func TestValidateReceiptOutputContract(t *testing.T) { if err := validateReceiptOutputContract(receipt, "patients"); err != nil { t.Fatal(err) } + contracts, err := explorer.DecodePublicOutputContracts(receipt.PublicOutputContract) + if err != nil { + t.Fatal(err) + } + contracts.Outputs = append(contracts.Outputs, explorer.PublicOutputContract{OutputID: "specimens", Columns: []explorer.PublicOutputColumn{}}) + receipt.PublicOutputContract, err = json.Marshal(contracts) + if err != nil { + t.Fatal(err) + } + receipt.Bundle.Outputs = append(receipt.Bundle.Outputs, recipe.Output{Name: "specimens", RootResourceType: "Specimen", RowGrain: "resource"}) + if err := validateReceiptOutputContract(receipt, "specimens"); err != nil { + t.Fatal(err) + } if err := validateReceiptOutputContract(receipt, "observations"); !errors.Is(err, ErrReceiptExecutionContract) { t.Fatalf("unknown output error=%v, want contract mismatch", err) } malformed := *receipt - malformed.PublicOutputContract = json.RawMessage(`{"outputId":"observations"}`) + malformed.PublicOutputContract = json.RawMessage(`{"outputs":[{"outputId":"observations","columns":[]}]}`) if err := validateReceiptOutputContract(&malformed, "patients"); !errors.Is(err, ErrReceiptExecutionContract) { t.Fatalf("forged output contract error=%v, want contract mismatch", err) } @@ -109,14 +122,14 @@ func testSecurityReceipt(t *testing.T, snapshot capability.Snapshot, output stri t.Helper() fields := make([]recipe.Field, 0, len(columns)) emitted := make([]explorer.EmittedColumn, 0, len(columns)) - contractColumns := make([]map[string]string, 0, len(columns)) + contractColumns := make([]explorer.PublicOutputColumn, 0, len(columns)) for _, column := range columns { fields = append(fields, recipe.Field{Name: column, Expr: recipe.Expression{Select: "root." + column}}) - emitted = append(emitted, explorer.EmittedColumn{EmissionID: "em_" + column, OutputID: output, PublicColumn: column, LogicalType: "string"}) - contractColumns = append(contractColumns, map[string]string{"publicColumn": column}) + emitted = append(emitted, explorer.EmittedColumn{EmissionID: "em_" + column, OutputID: output, CandidateID: "c_" + column, OccurrenceID: "base", ProjectionMode: "VALUE", PublicColumn: column, Label: column, LogicalType: "string"}) + contractColumns = append(contractColumns, explorer.PublicOutputColumn{EmissionID: "em_" + column, PublicColumn: column, CandidateID: "c_" + column, OccurrenceID: "base", ProjectionMode: "VALUE", Label: column, LogicalType: "string"}) } bundle := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "security", TranslationVersion: "test", Outputs: []recipe.Output{{Name: output, RootResourceType: "Patient", RowGrain: "resource", Fields: fields}}} - contract, err := json.Marshal(map[string]any{"outputId": output, "columns": contractColumns}) + contract, err := json.Marshal(explorer.PublicOutputContracts{Outputs: []explorer.PublicOutputContract{{OutputID: output, Columns: contractColumns}}}) if err != nil { t.Fatal(err) } diff --git a/internal/server/explorer_receipt_contract.go b/internal/server/explorer_receipt_contract.go index 0dab6c76..4c14a612 100644 --- a/internal/server/explorer_receipt_contract.go +++ b/internal/server/explorer_receipt_contract.go @@ -1,6 +1,7 @@ package server import ( + "context" "crypto/sha256" "encoding/hex" "encoding/json" @@ -8,8 +9,10 @@ import ( "sort" "strings" + "github.com/calypr/loom/internal/dataframe/recipe" "github.com/calypr/loom/internal/dataframe/recipe/engine" "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/explorer/authoringv2" "github.com/calypr/loom/internal/explorer/capability" explorercompilation "github.com/calypr/loom/internal/explorer/compilation" "github.com/calypr/loom/internal/projectid" @@ -57,6 +60,56 @@ func compiledExplorerConfigV2(project, explorerID string, compiled explorercompi return json.Marshal(config) } +func compiledExplorerWorkspaceConfigV2(project, explorerID string, compiled explorercompilation.WorkspaceResult) ([]byte, error) { + if len(compiled.EmittedColumns) == 0 { + return nil, nil + } + recipeJSON, err := json.Marshal(compiled.Bundle) + if err != nil { + return nil, err + } + byOutput := map[string]explorercompilation.PresentationConfig{} + for _, presentation := range compiled.Presentations { + byOutput[presentation.OutputID] = presentation + } + tabs := append([]authoringv2.Tab(nil), compiled.Workspace.Tabs...) + sort.SliceStable(tabs, func(i, j int) bool { return tabs[i].Order < tabs[j].Order }) + views := make([]explorer.ConfigView, 0, len(tabs)) + for _, tab := range tabs { + if !tab.Visible { + continue + } + presentation, ok := byOutput[tab.OutputID] + if !ok { + return nil, fmt.Errorf("missing compiled output %q", tab.OutputID) + } + columns := append([]explorercompilation.PresentationColumn(nil), presentation.Columns...) + sort.SliceStable(columns, func(i, j int) bool { + if columns[i].Order != columns[j].Order { + return columns[i].Order < columns[j].Order + } + return columns[i].EmissionID < columns[j].EmissionID + }) + view := explorer.ConfigView{ID: tab.ID, Title: tab.Title, Output: tab.OutputID, Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{}}} + for _, column := range columns { + view.Table.Columns = append(view.Table.Columns, explorer.ConfigColumn{Column: column.PublicColumn, Label: column.Label, Visible: column.Visible, Pinned: column.Pinned}) + if column.FilterLabel != "" { + view.Filters = append(view.Filters, explorer.ConfigFilter{Column: column.PublicColumn, Label: column.FilterLabel}) + } + if column.ChartType != "" { + view.Charts = append(view.Charts, explorer.ConfigChart{Column: column.PublicColumn, Type: column.ChartType, Title: column.ChartTitle}) + } + } + views = append(views, view) + } + title := explorerID + if len(tabs) > 0 { + title = tabs[0].Title + } + config := explorer.ConfigV2{APIVersion: explorer.ConfigV2APIVersion, Kind: "ExplorerConfig", Project: projectid.Canonical(project), Explorer: explorer.ConfigExplorer{ID: explorerID, Title: title, Management: explorer.ConfigManagementForID(explorerID)}, Recipe: recipeJSON, Views: views} + return json.Marshal(config) +} + func validateReceiptCapability(receipt *explorer.CompilationReceipt, snapshot capability.Snapshot) error { if receipt == nil { return fmt.Errorf("compilation receipt is required") @@ -102,3 +155,23 @@ func validateReceiptResolution(receipt *explorer.CompilationReceipt, resolved en } return nil } + +// compileValidatedReceiptResolution validates the complete immutable receipt +// even when the caller intends to execute only one output. OutputNames is an +// execution selector: allowing it to narrow compilation here would compare a +// partial fingerprint and column set with the receipt's full contract. +func compileValidatedReceiptResolution(ctx context.Context, recipeEngine *engine.Engine, receipt *explorer.CompilationReceipt, bindings recipe.RuntimeBindings) (engine.Resolved, error) { + validationBindings := bindings + validationBindings.OutputNames = nil + resolved, err := recipeEngine.CompileResolvedBundle(ctx, receipt.Bundle, validationBindings) + if err != nil { + return engine.Resolved{}, err + } + if err := validateReceiptResolution(receipt, resolved); err != nil { + return engine.Resolved{}, err + } + if err := validateReceiptEnginePublicColumns(receipt, resolved); err != nil { + return engine.Resolved{}, err + } + return resolved, nil +} diff --git a/internal/server/explorer_receipt_contract_test.go b/internal/server/explorer_receipt_contract_test.go index e0243d24..5391883b 100644 --- a/internal/server/explorer_receipt_contract_test.go +++ b/internal/server/explorer_receipt_contract_test.go @@ -38,6 +38,59 @@ func TestCompiledExplorerConfigV2UsesCompilerOwnedPresentation(t *testing.T) { } } +func TestCompileValidatedReceiptResolutionChecksAllOutputsForScopedPreview(t *testing.T) { + recipeEngine, err := engine.New(engine.Config{ + Registry: compilerTestRegistry{}, + QueryRows: func(context.Context, string, int, map[string]any, func(map[string]any) error) error { + return nil + }, + }) + if err != nil { + t.Fatal(err) + } + bundle := recipe.Bundle{ + RecipeSchemaVersion: recipe.CurrentSchemaVersion, + Name: "multi-output-preview", + TranslationVersion: explorercompilation.TranslationVersion, + Outputs: []recipe.Output{ + {Name: "patients", RootResourceType: "Patient", RowGrain: "patient", Fields: []recipe.Field{{Name: "patient_id", Expr: recipe.Expression{Select: "root.id"}}}}, + {Name: "specimens", RootResourceType: "Specimen", RowGrain: "resource", Fields: []recipe.Field{{Name: "specimen_id", Expr: recipe.Expression{Select: "root.id"}}}}, + }, + } + bindings := recipe.RuntimeBindings{Project: "project-a", DatasetGeneration: "generation-a"} + compiled, err := recipeEngine.CompileResolvedBundle(context.Background(), bundle, bindings) + if err != nil { + t.Fatal(err) + } + resolvedDigest, err := bundle.Digest() + if err != nil { + t.Fatal(err) + } + receipt := &explorer.CompilationReceipt{ + Bundle: bundle, + RecipeDigest: compiled.StoredRecipeDigest, + ResolvedRecipeDigest: resolvedDigest, + ResolvedSchemaDigest: compiled.ResolvedSchemaDigest, + OutputFingerprints: resolvedOutputFingerprints(compiled), + EmittedColumns: []explorer.EmittedColumn{ + {OutputID: "patients", PublicColumn: "patient_id"}, + {OutputID: "specimens", PublicColumn: "specimen_id"}, + }, + } + previewBindings := bindings + previewBindings.OutputNames = []string{"patients"} + resolved, err := compileValidatedReceiptResolution(context.Background(), recipeEngine, receipt, previewBindings) + if err != nil { + t.Fatal(err) + } + if len(resolved.Compiled.Outputs) != 2 { + t.Fatalf("validated outputs=%d, want complete receipt with 2 outputs", len(resolved.Compiled.Outputs)) + } + if len(previewBindings.OutputNames) != 1 || previewBindings.OutputNames[0] != "patients" { + t.Fatalf("preview execution selection was mutated: %#v", previewBindings.OutputNames) + } +} + func TestNativeV2RouteUsesAuthorizedPersistedReceipt(t *testing.T) { snapshot := testAuthoringV2CapabilitySnapshot() scope := authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted} @@ -85,7 +138,7 @@ func TestNativeV2RouteUsesAuthorizedPersistedReceipt(t *testing.T) { } app := fiber.New() RegisterExplorerAuthoringV2Routes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, config) - body := `{"document":{"apiVersion":"` + authoringv2.APIVersion + `","kind":"` + authoringv2.Kind + `","output":{"id":"patients","title":"Patients"},"rootNodeId":"n_patient","routeSteps":[],"selections":[{"candidateId":"c_patient_id","occurrenceId":"base","projectionMode":"FIRST"}],"presentation":{}},"snapshotToken":"` + snapshot.Token + `"}` + body := `{"workspace":{"apiVersion":"` + authoringv2.APIVersion + `","kind":"` + authoringv2.WorkspaceKind + `","documents":[{"kind":"` + authoringv2.Kind + `","output":{"id":"patients","title":"Patients"},"rootNodeId":"n_patient","routeSteps":[],"selections":[{"candidateId":"c_patient_id","occurrenceId":"base","projectionMode":"FIRST"}],"presentation":{}}],"tabs":[{"id":"patients-tab","title":"Patients","outputId":"patients","order":0,"visible":true}]},"snapshotToken":"` + snapshot.Token + `"}` compiled := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/compile", body) if compiled.StatusCode != http.StatusOK { t.Fatalf("compile status=%d body=%s", compiled.StatusCode, compiled.Body) @@ -112,13 +165,13 @@ func TestNativeV2RouteUsesAuthorizedPersistedReceipt(t *testing.T) { "/api/v1/projects/project-a/explorers/other/authoring/v2/preview", } { foreign := requestJSON(t, app, http.MethodPost, path, `{"receiptId":"`+result.ReceiptID+`","outputId":"patients","limit":5}`) - if foreign.StatusCode != http.StatusNotFound || !strings.Contains(foreign.Body, `"code":"RECEIPT_NOT_FOUND"`) || previewCalls != 1 { + if foreign.StatusCode != http.StatusNotFound || !strings.Contains(foreign.Body, `"code":"COMPILE_RECEIPT_NOT_FOUND"`) || previewCalls != 1 { t.Fatalf("foreign receipt path=%s status=%d calls=%d body=%s", path, foreign.StatusCode, previewCalls, foreign.Body) } } executionScope = authscope.ReadScope{Mode: authscope.ReadScopeRestricted} widened := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/preview", `{"receiptId":"`+result.ReceiptID+`","outputId":"patients","limit":5}`) - if widened.StatusCode != http.StatusConflict || !strings.Contains(widened.Body, `"code":"RECEIPT_INPUT_UNAVAILABLE"`) || previewCalls != 1 { + if widened.StatusCode != http.StatusConflict || !strings.Contains(widened.Body, `"code":"RECEIPT_STALE"`) || previewCalls != 1 { t.Fatalf("scope mismatch status=%d calls=%d body=%s", widened.StatusCode, previewCalls, widened.Body) } stats, err := service.CompilationReceiptStats(context.Background(), "project-a") @@ -156,18 +209,22 @@ func TestBuilderReadRestoresPublishedNativeV2Document(t *testing.T) { if err := json.Unmarshal([]byte(response.Body), &state); err != nil { t.Fatal(err) } - if state.Document == nil || state.Document.Output.ID != document.Output.ID || state.Document.Selections[0].CandidateID != document.Selections[0].CandidateID { - t.Fatalf("restored document = %#v", state.Document) + if state.Workspace == nil || len(state.Workspace.Documents) != 1 || state.Workspace.Documents[0].Output.ID != document.Output.ID || state.Workspace.Documents[0].Selections[0].CandidateID != document.Selections[0].CandidateID { + t.Fatalf("restored workspace = %#v", state.Workspace) } } func persistTestNativeReceipt(ctx context.Context, t *testing.T, service *explorer.Service, request ExplorerV2ReceiptCompileRequest, snapshot capability.Snapshot) (*explorer.CompilationReceipt, error) { t.Helper() - normalized, err := request.Document.CanonicalJSON() + workspace := request.Workspace + if workspace.APIVersion == "" { + workspace = authoringv2.Workspace{APIVersion: authoringv2.APIVersion, Kind: authoringv2.WorkspaceKind, Documents: []authoringv2.Document{request.Document}, Tabs: []authoringv2.Tab{{ID: "patients-tab", Title: request.Document.Output.Title, OutputID: request.Document.Output.ID, Order: 0, Visible: true}}} + } + normalized, err := workspace.CanonicalJSON() if err != nil { return nil, err } - intentDigest, err := request.Document.Digest() + intentDigest, err := workspace.Digest() if err != nil { return nil, err } @@ -176,7 +233,7 @@ func persistTestNativeReceipt(ctx context.Context, t *testing.T, service *explor if err != nil { return nil, err } - contract := json.RawMessage(`{"outputId":"patients","columns":[{"emissionId":"em_patient","publicColumn":"c_patient","candidateId":"c_patient_id","occurrenceId":"base","logicalType":"string","filterable":true,"chartable":true}]}`) + contract := json.RawMessage(`{"outputs":[{"outputId":"patients","columns":[{"emissionId":"em_patient","publicColumn":"c_patient","candidateId":"c_patient_id","occurrenceId":"base","projectionMode":"FIRST","label":"Patient ID","logicalType":"string","filterable":true,"chartable":true}]}]}`) contractDigest, err := explorer.CompilationArtifactDigest(contract) if err != nil { return nil, err @@ -188,7 +245,7 @@ func persistTestNativeReceipt(ctx context.Context, t *testing.T, service *explor SourceGeneration: snapshot.Identity.Generation, RecipeDigest: bundleDigest, ResolvedRecipeDigest: bundleDigest, ResolvedSchemaDigest: "resolved-schema", OutputContractDigest: contractDigest, NormalizedBundle: normalized, Bundle: bundle, PublicOutputContract: contract, - EmittedColumns: []explorer.EmittedColumn{{EmissionID: "em_patient", OutputID: "patients", CandidateID: "c_patient_id", OccurrenceID: authoringv2.RootOccurrenceID, PublicColumn: "c_patient", LogicalType: "string", Filterable: true, Chartable: true}}, + EmittedColumns: []explorer.EmittedColumn{{EmissionID: "em_patient", OutputID: "patients", CandidateID: "c_patient_id", OccurrenceID: authoringv2.RootOccurrenceID, ProjectionMode: "FIRST", PublicColumn: "c_patient", Label: "Patient ID", LogicalType: "string", Filterable: true, Chartable: true}}, OutputFingerprints: map[string]string{"patients": "fingerprint"}, CreatedAt: time.Now().UTC(), } receipt.CompilationKey, err = explorer.CompilationKey(receipt) diff --git a/internal/server/explorer_v2_lifecycle.go b/internal/server/explorer_v2_lifecycle.go index 66c618ed..94b1665c 100644 --- a/internal/server/explorer_v2_lifecycle.go +++ b/internal/server/explorer_v2_lifecycle.go @@ -58,6 +58,8 @@ type ExplorerV2Materializer = graphresolver.ExplorerBundleMaterializer type ExplorerV2ReceiptCompileRequest struct { Project string ExplorerID string + Workspace authoringv2.Workspace + // Document remains for internal legacy tests and migration callers. Document authoringv2.Document SnapshotToken string RequestID string diff --git a/internal/server/server.go b/internal/server/server.go index efca53ae..4053b4c2 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -37,6 +37,7 @@ import ( publicationarango "github.com/calypr/loom/internal/dataset/arango" "github.com/calypr/loom/internal/explorer" explorerarango "github.com/calypr/loom/internal/explorer/arango" + "github.com/calypr/loom/internal/explorer/authoringv2" "github.com/calypr/loom/internal/explorer/capability" explorercompilation "github.com/calypr/loom/internal/explorer/compilation" "github.com/calypr/loom/internal/ingest" @@ -392,11 +393,15 @@ func run(ctx context.Context, serverConfig Config) error { if err := validateAuthorizedReadScope(authorized.Scope, snapshot.Identity.AuthorizationScopeDigest); err != nil { return nil, capability.ErrStaleSnapshot } - intentDigest, err := request.Document.Digest() + workspace := request.Workspace + if workspace.APIVersion == "" && request.Document.Kind != "" { + workspace = authoringv2.Workspace{APIVersion: authoringv2.APIVersion, Kind: authoringv2.WorkspaceKind, Documents: []authoringv2.Document{request.Document}, Tabs: []authoringv2.Tab{{ID: request.Document.Output.ID, Title: request.Document.Output.Title, OutputID: request.Document.Output.ID, Order: 0, Visible: true}}} + } + intentDigest, err := workspace.Digest() if err != nil { return nil, err } - normalized, err := request.Document.CanonicalJSON() + normalized, err := workspace.CanonicalJSON() if err != nil { return nil, err } @@ -407,7 +412,7 @@ func run(ctx context.Context, serverConfig Config) error { return prior, nil } } - translated, err := explorercompilation.Compile(ctx, request.Project, request.ExplorerID, request.Document, snapshot) + translated, err := explorercompilation.CompileWorkspace(ctx, request.Project, request.ExplorerID, workspace, snapshot) if err != nil { return nil, err } @@ -416,14 +421,20 @@ func run(ctx context.Context, serverConfig Config) error { return nil, err } emitted := make([]explorer.EmittedColumn, 0, len(translated.EmittedColumns)) + presentationByEmission := map[string]explorercompilation.PresentationColumn{} + for _, presentation := range translated.Presentations { + for _, column := range presentation.Columns { + presentationByEmission[column.EmissionID] = column + } + } for _, column := range translated.EmittedColumns { - emitted = append(emitted, explorer.EmittedColumn{EmissionID: column.EmissionID, OutputID: column.OutputID, NodeID: column.NodeID, SelectionID: column.SelectionID, CandidateID: column.CandidateID, OccurrenceID: column.OccurrenceID, PublicColumn: column.PublicColumn, LogicalType: column.LogicalType, Filterable: column.Filterable, Chartable: column.Chartable}) + emitted = append(emitted, explorer.EmittedColumn{EmissionID: column.EmissionID, OutputID: column.OutputID, NodeID: column.NodeID, SelectionID: column.SelectionID, CandidateID: column.CandidateID, OccurrenceID: column.OccurrenceID, ProjectionMode: column.ProjectionMode, PublicColumn: column.PublicColumn, Label: presentationByEmission[column.EmissionID].Label, LogicalType: column.LogicalType, Filterable: column.Filterable, Chartable: column.Chartable}) } mappings := make([]explorer.IdentityMapping, 0, len(translated.IdentityMappings)) for _, mapping := range translated.IdentityMappings { - mappings = append(mappings, explorer.IdentityMapping{CandidateID: mapping.CandidateID, OccurrenceID: mapping.OccurrenceID, EmissionIDs: append([]string(nil), mapping.EmissionIDs...)}) + mappings = append(mappings, explorer.IdentityMapping{OutputID: mapping.OutputID, CandidateID: mapping.CandidateID, OccurrenceID: mapping.OccurrenceID, ProjectionMode: mapping.ProjectionMode, EmissionIDs: append([]string(nil), mapping.EmissionIDs...)}) } - contract, err := json.Marshal(translated.OutputContract) + contract, err := json.Marshal(explorer.PublicOutputContracts{Outputs: translated.OutputContracts}) if err != nil { return nil, err } @@ -435,7 +446,7 @@ func run(ctx context.Context, serverConfig Config) error { if err != nil { return nil, err } - compiledConfig, err := compiledExplorerConfigV2(request.Project, request.ExplorerID, translated) + compiledConfig, err := compiledExplorerWorkspaceConfigV2(request.Project, request.ExplorerID, translated) if err != nil { return nil, err } @@ -481,16 +492,10 @@ func run(ctx context.Context, serverConfig Config) error { if receipt == nil { return engine.PreviewSummary{}, fmt.Errorf("compilation receipt is required") } - resolved, err := recipeEngine.CompileResolvedBundle(ctx, receipt.Bundle, bindings) + resolved, err := compileValidatedReceiptResolution(ctx, recipeEngine, receipt, bindings) if err != nil { return engine.PreviewSummary{}, &receiptPreviewResolutionError{Err: err} } - if err := validateReceiptResolution(receipt, resolved); err != nil { - return engine.PreviewSummary{}, &receiptPreviewResolutionError{Err: err} - } - if err := validateReceiptEnginePublicColumns(receipt, resolved); err != nil { - return engine.PreviewSummary{}, &receiptPreviewResolutionError{Err: err} - } output := "" if len(bindings.OutputNames) > 0 { output = bindings.OutputNames[0] From b7b69673d9f1c6a27eb8227fca18ea90c3614285 Mon Sep 17 00:00:00 2001 From: matthewpeterkort Date: Thu, 27 Aug 2026 16:32:36 -0700 Subject: [PATCH 09/15] alot of cleanup, working well with UI --- cmd/explorer-authoring-bootstrap/main.go | 100 - cmd/explorer-authoring-live-migrate/main.go | 409 ---- internal/api/bulk/dump/dataframe_export.go | 12 - .../api/bulk/dump/dataframe_export_route.go | 70 - .../bulk/dump/dataframe_export_route_test.go | 73 - internal/api/bulk/dump/export.go | 145 -- internal/api/bulk/dump/export_route.go | 38 - internal/api/bulk/dump/handler.go | 30 - internal/api/bulk/dump/raw_dump.go | 46 - .../bulk/load/memory_lifecycle_store_test.go | 220 ++ internal/api/bulk/load/raw_route_test.go | 126 -- internal/api/bulk/load/snapshot_route_test.go | 2 +- .../api/bulk/load/snapshot_service_test.go | 10 +- .../api/bulk/load/test_server_helpers_test.go | 16 - .../graphql/graph/materialization/service.go | 20 - internal/api/graphql/graph/query/fieldrefs.go | 4 - internal/catalog/capability_evidence.go | 31 - internal/catalog/capability_evidence_test.go | 12 - internal/catalog/write_profiler.go | 23 - internal/catalog/write_profiler_test.go | 12 +- .../dataframe/compiler/capability/probe.go | 96 - internal/dataframe/published/aggregate_sql.go | 4 - internal/dataframe/published/federation.go | 4 +- .../dataframe/published/federation_test.go | 16 + internal/dataframe/published/read.go | 15 - internal/dataframe/published/read_test.go | 7 - internal/dataframe/recipe/document_types.go | 2 +- internal/dataframe/recipe/exec/persistent.go | 8 - .../dataframe/recipe/exec/persistent_test.go | 8 - internal/dataframe/recipe/revisions.go | 74 - internal/dataframe/recipe/revisions_test.go | 28 - .../dataframe/semantic/recipe_plan_output.go | 2 +- .../dataframe/semantic/resolved_plan_test.go | 6 +- internal/dataset/inventory.go | 9 + .../{memory_store.go => memory_store_test.go} | 12 +- .../arango/capability_snapshot_store.go | 5 - .../explorer/arango/receipt_store_test.go | 18 - internal/explorer/arango/store.go | 135 +- internal/explorer/arango/store_test.go | 12 - internal/explorer/authoring_errors.go | 31 + internal/explorer/authoring_v1.go | 470 ---- internal/explorer/authoring_v1_test.go | 214 -- internal/explorer/authoringv2/migration.go | 80 - .../explorer/authoringv2/migration_test.go | 45 - .../explorer/authoringv2/semantic_types.go | 252 +++ internal/explorer/authoringv2/types.go | 129 +- internal/explorer/bootstrap/bootstrap.go | 353 --- internal/explorer/bootstrap/bootstrap_test.go | 61 - internal/explorer/canonical_json.go | 45 + internal/explorer/capability/builder.go | 42 - internal/explorer/capability/builder_test.go | 46 + .../explorer/capabilitystore/repository.go | 179 -- .../capabilitystore/repository_test.go | 92 - internal/explorer/catalog.go | 103 - internal/explorer/catalog_test.go | 40 - .../explorer/compilation/semantic_compile.go | 307 +++ internal/explorer/compilation/translate.go | 11 +- .../explorer/compilation/translate_test.go | 107 + .../explorer/compilation/workspace_test.go | 2 +- internal/explorer/compilation_receipt.go | 21 +- internal/explorer/compilation_receipt_test.go | 15 +- internal/explorer/config_v2.go | 199 +- internal/explorer/config_v2_test.go | 38 - internal/explorer/memory_store.go | 499 ----- internal/explorer/output_contract.go | 35 +- internal/explorer/output_contract_test.go | 13 +- internal/explorer/receipt_store_test.go | 82 - .../explorer/repository_revision_id_test.go | 15 + internal/explorer/service.go | 426 ++-- internal/explorer/state_v1.go | 152 +- internal/explorer/store.go | 63 - internal/explorer/types.go | 41 +- internal/explorer/types_test.go | 21 + internal/explorer/v2_lifecycle_test.go | 69 - internal/explorer/viewer_projection.go | 406 ++++ internal/ingest/bench_test.go | 8 +- internal/ingest/generation_load_test.go | 6 +- internal/ingest/load_options_test.go | 16 +- internal/projectid/projectid.go | 25 - internal/projectid/projectid_test.go | 17 - internal/server/explorer_authoring_http.go | 168 ++ .../server/explorer_authoring_migration.go | 727 ------ .../explorer_authoring_migration_test.go | 296 --- .../explorer_authoring_normalization_test.go | 223 -- internal/server/explorer_authoring_v1.go | 878 -------- .../server/explorer_authoring_v1_routes.go | 533 ----- internal/server/explorer_authoring_v1_test.go | 440 ---- .../explorer_authoring_v2_migration_test.go | 63 - .../server/explorer_authoring_v2_routes.go | 390 +--- internal/server/explorer_builder_lifecycle.go | 90 +- .../server/explorer_builder_routes_test.go | 429 ---- internal/server/explorer_capability.go | 97 +- internal/server/explorer_capability_test.go | 121 +- internal/server/explorer_config_route.go | 82 +- internal/server/explorer_config_route_test.go | 80 +- internal/server/explorer_lifecycle_helpers.go | 65 + internal/server/explorer_lifecycle_types.go | 48 + internal/server/explorer_preview_response.go | 7 +- internal/server/explorer_preview_security.go | 28 +- .../server/explorer_preview_security_test.go | 19 +- internal/server/explorer_receipt_contract.go | 119 +- .../server/explorer_receipt_contract_test.go | 92 +- internal/server/explorer_state_route_test.go | 169 ++ internal/server/explorer_v2_engine.go | 147 -- internal/server/explorer_v2_engine_test.go | 235 -- internal/server/explorer_v2_lifecycle.go | 1971 ----------------- internal/server/explorer_v2_lifecycle_test.go | 877 -------- internal/server/explorer_wiring.go | 123 - internal/server/federation_status_test.go | 50 +- internal/server/http_test_helpers_test.go | 277 +++ internal/server/options.go | 30 - internal/server/release_verifier_test.go | 14 - internal/server/server.go | 73 +- internal/server/wiring_test.go | 11 - 114 files changed, 3076 insertions(+), 12532 deletions(-) delete mode 100644 cmd/explorer-authoring-bootstrap/main.go delete mode 100644 cmd/explorer-authoring-live-migrate/main.go delete mode 100644 internal/api/bulk/dump/dataframe_export.go delete mode 100644 internal/api/bulk/dump/dataframe_export_route.go delete mode 100644 internal/api/bulk/dump/dataframe_export_route_test.go delete mode 100644 internal/api/bulk/dump/export.go delete mode 100644 internal/api/bulk/dump/export_route.go delete mode 100644 internal/api/bulk/dump/handler.go delete mode 100644 internal/api/bulk/dump/raw_dump.go create mode 100644 internal/api/bulk/load/memory_lifecycle_store_test.go delete mode 100644 internal/api/bulk/load/raw_route_test.go delete mode 100644 internal/dataframe/recipe/revisions_test.go rename internal/dataset/{memory_store.go => memory_store_test.go} (95%) create mode 100644 internal/explorer/authoring_errors.go delete mode 100644 internal/explorer/authoring_v1.go delete mode 100644 internal/explorer/authoring_v1_test.go delete mode 100644 internal/explorer/authoringv2/migration.go delete mode 100644 internal/explorer/authoringv2/migration_test.go create mode 100644 internal/explorer/authoringv2/semantic_types.go delete mode 100644 internal/explorer/bootstrap/bootstrap.go delete mode 100644 internal/explorer/bootstrap/bootstrap_test.go delete mode 100644 internal/explorer/capabilitystore/repository_test.go delete mode 100644 internal/explorer/catalog.go delete mode 100644 internal/explorer/catalog_test.go create mode 100644 internal/explorer/compilation/semantic_compile.go delete mode 100644 internal/explorer/memory_store.go delete mode 100644 internal/explorer/receipt_store_test.go create mode 100644 internal/explorer/repository_revision_id_test.go create mode 100644 internal/explorer/types_test.go delete mode 100644 internal/explorer/v2_lifecycle_test.go create mode 100644 internal/explorer/viewer_projection.go create mode 100644 internal/server/explorer_authoring_http.go delete mode 100644 internal/server/explorer_authoring_migration.go delete mode 100644 internal/server/explorer_authoring_migration_test.go delete mode 100644 internal/server/explorer_authoring_normalization_test.go delete mode 100644 internal/server/explorer_authoring_v1.go delete mode 100644 internal/server/explorer_authoring_v1_routes.go delete mode 100644 internal/server/explorer_authoring_v1_test.go delete mode 100644 internal/server/explorer_authoring_v2_migration_test.go delete mode 100644 internal/server/explorer_builder_routes_test.go create mode 100644 internal/server/explorer_lifecycle_helpers.go create mode 100644 internal/server/explorer_lifecycle_types.go create mode 100644 internal/server/explorer_state_route_test.go delete mode 100644 internal/server/explorer_v2_engine.go delete mode 100644 internal/server/explorer_v2_engine_test.go delete mode 100644 internal/server/explorer_v2_lifecycle.go delete mode 100644 internal/server/explorer_v2_lifecycle_test.go delete mode 100644 internal/server/explorer_wiring.go create mode 100644 internal/server/http_test_helpers_test.go diff --git a/cmd/explorer-authoring-bootstrap/main.go b/cmd/explorer-authoring-bootstrap/main.go deleted file mode 100644 index e5058ae9..00000000 --- a/cmd/explorer-authoring-bootstrap/main.go +++ /dev/null @@ -1,100 +0,0 @@ -package main - -import ( - "bytes" - "encoding/json" - "flag" - "fmt" - "io" - "os" - - "github.com/calypr/loom/internal/explorer" - "github.com/calypr/loom/internal/explorer/bootstrap" -) - -type pinnedCatalog struct { - Nodes []struct { - NodeID string `json:"nodeId"` - ResourceType string `json:"resourceType"` - } `json:"nodes"` - RouteEdges []struct { - EdgeID string `json:"edgeId"` - FromNodeID string `json:"fromNodeId"` - ToNodeID string `json:"toNodeId"` - Label string `json:"label"` - } `json:"routeEdges"` - Candidates []struct { - CandidateID string `json:"candidateId"` - NodeID string `json:"nodeId"` - FieldRef string `json:"fieldRef"` - Select string `json:"select"` - LogicalType string `json:"logicalType"` - Filterable bool `json:"filterable"` - Chartable bool `json:"chartable"` - } `json:"candidates"` -} - -func main() { - configPath := flag.String("config", "", "legacy default ExplorerConfigV2 JSON") - catalogPath := flag.String("catalog", "", "pinned V1 authoring catalog JSON") - project := flag.String("project", "", "project identity") - bundlePath := flag.String("bundle", "", "output canonical authoring bundle JSON") - reportPath := flag.String("report", "", "output conversion report JSON") - flag.Parse() - if *configPath == "" || *catalogPath == "" || *project == "" || *bundlePath == "" || *reportPath == "" { - flag.Usage() - os.Exit(2) - } - config, err := os.ReadFile(*configPath) - if err != nil { - fail(err) - } - catalogRaw, err := os.ReadFile(*catalogPath) - if err != nil { - fail(err) - } - var wire pinnedCatalog - dec := json.NewDecoder(bytes.NewReader(catalogRaw)) - dec.DisallowUnknownFields() - if err := dec.Decode(&wire); err != nil { - fail(fmt.Errorf("decode pinned catalog: %w", err)) - } - var trailing any - if err := dec.Decode(&trailing); err != io.EOF { - fail(fmt.Errorf("pinned catalog has trailing JSON")) - } - catalog := explorer.Catalog{Selections: map[string]explorer.CatalogSelection{}} - for _, node := range wire.Nodes { - catalog.Nodes = append(catalog.Nodes, explorer.CatalogNode{ID: node.NodeID, ResourceType: node.ResourceType}) - } - for _, edge := range wire.RouteEdges { - catalog.Edges = append(catalog.Edges, explorer.CatalogEdge{ID: edge.EdgeID, FromNodeID: edge.FromNodeID, ToNodeID: edge.ToNodeID, Label: edge.Label}) - } - for _, candidate := range wire.Candidates { - catalog.Selections[candidate.CandidateID] = explorer.CatalogSelection{ID: candidate.CandidateID, NodeID: candidate.NodeID, FieldRef: candidate.FieldRef, Select: candidate.Select, LogicalType: candidate.LogicalType, Filterable: candidate.Filterable, Chartable: candidate.Chartable} - } - bundle, report, err := bootstrap.ConvertDefault(config, catalog, *project) - if err != nil { - writeReport(*reportPath, report) - fail(err) - } - canonical, err := bundle.CanonicalJSON() - if err != nil { - fail(err) - } - if err := os.WriteFile(*bundlePath, canonical, 0o644); err != nil { - fail(err) - } - writeReport(*reportPath, report) -} - -func writeReport(path string, report bootstrap.Report) { - raw, err := json.MarshalIndent(report, "", " ") - if err != nil { - fail(err) - } - if err := os.WriteFile(path, append(raw, '\n'), 0o644); err != nil { - fail(err) - } -} -func fail(err error) { _, _ = fmt.Fprintln(os.Stderr, err); os.Exit(1) } diff --git a/cmd/explorer-authoring-live-migrate/main.go b/cmd/explorer-authoring-live-migrate/main.go deleted file mode 100644 index 0cd60756..00000000 --- a/cmd/explorer-authoring-live-migrate/main.go +++ /dev/null @@ -1,409 +0,0 @@ -// Command explorer-authoring-live-migrate performs an explicit admin-only -// conversion of the active legacy Explorer packet into a V1 multi-output, -// multi-tab draft. It never activates or materializes the result. -// -// This is intentionally a best-effort bridge for the cutover. Legacy recipe -// transforms are lowered to their underlying catalog selection when possible; -// the report names every skipped or deduplicated field so the conversion is -// not mistaken for an exact legacy equivalence proof. -package main - -import ( - "bytes" - "encoding/json" - "errors" - "flag" - "fmt" - "io" - "net/http" - "os" - "sort" - "strings" - "time" - - "github.com/calypr/loom/internal/dataframe/recipe" - "github.com/calypr/loom/internal/explorer" -) - -type liveField struct { - Project string `json:"project"` - ResourceType string `json:"resource_type"` - Path string `json:"path"` - Kind string `json:"kind"` -} - -type liveSource struct { - Key string `json:"key"` - Project string `json:"project"` - ExplorerID string `json:"explorerId"` - Title string `json:"title"` - SourceGeneration string `json:"sourceGeneration"` - DraftVersion int64 `json:"draftVersion"` - Config json.RawMessage `json:"config"` - Emitted []explorer.EmittedColumn `json:"emitted"` - Fields []liveField `json:"fields"` -} - -type migrationReport struct { - Project string `json:"project"` - ExplorerID string `json:"explorerId"` - SourceGeneration string `json:"sourceGeneration"` - LegacyRevisionID string `json:"legacyRevisionId"` - LegacyOutputCount int `json:"legacyOutputCount"` - V1DocumentCount int `json:"v1DocumentCount"` - LegacyTabCount int `json:"legacyTabCount"` - V1TabCount int `json:"v1TabCount"` - ConvertedFields int `json:"convertedFields"` - ConvertedBindings int `json:"convertedBindings"` - DeduplicatedFields []string `json:"deduplicatedFields,omitempty"` - SkippedFields []string `json:"skippedFields,omitempty"` - SkippedBindings []string `json:"skippedBindings,omitempty"` - Exact bool `json:"exact"` - IntentDigest string `json:"intentDigest"` - Applied bool `json:"applied"` -} - -type cursorResponse struct { - Result []json.RawMessage `json:"result"` - Error bool `json:"error"` - ErrorMessage string `json:"errorMessage"` -} - -func main() { - url := flag.String("url", "http://127.0.0.1:18529", "ArangoDB base URL") - database := flag.String("database", "fhir_proto", "ArangoDB database") - project := flag.String("project", "HTAN_INT-BForePC", "Loom project") - explorerID := flag.String("explorer", "default", "Explorer identity") - apply := flag.Bool("apply", false, "write the V1 draft to loom_explorers") - flag.Parse() - - client := &http.Client{Timeout: 30 * time.Second} - source, err := loadSource(client, strings.TrimRight(*url, "/"), *database, *project, *explorerID) - if err != nil { - fail(err) - } - - bundle, report, err := convert(source) - if err != nil { - writeReport(report) - fail(err) - } - report.IntentDigest = bundle.IntentDigest - if *apply { - if err := applyDraft(client, strings.TrimRight(*url, "/"), *database, source, bundle); err != nil { - writeReport(report) - fail(err) - } - report.Applied = true - } - writeReport(report) - canonical, err := bundle.CanonicalJSON() - if err != nil { - fail(err) - } - _, _ = os.Stdout.Write(canonical) - _, _ = os.Stdout.Write([]byte("\n")) -} - -func loadSource(client *http.Client, baseURL, database, project, explorerID string) (liveSource, error) { - query := `LET owner = FIRST(FOR d IN loom_explorers FILTER d.project == @project AND d.explorerId == @explorerId RETURN d) -LET revision = owner == null OR owner.activeRevisionId == null ? null : DOCUMENT("loom_explorer_revisions", owner.activeRevisionId) -LET fields = (FOR d IN fhir_field_catalog FILTER d.project == @project RETURN KEEP(d, "project", "resource_type", "path", "kind")) -FILTER owner != null -RETURN {key: owner._key, project: owner.project, explorerId: owner.explorerId, title: owner.activeConfig.explorer.title, sourceGeneration: owner.sourceGeneration, draftVersion: owner.draftVersion, config: owner.activeConfig, emitted: revision == null ? [] : revision.emittedColumns, fields: fields}` - rows, err := runAQL(client, baseURL, database, query, map[string]any{"project": project, "explorerId": explorerID}) - if err != nil { - return liveSource{}, err - } - if len(rows) != 1 { - return liveSource{}, fmt.Errorf("expected one active Explorer source, got %d", len(rows)) - } - var source liveSource - if err := json.Unmarshal(rows[0], &source); err != nil { - return liveSource{}, fmt.Errorf("decode live Explorer source: %w", err) - } - return source, nil -} - -func convert(source liveSource) (explorer.ExplorerAuthoringBundleV1, migrationReport, error) { - var config explorer.ConfigV2 - if err := json.Unmarshal(source.Config, &config); err != nil { - return explorer.ExplorerAuthoringBundleV1{}, migrationReport{}, fmt.Errorf("decode active ExplorerConfigV2: %w", err) - } - var legacy recipe.Bundle - if err := json.Unmarshal(config.Recipe, &legacy); err != nil { - return explorer.ExplorerAuthoringBundleV1{}, migrationReport{}, fmt.Errorf("decode active recipe: %w", err) - } - report := migrationReport{Project: source.Project, ExplorerID: source.ExplorerID, SourceGeneration: source.SourceGeneration, LegacyRevisionID: "active", LegacyOutputCount: len(legacy.Outputs), LegacyTabCount: len(config.Views), Exact: false} - - catalog := make(map[string]liveField, len(source.Fields)) - for _, field := range source.Fields { - if field.ResourceType == "" || field.Path == "" { - continue - } - key := field.ResourceType + "\x00" + field.Path - if _, exists := catalog[key]; !exists { - catalog[key] = field - } - } - emittedByOutputPublic := map[string]map[string]explorer.EmittedColumn{} - for _, emitted := range source.Emitted { - if emittedByOutputPublic[emitted.OutputID] == nil { - emittedByOutputPublic[emitted.OutputID] = map[string]explorer.EmittedColumn{} - } - emittedByOutputPublic[emitted.OutputID][emitted.PublicColumn] = emitted - } - - documents := make([]explorer.ExplorerBuilderDocumentV1, 0, len(legacy.Outputs)) - documentsByLegacyOutput := map[string]int{} - pathsByOutput := map[string]map[string]string{} - for _, output := range legacy.Outputs { - outputID := explorer.StableExplorerID(output.Name) - nodeID := explorer.OpaqueID("n_", output.RootResourceType) - document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: outputID, Title: output.Name}, BaseNodeID: nodeID, RowNodeID: nodeID, Presentation: map[string]explorer.ExplorerPresentationBindingV1{}} - pathsByOutput[output.Name] = map[string]string{} - for _, field := range output.Fields { - path, ok := firstSelectionPath(field.Expr) - if !ok || strings.HasPrefix(path, "route_") { - report.SkippedFields = append(report.SkippedFields, output.Name+"."+field.Name) - continue - } - path = strings.TrimPrefix(path, "root.") - key := output.RootResourceType + "\x00" + path - catalogField, ok := catalog[key] - if !ok { - report.SkippedFields = append(report.SkippedFields, output.Name+"."+field.Name) - continue - } - candidateID := explorer.OpaqueID("s_", catalogField.ResourceType+"\x00"+catalogField.Path) - if addCandidate(&document, candidateID) { - report.ConvertedFields++ - } else { - report.DeduplicatedFields = append(report.DeduplicatedFields, output.Name+"."+field.Name) - } - pathsByOutput[output.Name][field.Name] = path - } - documentsByLegacyOutput[output.Name] = len(documents) - documents = append(documents, document) - } - - tabs := make([]explorer.ExplorerTabV1, 0, len(config.Views)) - for index, view := range config.Views { - documentIndex, ok := documentsByLegacyOutput[view.Output] - if !ok { - report.SkippedBindings = append(report.SkippedBindings, view.ID+":unknown-output") - continue - } - document := &documents[documentIndex] - output := legacy.Outputs[documentIndex] - outputPaths := pathsByOutput[view.Output] - for columnIndex, column := range view.Table.Columns { - path, ok := outputPaths[column.Column] - if !ok { - if emitted, exists := emittedByOutputPublic[view.Output][column.Column]; exists { - path, ok = selectionPath(output.RootResourceType, emitted.SelectionID) - } - } - candidateID, ok := candidateForPath(catalog, output.RootResourceType, path) - if !ok { - report.SkippedBindings = append(report.SkippedBindings, view.ID+"."+column.Column) - continue - } - if !addCandidate(document, candidateID) { - report.DeduplicatedFields = append(report.DeduplicatedFields, view.ID+"."+column.Column) - } - emissionID := explorer.OpaqueID("em_", document.Output.ID+"\x00base\x00"+candidateID) - binding := document.Presentation[emissionID] - binding.Label = firstNonEmpty(column.Label, column.Column) - visible := column.Visible - binding.Visible = &visible - order := columnIndex - binding.Order = &order - document.Presentation[emissionID] = binding - report.ConvertedBindings++ - } - for _, filter := range view.Filters { - path := outputPaths[filter.Column] - if path == "" { - if emitted, exists := emittedByOutputPublic[view.Output][filter.Column]; exists { - path, _ = selectionPath(output.RootResourceType, emitted.SelectionID) - } - } - candidateID, ok := candidateForPath(catalog, output.RootResourceType, path) - if !ok || !presentationCandidate(catalog, output.RootResourceType, path) { - report.SkippedBindings = append(report.SkippedBindings, view.ID+".filter."+filter.Column) - continue - } - addCandidate(document, candidateID) - emissionID := explorer.OpaqueID("em_", document.Output.ID+"\x00base\x00"+candidateID) - binding := document.Presentation[emissionID] - binding.Filter = &explorer.ExplorerFilterBindingV1{Label: filter.Label} - document.Presentation[emissionID] = binding - } - for _, chart := range view.Charts { - path := outputPaths[chart.Column] - if path == "" { - if emitted, exists := emittedByOutputPublic[view.Output][chart.Column]; exists { - path, _ = selectionPath(output.RootResourceType, emitted.SelectionID) - } - } - candidateID, ok := candidateForPath(catalog, output.RootResourceType, path) - if !ok || !presentationCandidate(catalog, output.RootResourceType, path) { - report.SkippedBindings = append(report.SkippedBindings, view.ID+".chart."+chart.Column) - continue - } - addCandidate(document, candidateID) - emissionID := explorer.OpaqueID("em_", document.Output.ID+"\x00base\x00"+candidateID) - binding := document.Presentation[emissionID] - binding.Chart = &explorer.ExplorerChartBindingV1{Type: chart.Type, Title: chart.Title} - document.Presentation[emissionID] = binding - } - tabs = append(tabs, explorer.ExplorerTabV1{ID: explorer.StableExplorerID(view.ID), Title: view.Title, OutputID: document.Output.ID, Order: index}) - } - for i := range documents { - sort.Strings(documents[i].CandidateIDs) - } - bundle := explorer.ExplorerAuthoringBundleV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, Project: source.Project, ExplorerID: source.ExplorerID, Title: source.Title, Documents: documents, Tabs: tabs} - canonical, err := bundle.CanonicalJSON() - if err != nil { - return explorer.ExplorerAuthoringBundleV1{}, report, fmt.Errorf("canonicalize manual V1 bundle: %w", err) - } - if err := json.Unmarshal(canonical, &bundle); err != nil { - return explorer.ExplorerAuthoringBundleV1{}, report, fmt.Errorf("normalize manual V1 bundle: %w", err) - } - bundle.IntentDigest, err = bundle.DocumentDigest() - if err != nil { - return explorer.ExplorerAuthoringBundleV1{}, report, err - } - report.V1DocumentCount = len(bundle.AuthoringDocuments()) - report.V1TabCount = len(bundle.Tabs) - return bundle, report, nil -} - -func firstSelectionPath(expression recipe.Expression) (string, bool) { - if expression.Select != "" { - return expression.Select, true - } - for _, argument := range expression.Args { - if argument.Select != "" { - return argument.Select, true - } - } - return "", false -} - -func selectionPath(rootResourceType, selectionID string) (string, bool) { - selectionID = strings.TrimSpace(strings.SplitN(selectionID, "#", 2)[0]) - prefix, path, ok := strings.Cut(selectionID, ".") - if !ok || prefix != rootResourceType || path == "" { - return "", false - } - return path, true -} - -func candidateForPath(catalog map[string]liveField, resourceType, path string) (string, bool) { - path = strings.TrimPrefix(strings.TrimSpace(path), "root.") - if path == "" { - return "", false - } - field, ok := catalog[resourceType+"\x00"+path] - if !ok { - return "", false - } - return explorer.OpaqueID("s_", field.ResourceType+"\x00"+field.Path), true -} - -func presentationCandidate(catalog map[string]liveField, resourceType, path string) bool { - path = strings.TrimPrefix(strings.TrimSpace(path), "root.") - field, ok := catalog[resourceType+"\x00"+path] - return ok && field.Kind != "object" && field.Kind != "array" -} - -func addCandidate(document *explorer.ExplorerBuilderDocumentV1, candidateID string) bool { - for _, existing := range document.CandidateIDs { - if existing == candidateID { - return false - } - } - document.CandidateIDs = append(document.CandidateIDs, candidateID) - return true -} - -func applyDraft(client *http.Client, baseURL, database string, source liveSource, bundle explorer.ExplorerAuthoringBundleV1) error { - canonical, err := bundle.CanonicalJSON() - if err != nil { - return err - } - var bundleObject map[string]any - if err := json.Unmarshal(canonical, &bundleObject); err != nil { - return err - } - query := `FOR d IN loom_explorers -FILTER d._key == @key AND d.project == @project AND d.explorerId == @explorerId AND d.draftVersion == @expectedVersion -UPDATE d WITH {draftVersion: d.draftVersion + 1, draftAuthoringBundle: @bundle, draftIntentDigest: @digest, draftDigest: @digest, draftReceiptId: null, draftIdentityMappings: [], diagnostics: @diagnostics, updatedBy: @actor, updatedAt: @updatedAt} IN loom_explorers -RETURN NEW` - rows, err := runAQL(client, baseURL, database, query, map[string]any{ - "key": source.Key, "project": source.Project, "explorerId": source.ExplorerID, - "expectedVersion": source.DraftVersion, "bundle": bundleObject, "digest": bundle.IntentDigest, - "diagnostics": []map[string]any{{"severity": "WARN", "stage": "migration", "code": "MANUAL_AUTHORING_MIGRATION", "message": "draft created by the live best-effort legacy conversion; inspect the migration report before compiling or publishing"}}, - "actor": "manual-authoring-migration", "updatedAt": time.Now().UTC().Format(time.RFC3339Nano), - }) - if err != nil { - return err - } - if len(rows) != 1 { - return errors.New("draft changed during manual migration; no write was applied") - } - return nil -} - -func runAQL(client *http.Client, baseURL, database, query string, bindVars map[string]any) ([]json.RawMessage, error) { - body, err := json.Marshal(map[string]any{"query": query, "bindVars": bindVars}) - if err != nil { - return nil, err - } - request, err := http.NewRequest(http.MethodPost, baseURL+"/_db/"+database+"/_api/cursor", bytes.NewReader(body)) - if err != nil { - return nil, err - } - request.Header.Set("Content-Type", "application/json") - response, err := client.Do(request) - if err != nil { - return nil, err - } - defer response.Body.Close() - raw, err := io.ReadAll(response.Body) - if err != nil { - return nil, err - } - if response.StatusCode < 200 || response.StatusCode >= 300 { - return nil, fmt.Errorf("Arango query returned %s: %s", response.Status, strings.TrimSpace(string(raw))) - } - var result cursorResponse - if err := json.Unmarshal(raw, &result); err != nil { - return nil, err - } - if result.Error { - return nil, errors.New(result.ErrorMessage) - } - return result.Result, nil -} - -func firstNonEmpty(values ...string) string { - for _, value := range values { - if strings.TrimSpace(value) != "" { - return value - } - } - return "Explorer" -} - -func writeReport(report migrationReport) { - raw, _ := json.MarshalIndent(report, "", " ") - _, _ = os.Stderr.Write(append(raw, '\n')) -} - -func fail(err error) { - _, _ = fmt.Fprintln(os.Stderr, err) - os.Exit(1) -} diff --git a/internal/api/bulk/dump/dataframe_export.go b/internal/api/bulk/dump/dataframe_export.go deleted file mode 100644 index 939bf8a8..00000000 --- a/internal/api/bulk/dump/dataframe_export.go +++ /dev/null @@ -1,12 +0,0 @@ -package dump - -import ( - "context" - "io" - - dfmaterialization "github.com/calypr/loom/internal/dataframe/published" -) - -type DataframeExporter interface { - ExportDataframe(context.Context, dfmaterialization.ExportRequest, io.Writer) error -} diff --git a/internal/api/bulk/dump/dataframe_export_route.go b/internal/api/bulk/dump/dataframe_export_route.go deleted file mode 100644 index d10aed36..00000000 --- a/internal/api/bulk/dump/dataframe_export_route.go +++ /dev/null @@ -1,70 +0,0 @@ -package dump - -import ( - "encoding/json" - "strings" - - dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" - dfmaterialization "github.com/calypr/loom/internal/dataframe/published" - "github.com/gofiber/fiber/v3" -) - -func (s *Handler) exportDataframe(c fiber.Ctx) error { - var request dfmaterialization.ExportRequest - if err := json.Unmarshal(c.Body(), &request); err != nil { - return dataframeerrors.Wrap(err, dataframeerrors.CodeInvalidRequest, "") - } - if request.Selector == nil { - return dataframeerrors.NewError(dataframeerrors.CodeInvalidSelector, "") - } - if request.Format.Normalize() == "" { - return dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") - } - filename := sanitizeExportFilename(request.Filename, request.Format.Normalize()) - c.Set(fiber.HeaderContentType, exportContentType(request.Format.Normalize())) - c.Set(fiber.HeaderContentDisposition, `attachment; filename="`+filename+`"`) - if err := s.dataframeExporter.ExportDataframe(c.Context(), request, c); err != nil { - resetExportResponse(c) - return err - } - return nil -} - -func resetExportResponse(c fiber.Ctx) { - // Fiber buffers response writes until the handler returns. Clear any - // partial export before the central error handler emits JSON. - c.Response().ResetBody() - c.Response().Header.Del(fiber.HeaderContentType) - c.Response().Header.Del(fiber.HeaderContentDisposition) -} - -func exportContentType(format dfmaterialization.ExportFormat) string { - switch format.Normalize() { - case dfmaterialization.ExportCSV: - return "text/csv; charset=utf-8" - case dfmaterialization.ExportTSV: - return "text/tab-separated-values; charset=utf-8" - case dfmaterialization.ExportJSON: - return "application/json; charset=utf-8" - default: - return "application/x-ndjson; charset=utf-8" - } -} - -func sanitizeExportFilename(value string, format dfmaterialization.ExportFormat) string { - value = strings.TrimSpace(value) - value = strings.NewReplacer("/", "_", "\\", "_", "\"", "", "\r", "", "\n", "").Replace(value) - if value == "" { - ext := "jsonl" - switch format.Normalize() { - case dfmaterialization.ExportCSV: - ext = "csv" - case dfmaterialization.ExportTSV: - ext = "tsv" - case dfmaterialization.ExportJSON: - ext = "json" - } - return "loom-export." + ext - } - return value -} diff --git a/internal/api/bulk/dump/dataframe_export_route_test.go b/internal/api/bulk/dump/dataframe_export_route_test.go deleted file mode 100644 index 60759b90..00000000 --- a/internal/api/bulk/dump/dataframe_export_route_test.go +++ /dev/null @@ -1,73 +0,0 @@ -package dump - -import ( - "context" - "io" - "net/http" - "net/http/httptest" - "strings" - "testing" - - httpapi "github.com/calypr/loom/internal/api/http" - "github.com/calypr/loom/internal/authscope" - dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" - dfmaterialization "github.com/calypr/loom/internal/dataframe/published" -) - -type fakeDataframeExporter struct{} - -func (fakeDataframeExporter) ExportDataframe(_ context.Context, request dfmaterialization.ExportRequest, out io.Writer) error { - if request.Selector == nil || request.Format.Normalize() != dfmaterialization.ExportCSV { - return dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") - } - _, err := io.WriteString(out, "id\n1\n") - return err -} - -type fakeSelectorExporter struct{} - -func (fakeSelectorExporter) ExportDataframe(_ context.Context, request dfmaterialization.ExportRequest, out io.Writer) error { - if request.Selector == nil || request.Selector.Recipe != "documents" || request.Selector.TranslationVersion != "v2" || request.Selector.Output != "DocumentReference" { - return dataframeerrors.NewError(dataframeerrors.CodeInvalidSelector, "") - } - _, err := io.WriteString(out, "{}\n") - return err -} - -func TestDataframeExportRouteRejectsLegacyDataType(t *testing.T) { - server, err := httpapi.NewHTTPServer(httpapi.HTTPConfig{Authorizer: authscope.AllowAllAuthorizer{}}) - if err != nil { - t.Fatal(err) - } - NewHandler(Config{DataframeExporter: fakeDataframeExporter{}}).RegisterRoutes(server.App()) - req := httptest.NewRequest(http.MethodPost, "/loom/api/v1/dataframe/export", strings.NewReader(`{"dataType":"files","format":"CSV","fileName":"../files.csv"}`)) - req.Header.Set("Content-Type", "application/json") - resp, err := server.App().Test(req) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusBadRequest { - body, _ := io.ReadAll(resp.Body) - t.Fatalf("status = %d, body = %s", resp.StatusCode, body) - } -} - -func TestDataframeExportRouteAcceptsExactSelector(t *testing.T) { - server, err := httpapi.NewHTTPServer(httpapi.HTTPConfig{Authorizer: authscope.AllowAllAuthorizer{}}) - if err != nil { - t.Fatal(err) - } - NewHandler(Config{DataframeExporter: fakeSelectorExporter{}}).RegisterRoutes(server.App()) - req := httptest.NewRequest(http.MethodPost, "/loom/api/v1/dataframe/export", strings.NewReader(`{"selector":{"recipe":"documents","translationVersion":"v2","output":"DocumentReference"},"format":"JSONL"}`)) - req.Header.Set("Content-Type", "application/json") - resp, err := server.App().Test(req) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - body, _ := io.ReadAll(resp.Body) - t.Fatalf("status = %d, body = %s", resp.StatusCode, body) - } -} diff --git a/internal/api/bulk/dump/export.go b/internal/api/bulk/dump/export.go deleted file mode 100644 index 2ba42ee3..00000000 --- a/internal/api/bulk/dump/export.go +++ /dev/null @@ -1,145 +0,0 @@ -package dump - -import ( - "context" - "encoding/json" - "errors" - "io" - - "github.com/calypr/loom/internal/authscope" - dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" - publication "github.com/calypr/loom/internal/dataset" - arangostore "github.com/calypr/loom/internal/store/arango" -) - -type RawExporter interface { - ExportRaw(context.Context, string, string, authscope.ReadScope, io.Writer) error - ExportRawFiltered(context.Context, RawDumpRequest, authscope.ReadScope, io.Writer) error - ResolveGeneration(context.Context, string, string) (string, error) -} - -type RawDumpRequest struct { - Project string - Generation string - ResourceType string - Limit int -} - -type QueryRowsClient interface { - QueryRows(context.Context, string, int, map[string]interface{}, arangostore.RowVisitor) error - CollectionExists(context.Context, string) (bool, error) -} - -type ArangoRawExporter struct { - Query QueryRowsClient - Manifests interface { - ReadManifest(context.Context, publication.Ref) (publication.Manifest, error) - ResolveActiveManifest(context.Context, string) (publication.Manifest, error) - } -} - -func (e ArangoRawExporter) ExportRaw(ctx context.Context, project, generationID string, scope authscope.ReadScope, out io.Writer) error { - return e.ExportRawFiltered(ctx, RawDumpRequest{Project: project, Generation: generationID}, scope, out) -} - -func (e ArangoRawExporter) ResolveGeneration(ctx context.Context, project, generationID string) (string, error) { - manifest, err := e.resolveManifest(ctx, project, generationID) - if err != nil { - return "", err - } - return manifest.Dataset.Generation, nil -} - -func (e ArangoRawExporter) resolveManifest(ctx context.Context, project, generationID string) (publication.Manifest, error) { - if generationID == "" { - manifest, err := e.Manifests.ResolveActiveManifest(ctx, project) - if err != nil { - return publication.Manifest{}, classifyRawExportError(err) - } - if !manifest.IsStaged() { - return publication.Manifest{}, dataframeerrors.NewError(dataframeerrors.CodeNoActiveGeneration, "") - } - return manifest, nil - } - ref, err := publication.NewRef(project, generationID) - if err != nil { - return publication.Manifest{}, dataframeerrors.Wrap(err, dataframeerrors.CodeInvalidRequest, "") - } - manifest, err := e.Manifests.ReadManifest(ctx, ref) - if err != nil { - return publication.Manifest{}, classifyRawExportError(err) - } - if !manifest.IsStaged() { - return publication.Manifest{}, dataframeerrors.NewError(dataframeerrors.CodeNoActiveGeneration, "") - } - return manifest, nil -} - -func (e ArangoRawExporter) ExportRawFiltered(ctx context.Context, req RawDumpRequest, scope authscope.ReadScope, out io.Writer) error { - generation := req.Generation - manifest, err := e.resolveManifest(ctx, req.Project, req.Generation) - if err != nil { - return err - } - generation = manifest.Dataset.Generation - resourceTypes := manifest.SchemaIdentity.GeneratedResourceTypes - if req.ResourceType != "" { - found := false - for _, resourceType := range resourceTypes { - if resourceType == req.ResourceType { - found = true - break - } - } - if !found { - return dataframeerrors.NewError(dataframeerrors.CodeInvalidResourceType, "") - } - resourceTypes = []string{req.ResourceType} - } - - encoder := json.NewEncoder(out) - remaining := req.Limit - for _, resourceType := range resourceTypes { - collection := resourceType - exists, err := e.Query.CollectionExists(ctx, collection) - if err != nil { - return dataframeerrors.Wrap(err, dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) - } - if !exists { - continue - } - query := "FOR doc IN @@collection FILTER doc.project == @project AND doc.dataset_generation == @generation AND (@auth_resource_paths_unrestricted == true OR doc.auth_resource_path IN @auth_resource_paths) SORT doc._key RETURN doc.payload" - bindVars := map[string]interface{}{"@collection": collection, "project": req.Project, "generation": generation, "auth_resource_paths_unrestricted": scope.Unrestricted(), "auth_resource_paths": scope.AuthResourcePaths} - if remaining > 0 { - query = "FOR doc IN @@collection FILTER doc.project == @project AND doc.dataset_generation == @generation AND (@auth_resource_paths_unrestricted == true OR doc.auth_resource_path IN @auth_resource_paths) SORT doc._key LIMIT @limit RETURN doc.payload" - bindVars["limit"] = remaining - } - written := 0 - if err := e.Query.QueryRows(ctx, query, 500, bindVars, func(row map[string]any) error { - written++ - return encoder.Encode(row) - }); err != nil { - return dataframeerrors.Wrap(err, dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) - } - if remaining > 0 { - remaining -= written - if remaining == 0 { - break - } - } - } - return nil -} - -func classifyRawExportError(err error) error { - if err == nil { - return nil - } - if _, ok := dataframeerrors.AsUserError(err); ok { - return err - } - if errors.Is(err, publication.ErrNoActiveGeneration) { - return dataframeerrors.Wrap(err, dataframeerrors.CodeNoActiveGeneration, "") - } - return dataframeerrors.Wrap(err, dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) -} diff --git a/internal/api/bulk/dump/export_route.go b/internal/api/bulk/dump/export_route.go deleted file mode 100644 index 21b2c58d..00000000 --- a/internal/api/bulk/dump/export_route.go +++ /dev/null @@ -1,38 +0,0 @@ -package dump - -import ( - "strings" - - "github.com/calypr/loom/internal/authscope" - dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" - "github.com/gofiber/fiber/v3" -) - -func (s *Handler) exportGeneration(c fiber.Ctx) error { - if s.rawExporter == nil { - return dataframeerrors.NewError(dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) - } - project := strings.TrimSpace(c.Params("project")) - generation := strings.TrimSpace(c.Params("generation")) - if project == "" || generation == "" { - return dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") - } - principal, _ := c.Locals("principal").(*authscope.Principal) - scope := authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted} - if s.scopeResolver != nil { - resolved, err := s.scopeResolver.ResolveReadScopeForGeneration(c.Context(), principal, project, generation, nil) - if err != nil { - return dataframeerrors.Wrap(err, dataframeerrors.CodeForbidden, "") - } - if resolved.Mode == authscope.ReadScopeRestricted && len(resolved.AuthResourcePaths) == 0 { - return dataframeerrors.NewError(dataframeerrors.CodeForbidden, "") - } - scope = resolved - } - c.Set(fiber.HeaderContentType, "application/x-ndjson") - if err := s.rawExporter.ExportRaw(c.Context(), project, generation, scope, c); err != nil { - resetExportResponse(c) - return err - } - return nil -} diff --git a/internal/api/bulk/dump/handler.go b/internal/api/bulk/dump/handler.go deleted file mode 100644 index 7c0d81a5..00000000 --- a/internal/api/bulk/dump/handler.go +++ /dev/null @@ -1,30 +0,0 @@ -package dump - -import ( - "github.com/calypr/loom/internal/authscope" - "github.com/gofiber/fiber/v3" -) - -type Handler struct { - rawExporter RawExporter - dataframeExporter DataframeExporter - scopeResolver *authscope.ScopeResolver -} -type Config struct { - RawExporter RawExporter - DataframeExporter DataframeExporter - ScopeResolver *authscope.ScopeResolver -} - -func NewHandler(cfg Config) *Handler { - return &Handler{rawExporter: cfg.RawExporter, dataframeExporter: cfg.DataframeExporter, scopeResolver: cfg.ScopeResolver} -} -func (h *Handler) RegisterRoutes(router fiber.Router) { - if h.rawExporter != nil { - router.Get("/api/v1/raw", h.dumpRaw) - router.Get("/api/v1/datasets/:project/generations/:generation/export", h.exportGeneration) - } - if h.dataframeExporter != nil { - router.Post("/loom/api/v1/dataframe/export", h.exportDataframe) - } -} diff --git a/internal/api/bulk/dump/raw_dump.go b/internal/api/bulk/dump/raw_dump.go deleted file mode 100644 index 3adaf21b..00000000 --- a/internal/api/bulk/dump/raw_dump.go +++ /dev/null @@ -1,46 +0,0 @@ -package dump - -import ( - "github.com/calypr/loom/internal/authscope" - dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" - "github.com/gofiber/fiber/v3" - "strconv" - "strings" -) - -func (s *Handler) dumpRaw(c fiber.Ctx) error { - project := strings.TrimSpace(c.Query("project")) - if project == "" { - return dataframeerrors.NewError(dataframeerrors.CodeProjectRequired, "") - } - limit := 0 - if raw := strings.TrimSpace(c.Query("limit")); raw != "" { - parsed, err := strconv.Atoi(raw) - if err != nil || parsed < 1 { - return dataframeerrors.NewError(dataframeerrors.CodeInvalidLimit, "") - } - limit = parsed - } - requestedGeneration := strings.TrimSpace(c.Query("generation")) - generation, err := s.rawExporter.ResolveGeneration(c.Context(), project, requestedGeneration) - if err != nil { - return err - } - principal, _ := c.Locals("principal").(*authscope.Principal) - scope := authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted} - if s.scopeResolver != nil { - scope, err = s.scopeResolver.ResolveReadScopeForGeneration(c.Context(), principal, project, generation, nil) - if err != nil { - return dataframeerrors.Wrap(err, dataframeerrors.CodeForbidden, "") - } - if scope.Mode == authscope.ReadScopeRestricted && len(scope.AuthResourcePaths) == 0 { - return dataframeerrors.NewError(dataframeerrors.CodeForbidden, "") - } - } - c.Set(fiber.HeaderContentType, "application/x-ndjson") - if err := s.rawExporter.ExportRawFiltered(c.Context(), RawDumpRequest{Project: project, Generation: generation, ResourceType: strings.TrimSpace(c.Query("resourceType")), Limit: limit}, scope, c); err != nil { - resetExportResponse(c) - return err - } - return nil -} diff --git a/internal/api/bulk/load/memory_lifecycle_store_test.go b/internal/api/bulk/load/memory_lifecycle_store_test.go new file mode 100644 index 00000000..ffacf30a --- /dev/null +++ b/internal/api/bulk/load/memory_lifecycle_store_test.go @@ -0,0 +1,220 @@ +package load + +import ( + "context" + "fmt" + "reflect" + "sort" + "sync" + "time" + + "github.com/calypr/loom/internal/dataset" +) + +type memoryLifecycleStore struct { + mu sync.RWMutex + snapshots map[dataset.Ref]dataset.SnapshotGeneration + releases map[string]dataset.ActiveRelease + releaseRecords map[string]dataset.ProjectRelease +} + +func newMemoryLifecycleStore() *memoryLifecycleStore { + return &memoryLifecycleStore{ + snapshots: make(map[dataset.Ref]dataset.SnapshotGeneration), + releases: make(map[string]dataset.ActiveRelease), + releaseRecords: make(map[string]dataset.ProjectRelease), + } +} + +func (s *memoryLifecycleStore) SaveRelease(_ context.Context, release dataset.ProjectRelease) (dataset.ProjectRelease, error) { + s.mu.Lock() + defer s.mu.Unlock() + key := release.Project + "\x00" + release.ID + if existing, ok := s.releaseRecords[key]; ok { + if !reflect.DeepEqual(existing, release) { + return dataset.ProjectRelease{}, dataset.ErrSnapshotConflict + } + return cloneTestRelease(existing), nil + } + s.releaseRecords[key] = cloneTestRelease(release) + return cloneTestRelease(release), nil +} + +func (s *memoryLifecycleStore) ReadRelease(_ context.Context, project, releaseID string) (dataset.ProjectRelease, error) { + s.mu.RLock() + defer s.mu.RUnlock() + release, ok := s.releaseRecords[project+"\x00"+releaseID] + if !ok { + return dataset.ProjectRelease{}, dataset.ErrReleaseNotFound + } + return cloneTestRelease(release), nil +} + +func (s *memoryLifecycleStore) CreateOrResumeSnapshot(_ context.Context, candidate dataset.SnapshotGeneration) (dataset.SnapshotGeneration, error) { + if err := candidate.Validate(); err != nil { + return dataset.SnapshotGeneration{}, err + } + s.mu.Lock() + defer s.mu.Unlock() + if existing, ok := s.snapshots[candidate.Dataset]; ok { + if existing.GitCommit != candidate.GitCommit || existing.AuthResourcePath != candidate.AuthResourcePath || !reflect.DeepEqual(existing.ExpectedResourceTypes, candidate.ExpectedResourceTypes) { + return dataset.SnapshotGeneration{}, dataset.ErrSnapshotConflict + } + return cloneTestSnapshot(existing), nil + } + s.snapshots[candidate.Dataset] = cloneTestSnapshot(candidate) + return cloneTestSnapshot(candidate), nil +} + +func (s *memoryLifecycleStore) ReadSnapshot(_ context.Context, ref dataset.Ref) (dataset.SnapshotGeneration, error) { + s.mu.RLock() + defer s.mu.RUnlock() + snapshot, ok := s.snapshots[ref] + if !ok { + return dataset.SnapshotGeneration{}, dataset.ErrSnapshotNotFound + } + return cloneTestSnapshot(snapshot), nil +} + +func (s *memoryLifecycleStore) RecordSnapshotUpload(_ context.Context, ref dataset.Ref, upload dataset.ResourceUpload) (dataset.SnapshotGeneration, error) { + s.mu.Lock() + defer s.mu.Unlock() + snapshot, ok := s.snapshots[ref] + if !ok { + return dataset.SnapshotGeneration{}, dataset.ErrSnapshotNotFound + } + if snapshot.State != dataset.StateLoading { + if prior, found := snapshot.Upload(upload.ResourceType); found && prior.SHA256 == upload.SHA256 && prior.Size == upload.Size { + return cloneTestSnapshot(snapshot), nil + } + return dataset.SnapshotGeneration{}, dataset.ErrSnapshotFinalized + } + if !includesResource(snapshot.ExpectedResourceTypes, upload.ResourceType) { + return dataset.SnapshotGeneration{}, fmt.Errorf("%w: resource type %q was not declared", dataset.ErrSnapshotConflict, upload.ResourceType) + } + for _, prior := range snapshot.Uploads { + if prior.ResourceType != upload.ResourceType { + continue + } + if prior.SHA256 != upload.SHA256 || prior.Size != upload.Size { + return dataset.SnapshotGeneration{}, dataset.ErrChecksumConflict + } + return cloneTestSnapshot(snapshot), nil + } + snapshot.Uploads = append(snapshot.Uploads, upload) + sort.Slice(snapshot.Uploads, func(i, j int) bool { return snapshot.Uploads[i].ResourceType < snapshot.Uploads[j].ResourceType }) + snapshot.UpdatedAt = upload.UploadedAt + s.snapshots[ref] = snapshot + return cloneTestSnapshot(snapshot), nil +} + +func (s *memoryLifecycleStore) TransitionSnapshot(_ context.Context, ref dataset.Ref, expected, next dataset.State, now time.Time) (dataset.SnapshotGeneration, error) { + s.mu.Lock() + defer s.mu.Unlock() + snapshot, ok := s.snapshots[ref] + if !ok { + return dataset.SnapshotGeneration{}, dataset.ErrSnapshotNotFound + } + if snapshot.State == next { + return cloneTestSnapshot(snapshot), nil + } + if snapshot.State != expected || expected != dataset.StateLoading || (next != dataset.StateStaged && next != dataset.StateFailed) { + return dataset.SnapshotGeneration{}, fmt.Errorf("%w: %s -> %s", dataset.ErrSnapshotConflict, snapshot.State, next) + } + if next == dataset.StateStaged && len(snapshot.MissingResourceTypes()) != 0 { + return dataset.SnapshotGeneration{}, dataset.ErrGenerationIncomplete + } + snapshot.State = next + snapshot.UpdatedAt = now.UTC() + if next == dataset.StateFailed { + aborted := now.UTC() + snapshot.AbortedAt = &aborted + } + s.snapshots[ref] = snapshot + return cloneTestSnapshot(snapshot), nil +} + +func (s *memoryLifecycleStore) ListSnapshotProjects(context.Context) ([]string, error) { + s.mu.RLock() + defer s.mu.RUnlock() + set := make(map[string]struct{}) + for ref := range s.snapshots { + set[ref.Project] = struct{}{} + } + return sortedTestProjects(set), nil +} + +func (s *memoryLifecycleStore) ReadActiveRelease(_ context.Context, project string) (dataset.ActiveRelease, error) { + s.mu.RLock() + defer s.mu.RUnlock() + release, ok := s.releases[project] + if !ok { + return dataset.ActiveRelease{}, dataset.ErrNoActiveRelease + } + return cloneTestActiveRelease(release), nil +} + +func (s *memoryLifecycleStore) CompareAndSwapActivateRelease(_ context.Context, release dataset.ProjectRelease, expectedRevision int64) (dataset.ActiveRelease, error) { + s.mu.Lock() + defer s.mu.Unlock() + current := s.releases[release.Project] + if current.Revision == expectedRevision+1 && current.Release.ID == release.ID { + return cloneTestActiveRelease(current), nil + } + if current.Revision != expectedRevision { + return dataset.ActiveRelease{}, dataset.ErrReleaseActivationConflict + } + active := dataset.ActiveRelease{Release: cloneTestRelease(release), Revision: expectedRevision + 1} + s.releases[release.Project] = active + return cloneTestActiveRelease(active), nil +} + +func (s *memoryLifecycleStore) ListReleaseProjects(context.Context) ([]string, error) { + s.mu.RLock() + defer s.mu.RUnlock() + set := make(map[string]struct{}, len(s.releases)) + for project := range s.releases { + set[project] = struct{}{} + } + return sortedTestProjects(set), nil +} + +func cloneTestSnapshot(value dataset.SnapshotGeneration) dataset.SnapshotGeneration { + value.ExpectedResourceTypes = append([]string(nil), value.ExpectedResourceTypes...) + value.Uploads = append([]dataset.ResourceUpload(nil), value.Uploads...) + if value.AbortedAt != nil { + copied := *value.AbortedAt + value.AbortedAt = &copied + } + return value +} + +func cloneTestRelease(value dataset.ProjectRelease) dataset.ProjectRelease { + value.Publications = append([]dataset.ReleasePublication(nil), value.Publications...) + value.RequiredVerifications = append([]dataset.ContractVerification(nil), value.RequiredVerifications...) + return value +} + +func cloneTestActiveRelease(value dataset.ActiveRelease) dataset.ActiveRelease { + value.Release = cloneTestRelease(value.Release) + return value +} +func includesResource(values []string, target string) bool { + for _, value := range values { + if value == target { + return true + } + } + return false +} +func sortedTestProjects(values map[string]struct{}) []string { + result := make([]string, 0, len(values)) + for value := range values { + result = append(result, value) + } + sort.Strings(result) + return result +} + +var _ dataset.SnapshotRepository = (*memoryLifecycleStore)(nil) +var _ dataset.ReleaseRepository = (*memoryLifecycleStore)(nil) diff --git a/internal/api/bulk/load/raw_route_test.go b/internal/api/bulk/load/raw_route_test.go deleted file mode 100644 index d7d6194c..00000000 --- a/internal/api/bulk/load/raw_route_test.go +++ /dev/null @@ -1,126 +0,0 @@ -package load - -import ( - "context" - "io" - "net/http" - "net/http/httptest" - "os" - "path/filepath" - "strings" - "testing" - - "github.com/calypr/loom/internal/authscope" - "github.com/calypr/loom/internal/ingest" -) - -type fakeRawExporter struct { - request RawDumpRequest -} - -func (f *fakeRawExporter) ResolveGeneration(context.Context, string, string) (string, error) { - return "active-1", nil -} - -func (f *fakeRawExporter) ExportRaw(context.Context, string, string, authscope.ReadScope, io.Writer) error { - return nil -} - -func (f *fakeRawExporter) ExportRawFiltered(_ context.Context, req RawDumpRequest, _ authscope.ReadScope, out io.Writer) error { - f.request = req - _, err := io.WriteString(out, `{"resourceType":"Patient","id":"p1"}`+"\n") - return err -} - -type capturingGenerationRunner struct { - request GenerationLoadRequest - files map[string]string -} - -func (r *capturingGenerationRunner) RunGeneration(_ context.Context, req GenerationLoadRequest, _ ingest.EventSink) (ingest.LoadSummary, error) { - r.request = req - r.files = map[string]string{} - entries, err := os.ReadDir(req.StagedDir) - if err != nil { - return ingest.LoadSummary{}, err - } - for _, entry := range entries { - content, err := os.ReadFile(filepath.Join(req.StagedDir, entry.Name())) - if err != nil { - return ingest.LoadSummary{}, err - } - r.files[entry.Name()] = string(content) - } - return ingest.LoadSummary{Files: len(entries), VerticesInserted: 2}, nil -} - -func TestDumpRawAcceptsResourceTypeAndLimit(t *testing.T) { - service, err := NewService(ServiceConfig{GenerationRunner: &fakeGenerationRunner{}}) - if err != nil { - t.Fatal(err) - } - exporter := &fakeRawExporter{} - server, err := NewHTTPServer(HTTPConfig{Service: service, Authorizer: authscope.AllowAllAuthorizer{}, RawExporter: exporter}) - if err != nil { - t.Fatal(err) - } - resp, err := server.App().Test(httptest.NewRequest(http.MethodGet, "/api/v1/raw?project=P1&resourceType=Patient&limit=2", nil)) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - t.Fatalf("status = %d", resp.StatusCode) - } - if exporter.request.Project != "P1" || exporter.request.ResourceType != "Patient" || exporter.request.Limit != 2 || exporter.request.Generation != "active-1" { - t.Fatalf("request = %#v", exporter.request) - } -} - -func TestLoadRawPartitionsMixedFHIRNDJSON(t *testing.T) { - runner := &capturingGenerationRunner{} - service, err := NewService(ServiceConfig{GenerationRunner: runner}) - if err != nil { - t.Fatal(err) - } - server, err := NewHTTPServer(HTTPConfig{Service: service, Authorizer: authscope.AllowAllAuthorizer{}}) - if err != nil { - t.Fatal(err) - } - body := `{"resourceType":"Patient","id":"p1"}` + "\n" + `{"resourceType":"Specimen","id":"s1"}` + "\n" - req := httptest.NewRequest(http.MethodPut, "/api/v1/raw?project=P1&generation=generation-1", strings.NewReader(body)) - req.Header.Set("Content-Type", "application/x-ndjson") - resp, err := server.App().Test(req) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - payload, _ := io.ReadAll(resp.Body) - t.Fatalf("status = %d body = %s", resp.StatusCode, payload) - } - if runner.request.Project != "P1" || len(runner.files) != 2 { - t.Fatalf("request = %#v files = %#v", runner.request, runner.files) - } -} - -func TestLoadRawUsesWriteAuthorization(t *testing.T) { - service, err := NewService(ServiceConfig{GenerationRunner: &capturingGenerationRunner{}}) - if err != nil { - t.Fatal(err) - } - server, err := NewHTTPServer(HTTPConfig{Service: service, Authorizer: denyAuthorizer{}}) - if err != nil { - t.Fatal(err) - } - req := httptest.NewRequest(http.MethodPut, "/api/v1/raw?project=P1&generation=generation-1", strings.NewReader(`{"resourceType":"Patient","id":"p1"}`+"\n")) - req.Header.Set("Content-Type", "application/x-ndjson") - resp, err := server.App().Test(req) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusForbidden { - t.Fatalf("status = %d, want 403", resp.StatusCode) - } -} diff --git a/internal/api/bulk/load/snapshot_route_test.go b/internal/api/bulk/load/snapshot_route_test.go index e5bf4b37..278f347e 100644 --- a/internal/api/bulk/load/snapshot_route_test.go +++ b/internal/api/bulk/load/snapshot_route_test.go @@ -24,7 +24,7 @@ func (v routePublicationVerifier) VerifyPublication(context.Context, string, str } func TestSnapshotHTTPContractCreateUploadFinalizeStatusAndAbort(t *testing.T) { - store := dataset.NewMemoryLifecycleStore() + store := newMemoryLifecycleStore() runner := &snapshotRunnerFixture{} snapshots := &SnapshotService{Repository: store, Blobs: LocalSnapshotBlobs{Root: t.TempDir()}, Runner: runner} selector := dataset.DataframeSelector{Recipe: "core", TranslationVersion: "v1", Output: "Patient"} diff --git a/internal/api/bulk/load/snapshot_service_test.go b/internal/api/bulk/load/snapshot_service_test.go index 36c8163c..63fef276 100644 --- a/internal/api/bulk/load/snapshot_service_test.go +++ b/internal/api/bulk/load/snapshot_service_test.go @@ -21,7 +21,7 @@ type snapshotRunnerFixture struct { } type stagedManifestRepository struct { - *dataset.MemoryLifecycleStore + *memoryLifecycleStore manifest dataset.Manifest } @@ -36,7 +36,7 @@ func (f *snapshotRunnerFixture) RunGeneration(_ context.Context, request Generat } func TestSnapshotServiceSafeRetryFinalizeAndNoImplicitActivation(t *testing.T) { - store := dataset.NewMemoryLifecycleStore() + store := newMemoryLifecycleStore() runner := &snapshotRunnerFixture{} now := time.Date(2026, 8, 6, 12, 0, 0, 0, time.UTC) blobs := LocalSnapshotBlobs{Root: t.TempDir()} @@ -97,7 +97,7 @@ func TestSnapshotServiceSafeRetryFinalizeAndNoImplicitActivation(t *testing.T) { func TestSnapshotServiceChecksumConflictAndFailurePreservePriorRelease(t *testing.T) { ctx := context.Background() - store := dataset.NewMemoryLifecycleStore() + store := newMemoryLifecycleStore() now := time.Now().UTC() runner := &snapshotRunnerFixture{err: errors.New("invalid rows")} service := &SnapshotService{Repository: store, Blobs: LocalSnapshotBlobs{Root: t.TempDir()}, Runner: runner, Now: func() time.Time { return now }} @@ -123,13 +123,13 @@ func TestSnapshotServiceChecksumConflictAndFailurePreservePriorRelease(t *testin func TestSnapshotFinalizeRecoversWhenLoadCommittedBeforeResponseWasLost(t *testing.T) { ctx := context.Background() - memory := dataset.NewMemoryLifecycleStore() + memory := newMemoryLifecycleStore() now := time.Now().UTC() ref, _ := dataset.NewRef("project-a", "commit-a") schema, _ := dataset.NewSchemaSnapshot("urn:test", "R5", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", []string{"Patient"}) manifest, _ := dataset.NewManifest(ref, schema) manifest, _ = manifest.Transition(dataset.StateStaged) - repository := &stagedManifestRepository{MemoryLifecycleStore: memory, manifest: manifest} + repository := &stagedManifestRepository{memoryLifecycleStore: memory, manifest: manifest} runner := &snapshotRunnerFixture{err: errors.New("connection lost after commit")} service := &SnapshotService{Repository: repository, Blobs: LocalSnapshotBlobs{Root: t.TempDir()}, Runner: runner, Now: func() time.Time { return now }} _, _ = service.CreateOrResume(ctx, "project-a", "commit-a", "", []string{"Patient"}) diff --git a/internal/api/bulk/load/test_server_helpers_test.go b/internal/api/bulk/load/test_server_helpers_test.go index 25ee83fb..d6c8f027 100644 --- a/internal/api/bulk/load/test_server_helpers_test.go +++ b/internal/api/bulk/load/test_server_helpers_test.go @@ -1,23 +1,16 @@ package load import ( - "context" - "errors" - - "github.com/calypr/loom/internal/api/bulk/dump" httpapi "github.com/calypr/loom/internal/api/http" "github.com/calypr/loom/internal/authscope" ) type HTTPConfig struct { Service *Service - RawExporter dump.RawExporter Authenticator authscope.Authenticator Authorizer authscope.Authorizer } -type RawDumpRequest = dump.RawDumpRequest - func NewHTTPServer(cfg HTTPConfig) (*httpapi.HTTPServer, error) { s, err := httpapi.NewHTTPServer(httpapi.HTTPConfig{Authenticator: cfg.Authenticator, Authorizer: cfg.Authorizer}) if err != nil { @@ -28,14 +21,5 @@ func NewHTTPServer(cfg HTTPConfig) (*httpapi.HTTPServer, error) { return nil, err } h.RegisterRoutes(s.App()) - if cfg.RawExporter != nil { - dump.NewHandler(dump.Config{RawExporter: cfg.RawExporter}).RegisterRoutes(s.App()) - } return s, nil } - -type denyAuthorizer struct{} - -func (denyAuthorizer) AuthorizeWrite(context.Context, *authscope.Principal, string, string) error { - return errors.New("nope") -} diff --git a/internal/api/graphql/graph/materialization/service.go b/internal/api/graphql/graph/materialization/service.go index 552cd950..395bdf4b 100644 --- a/internal/api/graphql/graph/materialization/service.go +++ b/internal/api/graphql/graph/materialization/service.go @@ -481,26 +481,6 @@ func readerUnavailable() error { return dataframeerrors.NewError(dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) } -func (s *Service) authorizePublished(ctx context.Context, value dfmaterialization.Materialization) error { - principal, err := s.principal(ctx) - if err != nil { - return err - } - if err := authscope.AuthorizeProject(principal, value.Project, false); err != nil { - return dataframeerrors.NewError(dataframeerrors.CodeDatasetNotFound, "") - } - if s.scopeResolver != nil { - scope, err := s.scopeResolver.ResolveReadScopeForGeneration(ctx, principal, value.Project, value.DatasetGeneration, value.AuthResourcePaths) - if err != nil { - return err - } - if !value.ScopeUnrestricted && scope.Unrestricted() { - return dataframeerrors.NewError(dataframeerrors.CodeDatasetNotFound, "") - } - } - return nil -} - func federatedMaterialization(dataset dfmaterialization.FederatedDataset) dfmaterialization.Materialization { return dfmaterialization.Materialization{ID: "federated:" + dataset.Selector.Key(), Name: dataset.Name, Revision: dataset.Revision, DatasetGeneration: "federated:" + dataset.Revision, State: dfmaterialization.StateReady, Columns: dataset.Columns, RowCount: dataset.RowCount, RowCountKnown: dataset.RowCountComplete, Selector: dataset.Selector, Availability: dataset.Availability, IncludedProjects: len(dataset.Sources), ExpectedProjects: dataset.ExpectedProjects, ProjectStatuses: append([]dfmaterialization.ProjectStatus(nil), dataset.ProjectStatuses...)} } diff --git a/internal/api/graphql/graph/query/fieldrefs.go b/internal/api/graphql/graph/query/fieldrefs.go index 56b27354..c4850191 100644 --- a/internal/api/graphql/graph/query/fieldrefs.go +++ b/internal/api/graphql/graph/query/fieldrefs.go @@ -150,10 +150,6 @@ func decomposeSelector(expression string) FieldSelector { } } -func DecomposeSelector(expression string) FieldSelector { - return decomposeSelector(expression) -} - func fieldSelectorFromSpec(spec fhirschema.FieldSelectorSpec) FieldSelector { var where *FieldPredicate if spec.Where != nil { diff --git a/internal/catalog/capability_evidence.go b/internal/catalog/capability_evidence.go index 3ba0a784..18082d5d 100644 --- a/internal/catalog/capability_evidence.go +++ b/internal/catalog/capability_evidence.go @@ -8,37 +8,6 @@ import ( "sort" ) -// newEvidenceStatus centralizes the empty/partial distinction. A successful -// query with no rows is valid empty evidence; a failed query is unavailable, -// and a bounded profiler result is incomplete/truncated. -func newEvidenceStatus(available, complete, truncated bool, count int) EvidenceStatus { - if !available { - return EvidenceUnavailable - } - if truncated { - return EvidenceTruncated - } - if !complete { - return EvidenceIncomplete - } - if count == 0 { - return EvidenceEmpty - } - return EvidenceAvailable -} - -func unavailableInventory(diagnostics []EvidenceDiagnostic) ResourceInventoryResult { - return ResourceInventoryResult{Values: []ResourceInventoryObservation{}, Status: EvidenceUnavailable, Diagnostics: append([]EvidenceDiagnostic(nil), diagnostics...)} -} - -func unavailableRelationships(diagnostics []EvidenceDiagnostic) RelationshipObservationResult { - return RelationshipObservationResult{Values: []RelationshipObservation{}, Status: EvidenceUnavailable, Diagnostics: append([]EvidenceDiagnostic(nil), diagnostics...)} -} - -func unavailableEnrichment(diagnostics []EvidenceDiagnostic) FieldEnrichmentResult { - return FieldEnrichmentResult{Values: []FieldEnrichmentObservation{}, Status: EvidenceUnavailable, Diagnostics: append([]EvidenceDiagnostic(nil), diagnostics...)} -} - func canonicalDigest(value any) (string, error) { encoded, err := json.Marshal(value) if err != nil { diff --git a/internal/catalog/capability_evidence_test.go b/internal/catalog/capability_evidence_test.go index 54945448..b16abcdd 100644 --- a/internal/catalog/capability_evidence_test.go +++ b/internal/catalog/capability_evidence_test.go @@ -39,15 +39,3 @@ func TestFieldEnrichmentDigestIncludesExactCanonicalRecord(t *testing.T) { t.Fatalf("field enrichment clone lost values: %#v", got) } } - -func TestEvidenceStatusesDistinguishEmptyFailureAndTruncation(t *testing.T) { - if got := newEvidenceStatus(true, true, false, 0); got != EvidenceEmpty { - t.Fatalf("empty status = %q", got) - } - if got := newEvidenceStatus(false, false, false, 0); got != EvidenceUnavailable { - t.Fatalf("failure status = %q", got) - } - if got := newEvidenceStatus(true, false, true, 1); got != EvidenceTruncated { - t.Fatalf("truncated status = %q", got) - } -} diff --git a/internal/catalog/write_profiler.go b/internal/catalog/write_profiler.go index c979b390..8cced6af 100644 --- a/internal/catalog/write_profiler.go +++ b/internal/catalog/write_profiler.go @@ -11,21 +11,10 @@ import ( fhirschema "github.com/calypr/loom/internal/fhir/schema" ) -func NewShapePlanCache() *ShapePlanCache { - return NewShapePlanCacheWithLimit(DefaultProfileLimits().MaxShapePlans) -} - func NewShapePlanCacheWithLimit(maxPlans int) *ShapePlanCache { return &ShapePlanCache{plans: make(map[string]*shapePlan), maxPlans: maxPlans} } -// NewProfilerForGeneration constructs a profiler whose catalog documents are -// bound to one immutable dataset generation. A blank (or whitespace-only) -// generation intentionally selects the legacy namespace for compatibility. -func NewProfilerForGeneration(project, datasetGeneration, authResourcePath, resourceType string, cache *ShapePlanCache) *Profiler { - return NewProfilerForGenerationWithLimits(project, datasetGeneration, authResourcePath, resourceType, cache, DefaultProfileLimits()) -} - // NewProfilerForGenerationWithLimits constructs a profiler with explicit // bounds for every write-side catalog structure. func NewProfilerForGenerationWithLimits(project, datasetGeneration, authResourcePath, resourceType string, cache *ShapePlanCache, limits ProfileLimits) *Profiler { @@ -263,10 +252,6 @@ func (p *Profiler) ensureStat(field *fieldPlan) *fieldCatalogStats { return stat } -func (s *fieldCatalogStats) addDistinct(value string) { - s.addDistinctWithLimits(value, DefaultProfileLimits()) -} - func (s *fieldCatalogStats) addDistinctWithLimits(value string, limits ProfileLimits) { value = strings.TrimSpace(value) if value == "" { @@ -284,10 +269,6 @@ func (s *fieldCatalogStats) addDistinctWithLimits(value string, limits ProfileLi s.distinctValues = append(s.distinctValues, value) } -func (s *fieldCatalogStats) addPivotColumn(value string) { - s.addPivotColumnWithLimits(value, DefaultProfileLimits()) -} - func (s *fieldCatalogStats) addPivotColumnWithLimits(value string, limits ProfileLimits) { value = strings.TrimSpace(value) if value == "" { @@ -305,10 +286,6 @@ func (s *fieldCatalogStats) addPivotColumnWithLimits(value string, limits Profil s.pivotColumns = append(s.pivotColumns, value) } -func (s *fieldCatalogStats) addExtensionValue(observation ExtensionValueObservation) { - s.addExtensionValueWithLimits(observation, DefaultProfileLimits()) -} - func (s *fieldCatalogStats) addExtensionValueWithLimits(observation ExtensionValueObservation, limits ProfileLimits) { limits = limits.normalized() observation.URL = strings.TrimSpace(observation.URL) diff --git a/internal/catalog/write_profiler_test.go b/internal/catalog/write_profiler_test.go index a2e575bb..22822013 100644 --- a/internal/catalog/write_profiler_test.go +++ b/internal/catalog/write_profiler_test.go @@ -12,16 +12,24 @@ import ( fhirschema "github.com/calypr/loom/internal/fhir/schema" ) +func NewShapePlanCache() *ShapePlanCache { + return NewShapePlanCacheWithLimit(DefaultProfileLimits().MaxShapePlans) +} + +func NewProfilerForGeneration(project, datasetGeneration, authResourcePath, resourceType string, cache *ShapePlanCache) *Profiler { + return NewProfilerForGenerationWithLimits(project, datasetGeneration, authResourcePath, resourceType, cache, DefaultProfileLimits()) +} + func TestFieldCatalogRetainsAllDynamicKeys(t *testing.T) { stat := fieldCatalogStats{distinctSet: make(map[string]struct{}), pivotColumnSet: make(map[string]struct{})} for i := range 257 { - stat.addDistinct(strconv.Itoa(i)) + stat.addDistinctWithLimits(strconv.Itoa(i), DefaultProfileLimits()) } if stat.distinctTruncated || len(stat.distinctValues) != 257 { t.Fatalf("distinct values = %d, truncated = %v", len(stat.distinctValues), stat.distinctTruncated) } for i := range 257 { - stat.addPivotColumn(strconv.Itoa(i)) + stat.addPivotColumnWithLimits(strconv.Itoa(i), DefaultProfileLimits()) } if stat.distinctTruncated || len(stat.pivotColumns) != 257 { t.Fatalf("pivot columns = %d, truncated = %v", len(stat.pivotColumns), stat.distinctTruncated) diff --git a/internal/dataframe/compiler/capability/probe.go b/internal/dataframe/compiler/capability/probe.go index 8922e87c..ab7dc7e5 100644 --- a/internal/dataframe/compiler/capability/probe.go +++ b/internal/dataframe/compiler/capability/probe.go @@ -105,15 +105,6 @@ type CostPolicy interface { Allow(context.Context, CostEstimate) error } -type CostPolicyFunc func(context.Context, CostEstimate) error - -func (f CostPolicyFunc) Allow(ctx context.Context, estimate CostEstimate) error { - if f == nil { - return nil - } - return f(ctx, estimate) -} - // Options controls the explicitly authorized physical rewrite and cost // policy. The default is the same conservative policy used by normal recipe // compilation. @@ -302,93 +293,6 @@ func ProbeCandidate(ctx context.Context, request CandidateRequest, options ...Op return Result{Candidate: &metadata, Rendered: rendered}, nil } -// Request groups probes for snapshot construction. Unsupported entries are -// returned as diagnostics so a caller can retain audit evidence while only -// publishing successful capabilities. -type Request struct { - Scope Scope - RootResourceType string - Roots []string - Traversals []Traversal - Candidates []CandidateRequest -} - -type Diagnostic struct { - Kind string - Message string -} - -type Snapshot struct { - Roots []RootCapability - Traversals []TraversalCapability - Candidates []CandidateCapability - Diagnostics []Diagnostic -} - -func ProbeCapabilities(ctx context.Context, request Request, options ...Options) (Snapshot, error) { - optionsValue := optionsFor(options) - roots := append([]string(nil), request.Roots...) - if len(roots) == 0 && strings.TrimSpace(request.RootResourceType) != "" { - roots = []string{request.RootResourceType} - } - if optionsValue.Cost != nil { - if err := optionsValue.Cost.Allow(ctx, CostEstimate{TraversalCount: len(request.Traversals), CandidateCount: len(request.Candidates)}); err != nil { - return Snapshot{}, err - } - } - snapshot := Snapshot{} - for _, root := range roots { - result, err := ProbeRoot(ctx, RootRequest{Scope: request.Scope, ResourceType: root}, optionsValue) - if err != nil { - snapshot.Diagnostics = append(snapshot.Diagnostics, Diagnostic{Kind: "root", Message: err.Error()}) - continue - } - snapshot.Roots = append(snapshot.Roots, *result.Root) - } - for _, route := range request.Traversals { - result, err := ProbeTraversal(ctx, TraversalRequest{Scope: request.Scope, RootResourceType: request.RootResourceType, Traversal: route}, optionsValue) - if err != nil { - snapshot.Diagnostics = append(snapshot.Diagnostics, Diagnostic{Kind: "traversal", Message: err.Error()}) - continue - } - snapshot.Traversals = append(snapshot.Traversals, *result.Traversal) - } - for _, candidate := range request.Candidates { - if candidate.Project == "" { - candidate.Scope = request.Scope - } - result, err := ProbeCandidate(ctx, candidate, optionsValue) - if err != nil { - snapshot.Diagnostics = append(snapshot.Diagnostics, Diagnostic{Kind: "candidate", Message: err.Error()}) - continue - } - snapshot.Candidates = append(snapshot.Candidates, *result.Candidate) - } - return snapshot, nil -} - -// Probe is the concise entry point for callers constructing a capability -// snapshot. The named ProbeCapabilities form remains useful at call sites -// where the distinction from the individual probes matters. -func Probe(ctx context.Context, request Request, options ...Options) (Snapshot, error) { - return ProbeCapabilities(ctx, request, options...) -} - -// ProbeZeroHop and ProbeOneHop are descriptive aliases for the primitive -// probes, kept small so backend adapters do not need to know the package's -// internal naming choices. -func ProbeZeroHop(ctx context.Context, request RootRequest, options ...Options) (Result, error) { - return ProbeRoot(ctx, request, options...) -} - -func ProbeOneHop(ctx context.Context, request TraversalRequest, options ...Options) (Result, error) { - return ProbeTraversal(ctx, request, options...) -} - -func ProbeSelection(ctx context.Context, request CandidateRequest, options ...Options) (Result, error) { - return ProbeCandidate(ctx, request, options...) -} - type preparedCandidate struct { scope Scope resourceType string diff --git a/internal/dataframe/published/aggregate_sql.go b/internal/dataframe/published/aggregate_sql.go index adbc5094..b1950723 100644 --- a/internal/dataframe/published/aggregate_sql.go +++ b/internal/dataframe/published/aggregate_sql.go @@ -291,10 +291,6 @@ func groupingMaskExpression(columns []string) string { return strings.Join(terms, " + ") } -func legacyMetric(job AggregateJob) string { - return legacyMetricOnColumn(job, job.Column) -} - func legacyMetricOnColumn(job AggregateJob, column string) string { switch job.Operation { case "COUNT_DISTINCT": diff --git a/internal/dataframe/published/federation.go b/internal/dataframe/published/federation.go index 8243cdce..3252b61b 100644 --- a/internal/dataframe/published/federation.go +++ b/internal/dataframe/published/federation.go @@ -1033,10 +1033,10 @@ func federatedNormalizedUnion(dataset FederatedDataset, columns []string, access func validateReaderColumns(columns []string, allowed map[string]struct{}) error { for _, column := range columns { if column == "__loom_row_id" || column == "__loom_global_row_id" { - return fmt.Errorf("column %q is internal to dataframe pagination", column) + return dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, fmt.Sprintf("column %q is internal to dataframe pagination", column)) } if _, ok := allowed[column]; !ok { - return fmt.Errorf("column %q is not in federated dataset schema", column) + return dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, fmt.Sprintf("column %q is not in federated dataset schema", column)) } } return nil diff --git a/internal/dataframe/published/federation_test.go b/internal/dataframe/published/federation_test.go index 677387e0..7b7aab9f 100644 --- a/internal/dataframe/published/federation_test.go +++ b/internal/dataframe/published/federation_test.go @@ -151,6 +151,22 @@ func TestFederatedUnionSynthesizesProjectIDForLegacySource(t *testing.T) { } } +func TestFederatedColumnsRejectsUnknownTableColumnAsInvalidRequest(t *testing.T) { + _, _, err := federatedColumns(FederatedDataset{ + Columns: []Column{{Name: "patient_id", ClickHouse: "String"}}, + }, []string{"stale_column"}, nil) + userErr, ok := dataframeerrors.AsUserError(err) + if !ok { + t.Fatalf("error = %v, want typed user error", err) + } + if userErr.Code() != string(dataframeerrors.CodeInvalidRequest) { + t.Fatalf("error code = %q, want INVALID_REQUEST", userErr.Code()) + } + if userErr.Retryable() { + t.Fatal("unknown table column must not be retryable") + } +} + type federationCatalog struct { bundlepublication.BundleCatalog executions []bundlepublication.BundleExecution diff --git a/internal/dataframe/published/read.go b/internal/dataframe/published/read.go index 1d95e9b2..024f6198 100644 --- a/internal/dataframe/published/read.go +++ b/internal/dataframe/published/read.go @@ -167,21 +167,6 @@ func decodeCursor(cursor string) (*pageCursor, error) { return &value, nil } -func cursorPredicate(cursor *pageCursor, sort *Sort) (string, []any, error) { - row := "toString(`__loom_row_id`) > ?" - if sort == nil { - return row, []any{cursor.RowID}, nil - } - if cursor.SortValue == nil { - return "", nil, dataframeerrors.NewError(dataframeerrors.CodeInvalidCursor, "") - } - operator := ">" - if sort.Desc { - operator = "<" - } - return fmt.Sprintf("(`%s` %s ? OR (`%s` = ? AND %s))", sort.Column, operator, sort.Column, row), []any{cursor.SortValue, cursor.SortValue, cursor.RowID}, nil -} - func contains(values []string, needle string) bool { for _, value := range values { if value == needle { diff --git a/internal/dataframe/published/read_test.go b/internal/dataframe/published/read_test.go index 821acfc6..d3739928 100644 --- a/internal/dataframe/published/read_test.go +++ b/internal/dataframe/published/read_test.go @@ -14,13 +14,6 @@ func TestKeysetCursorRoundTrip(t *testing.T) { if decoded.RowID != "42" || decoded.SortValue != "alice" { t.Fatalf("decoded cursor = %#v", decoded) } - predicate, args, err := cursorPredicate(decoded, &Sort{Column: "name"}) - if err != nil { - t.Fatal(err) - } - if predicate == "" || len(args) != 3 || predicate != "(`name` > ? OR (`name` = ? AND toString(`__loom_row_id`) > ?))" { - t.Fatalf("unexpected sort predicate %q", predicate) - } } func TestBuildWhereSupportsAggregateFilters(t *testing.T) { diff --git a/internal/dataframe/recipe/document_types.go b/internal/dataframe/recipe/document_types.go index 1a21619b..682bbd27 100644 --- a/internal/dataframe/recipe/document_types.go +++ b/internal/dataframe/recipe/document_types.go @@ -338,7 +338,7 @@ type DynamicColumn struct { // ColumnSourceKeys decouples a public frozen column name from the runtime // keyed-map lookup key. Extension columns use this for parent__child names // while matching the leaf Extension.url segment inside its scoped source. - ColumnSourceKeys map[string]string `json:"-"` + ColumnSourceKeys map[string]string `json:"columnSourceKeys,omitempty"` Discovered bool `json:"-"` } diff --git a/internal/dataframe/recipe/exec/persistent.go b/internal/dataframe/recipe/exec/persistent.go index 10adc45e..ea18753e 100644 --- a/internal/dataframe/recipe/exec/persistent.go +++ b/internal/dataframe/recipe/exec/persistent.go @@ -77,14 +77,6 @@ func (r PersistentRegistry) RegisterVersion(ctx context.Context, bundle recipe.B return entry, nil } -func (r PersistentRegistry) LoadVersion(ctx context.Context, name, translationVersion string) (Entry, error) { - store, ok := r.Store.(VersionedStore) - if !ok { - return Entry{}, fmt.Errorf("persistent recipe store does not support versioned recipes") - } - return store.LoadRecipeVersion(ctx, name, translationVersion) -} - func canonicalEntry(bundle recipe.Bundle) (Entry, error) { if bundle.Fragments != nil { expanded, err := bundle.ExpandFragments() diff --git a/internal/dataframe/recipe/exec/persistent_test.go b/internal/dataframe/recipe/exec/persistent_test.go index 92e80468..d9c14c11 100644 --- a/internal/dataframe/recipe/exec/persistent_test.go +++ b/internal/dataframe/recipe/exec/persistent_test.go @@ -67,14 +67,6 @@ func TestPersistentRegistryRetainsVersions(t *testing.T) { if first.Digest == second.Digest || len(store.entries) != 2 { t.Fatalf("recipe history was not retained: first=%#v second=%#v stored=%#v", first, second, store.entries) } - loadedFirst, err := registry.LoadVersion(context.Background(), "default", "v") - if err != nil || loadedFirst.Digest != first.Digest { - t.Fatalf("first version is not independently queryable: loaded=%#v err=%v", loadedFirst, err) - } - loadedSecond, err := registry.LoadVersion(context.Background(), "default", "changed") - if err != nil || loadedSecond.Digest != second.Digest { - t.Fatalf("second version is not independently queryable: loaded=%#v err=%v", loadedSecond, err) - } } func TestPersistentRegistryRejectsChangedDigestAfterUse(t *testing.T) { diff --git a/internal/dataframe/recipe/revisions.go b/internal/dataframe/recipe/revisions.go index 37f46204..608e15a7 100644 --- a/internal/dataframe/recipe/revisions.go +++ b/internal/dataframe/recipe/revisions.go @@ -3,8 +3,6 @@ package recipe import ( "context" "errors" - "fmt" - "sync" "time" ) @@ -27,75 +25,3 @@ type RevisionStore interface { Get(context.Context, string, string, string) (RecipeRevision, error) List(context.Context, string, string) ([]RecipeRevision, error) } - -// MemoryRevisionStore is the default process-local implementation. Production -// deployments can replace it with a durable project registry without changing -// compiler or GraphQL contracts. -type MemoryRevisionStore struct { - mu sync.RWMutex - values map[string]RecipeRevision - current map[string]string -} - -func NewMemoryRevisionStore() *MemoryRevisionStore { - return &MemoryRevisionStore{values: make(map[string]RecipeRevision), current: make(map[string]string)} -} - -func revisionKey(project, name, digest string) string { - return project + "\x00" + name + "\x00" + digest -} -func currentKey(project, name string) string { return project + "\x00" + name } - -func (s *MemoryRevisionStore) Register(_ context.Context, project string, bundle Bundle, parent string) (RecipeRevision, error) { - if s == nil { - return RecipeRevision{}, fmt.Errorf("recipe revision store is required") - } - if project == "" || bundle.Name == "" { - return RecipeRevision{}, fmt.Errorf("project and recipe name are required") - } - if err := bundle.Validate(); err != nil { - return RecipeRevision{}, err - } - digest, err := bundle.Digest() - if err != nil { - return RecipeRevision{}, err - } - now := time.Now().UTC() - revision := RecipeRevision{Project: project, Name: bundle.Name, Digest: digest, Parent: parent, Bundle: bundle, CreatedAt: now} - s.mu.Lock() - defer s.mu.Unlock() - key := revisionKey(project, bundle.Name, digest) - if existing, ok := s.values[key]; ok { - return existing, nil - } - if parent != "" { - if current := s.current[currentKey(project, bundle.Name)]; current != "" && current != parent { - return RecipeRevision{}, fmt.Errorf("recipe revision parent %q is not current (current %q)", parent, current) - } - } - s.values[key] = revision - s.current[currentKey(project, bundle.Name)] = digest - return revision, nil -} - -func (s *MemoryRevisionStore) Get(_ context.Context, project, name, digest string) (RecipeRevision, error) { - s.mu.RLock() - defer s.mu.RUnlock() - value, ok := s.values[revisionKey(project, name, digest)] - if !ok { - return RecipeRevision{}, ErrRecipeRevisionNotFound - } - return value, nil -} - -func (s *MemoryRevisionStore) List(_ context.Context, project, name string) ([]RecipeRevision, error) { - s.mu.RLock() - defer s.mu.RUnlock() - result := make([]RecipeRevision, 0) - for _, value := range s.values { - if value.Project == project && value.Name == name { - result = append(result, value) - } - } - return result, nil -} diff --git a/internal/dataframe/recipe/revisions_test.go b/internal/dataframe/recipe/revisions_test.go deleted file mode 100644 index b116ed65..00000000 --- a/internal/dataframe/recipe/revisions_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package recipe - -import ( - "context" - "testing" -) - -func TestMemoryRevisionStoreRegistersImmutableProjectRevision(t *testing.T) { - store := NewMemoryRevisionStore() - bundle := Bundle{RecipeSchemaVersion: CurrentSchemaVersion, Name: "files", TranslationVersion: "1", Outputs: []Output{{Name: "DocumentReference", RootResourceType: "DocumentReference", RowGrain: "document_reference"}}} - revision, err := store.Register(context.Background(), "project-a", bundle, "") - if err != nil { - t.Fatal(err) - } - if revision.Digest == "" || revision.Project != "project-a" { - t.Fatalf("revision = %+v", revision) - } - loaded, err := store.Get(context.Background(), "project-a", "files", revision.Digest) - if err != nil { - t.Fatal(err) - } - if loaded.Digest != revision.Digest || loaded.Bundle.Name != "files" { - t.Fatalf("loaded revision = %+v", loaded) - } - if _, err := store.Get(context.Background(), "project-b", "files", revision.Digest); err != ErrRecipeRevisionNotFound { - t.Fatalf("cross-project lookup error = %v", err) - } -} diff --git a/internal/dataframe/semantic/recipe_plan_output.go b/internal/dataframe/semantic/recipe_plan_output.go index 176372e2..144771f7 100644 --- a/internal/dataframe/semantic/recipe_plan_output.go +++ b/internal/dataframe/semantic/recipe_plan_output.go @@ -287,7 +287,7 @@ func buildRecipeDynamicMaps(items []recipe.DynamicColumn, scope scopeFrame, path // to mark an optional family as resolved with zero discovered keys. columns = append([]string{}, dynamic.Columns...) } - item := SemanticDynamicMap{Name: dynamic.Name, ScopeAlias: scopeAlias, ResourceType: resourceType, Columns: columns, MaxColumns: dynamic.MaxColumns, ColumnTypes: dynamic.ColumnTypes, ColumnSourceKeys: dynamic.ColumnSourceKeys, Discovered: dynamic.Discovered} + item := SemanticDynamicMap{Name: dynamic.Name, ScopeAlias: scopeAlias, ResourceType: resourceType, Columns: columns, MaxColumns: dynamic.MaxColumns, ColumnTypes: dynamic.ColumnTypes, ColumnSourceKeys: dynamic.ColumnSourceKeys, AllowUnknownKeys: len(dynamic.ColumnSourceKeys) > 0, Discovered: dynamic.Discovered} if dynamic.ColumnPrefix != nil { prefix := *dynamic.ColumnPrefix item.ColumnPrefix = &prefix diff --git a/internal/dataframe/semantic/resolved_plan_test.go b/internal/dataframe/semantic/resolved_plan_test.go index 79e3b7f1..d6d713eb 100644 --- a/internal/dataframe/semantic/resolved_plan_test.go +++ b/internal/dataframe/semantic/resolved_plan_test.go @@ -47,6 +47,7 @@ func TestResolveRecipePlanHonorsExplicitEmptyDynamicColumnPrefix(t *testing.T) { Source: recipe.Expression{Select: "content[].attachment.extension[]"}, Key: &recipe.Expression{Call: "last_segment", Args: []recipe.Expression{{Select: "item.url"}}}, Value: &recipe.Expression{Select: "item.valueString"}, Columns: []string{"source_path"}, MaxColumns: 4, + ColumnSourceKeys: map[string]string{"source_path": "https://example.test/source_path"}, }}, }}, } @@ -54,12 +55,15 @@ func TestResolveRecipePlanHonorsExplicitEmptyDynamicColumnPrefix(t *testing.T) { if err != nil { t.Fatal(err) } + if len(plan.Outputs) != 1 || len(plan.Outputs[0].Root.DynamicMaps) != 1 || !plan.Outputs[0].Root.DynamicMaps[0].AllowUnknownKeys { + t.Fatalf("fixed keyed map must ignore unrelated sibling keys: %#v", plan.Outputs) + } resolved, err := ResolveRecipePlan(plan, "scope-1", "g") if err != nil { t.Fatal(err) } columns := resolved.ResolvedColumns["DocumentReference:attachment_extensions"] - if len(columns) != 1 || columns[0].Column.Name != "source_path" || columns[0].Column.SourceKey != "source_path" { + if len(columns) != 1 || columns[0].Column.Name != "source_path" || columns[0].Column.SourceKey != "https://example.test/source_path" { t.Fatalf("unexpected compatibility dynamic column: %#v", columns) } } diff --git a/internal/dataset/inventory.go b/internal/dataset/inventory.go index c9dce0af..47d722e0 100644 --- a/internal/dataset/inventory.go +++ b/internal/dataset/inventory.go @@ -15,6 +15,15 @@ type ProjectInventory struct { Executions ExecutionProjectSource } +func sortedSet(values map[string]struct{}) []string { + result := make([]string, 0, len(values)) + for value := range values { + result = append(result, value) + } + sort.Strings(result) + return result +} + // ExpectedProjects returns only caller-authorized identities in auth mode. In // no-auth development mode it exposes every project observed through snapshot // sessions, releases, or publication attempts, including projects that never diff --git a/internal/dataset/memory_store.go b/internal/dataset/memory_store_test.go similarity index 95% rename from internal/dataset/memory_store.go rename to internal/dataset/memory_store_test.go index 04609ad9..170d9d70 100644 --- a/internal/dataset/memory_store.go +++ b/internal/dataset/memory_store_test.go @@ -9,8 +9,7 @@ import ( "time" ) -// MemoryLifecycleStore is a concurrency-correct reference implementation used -// by contract tests and embedders that do not need durable persistence. +// MemoryLifecycleStore is a concurrency-correct test implementation. type MemoryLifecycleStore struct { mu sync.RWMutex snapshots map[Ref]SnapshotGeneration @@ -209,14 +208,5 @@ func contains(values []string, target string) bool { return false } -func sortedSet(values map[string]struct{}) []string { - result := make([]string, 0, len(values)) - for value := range values { - result = append(result, value) - } - sort.Strings(result) - return result -} - var _ SnapshotRepository = (*MemoryLifecycleStore)(nil) var _ ReleaseRepository = (*MemoryLifecycleStore)(nil) diff --git a/internal/explorer/arango/capability_snapshot_store.go b/internal/explorer/arango/capability_snapshot_store.go index adc6b7cf..d41f1840 100644 --- a/internal/explorer/arango/capability_snapshot_store.go +++ b/internal/explorer/arango/capability_snapshot_store.go @@ -41,11 +41,6 @@ func NewCapabilitySnapshotStore(c client) (*CapabilitySnapshotStore, error) { return &CapabilitySnapshotStore{client: c}, nil } -// NewSnapshotStore is a concise compatibility constructor. -func NewSnapshotStore(c client) (*CapabilitySnapshotStore, error) { - return NewCapabilitySnapshotStore(c) -} - func (s *CapabilitySnapshotStore) Put(ctx context.Context, snapshot capability.Snapshot) (*capability.Snapshot, error) { if err := capabilitystore.ValidateSnapshot(snapshot); err != nil { return nil, err diff --git a/internal/explorer/arango/receipt_store_test.go b/internal/explorer/arango/receipt_store_test.go index efc8d86c..5bc00383 100644 --- a/internal/explorer/arango/receipt_store_test.go +++ b/internal/explorer/arango/receipt_store_test.go @@ -28,9 +28,6 @@ func (c *receiptClient) QueryRows(_ context.Context, query string, _ int, binds } return visit(c.doc) } - if strings.Contains(query, "oldestCreatedAt") { - return visit(map[string]any{"count": 1, "approxBytes": 128, "oldestCreatedAt": "2026-01-01T00:00:00Z", "unreferencedCount": 1}) - } if c.doc != nil { return visit(c.doc) } @@ -80,21 +77,6 @@ func TestReceiptArangoStoreUsesImmutableTenantScopedQueries(t *testing.T) { } } -func TestReceiptArangoStats(t *testing.T) { - client := &receiptClient{} - adapter, err := New(client) - if err != nil { - t.Fatal(err) - } - stats, err := adapter.CompilationReceiptStats(context.Background(), "project-a") - if err != nil { - t.Fatal(err) - } - if stats.Count != 1 || stats.ApproxBytes != 128 || stats.UnreferencedCount != 1 { - t.Fatalf("stats=%+v", stats) - } -} - func testReceiptBundle() recipe.Bundle { return recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "receipt-test", TranslationVersion: "test", Outputs: []recipe.Output{{Name: "output", RootResourceType: "Patient", RowGrain: "resource"}}} } diff --git a/internal/explorer/arango/store.go b/internal/explorer/arango/store.go index ce7680c5..f2484866 100644 --- a/internal/explorer/arango/store.go +++ b/internal/explorer/arango/store.go @@ -40,50 +40,6 @@ func explorerKey(project, id string) string { return "explorer_" + key(project, func repositoryConfigKey(project string) string { return "repository_config_" + key(project, "default") } -func configKey(project, id string) string { return "explorer_config_" + key(project, id) } -func (s *Store) ListConfigs(ctx context.Context, project string) ([]explorer.RepositoryConfig, error) { - out := []explorer.RepositoryConfig{} - err := s.client.QueryRows(ctx, `FOR d IN @@c FILTER d.project == @project SORT d.explorerId RETURN d`, 1000, map[string]any{"@c": RepositoryConfigsCollection, "project": project}, func(row map[string]any) error { - v, err := decode[explorer.RepositoryConfig](row) - if err == nil { - out = append(out, v) - } - return err - }) - for i := range out { - if out[i].ExplorerID == "" { - out[i].ExplorerID, out[i].Management = "default", explorer.ManagementRepository - } - } - return out, err -} -func (s *Store) GetConfig(ctx context.Context, project, id string) (*explorer.RepositoryConfig, error) { - var out *explorer.RepositoryConfig - err := s.client.QueryRows(ctx, `FOR d IN @@c FILTER d._key == @key RETURN d`, 1, map[string]any{"@c": RepositoryConfigsCollection, "key": configKey(project, id)}, func(row map[string]any) error { v, err := decode[explorer.RepositoryConfig](row); out = &v; return err }) - if err != nil { - return nil, err - } - if out == nil { - return nil, explorer.ErrNotFound - } - if out.ExplorerID == "" { - out.ExplorerID, out.Management = "default", explorer.ManagementRepository - } - return out, nil -} -func (s *Store) SaveConfig(ctx context.Context, value explorer.RepositoryConfig) (*explorer.RepositoryConfig, error) { - value.UpdatedAt = time.Now().UTC() - doc, err := document(value, configKey(value.Project, value.ExplorerID)) - if err != nil { - return nil, err - } - var out *explorer.RepositoryConfig - err = s.client.QueryRows(ctx, `UPSERT { _key: @key } INSERT @doc UPDATE @doc IN @@c RETURN NEW`, 1, map[string]any{"@c": RepositoryConfigsCollection, "key": configKey(value.Project, value.ExplorerID), "doc": doc}, func(row map[string]any) error { v, err := decode[explorer.RepositoryConfig](row); out = &v; return err }) - if err != nil { - return nil, err - } - return out, nil -} func (s *Store) GetRepositoryConfig(ctx context.Context, project string) (*explorer.RepositoryConfig, error) { var out *explorer.RepositoryConfig err := s.client.QueryRows(ctx, `FOR d IN @@c FILTER d._key == @key RETURN d`, 1, map[string]any{"@c": RepositoryConfigsCollection, "key": repositoryConfigKey(project)}, func(row map[string]any) error { v, err := decode[explorer.RepositoryConfig](row); out = &v; return err }) @@ -158,8 +114,12 @@ func (s *Store) SaveDraft(ctx context.Context, e explorer.Explorer, expected int if err != nil { return nil, err } + digest := "" + if len(expectedDigest) > 0 { + digest = strings.TrimSpace(expectedDigest[0]) + } var out *explorer.Explorer - err = s.client.QueryRows(ctx, `FOR d IN @@c FILTER d._key == @key UPDATE d WITH MERGE(@doc, { draftVersion: d.draftVersion + 1 }) IN @@c RETURN NEW`, 1, map[string]any{"@c": ExplorersCollection, "key": explorerKey(e.Project, e.ExplorerID), "doc": raw}, func(row map[string]any) error { v, err := decode[explorer.Explorer](row); out = &v; return err }) + err = s.client.QueryRows(ctx, `FOR d IN @@c FILTER d._key == @key AND (d.draftVersion == @expected OR (!HAS(d, "draftVersion") AND @expected == 0)) AND (@expectedDigest == "" OR d.draftDigest == @expectedDigest) UPDATE d WITH MERGE(@doc, { draftVersion: NOT_NULL(d.draftVersion, 0) + 1 }) IN @@c RETURN NEW`, 1, map[string]any{"@c": ExplorersCollection, "key": explorerKey(e.Project, e.ExplorerID), "expected": expected, "expectedDigest": digest, "doc": raw}, func(row map[string]any) error { v, err := decode[explorer.Explorer](row); out = &v; return err }) if err != nil { return nil, err } @@ -187,11 +147,7 @@ func (s *Store) InsertCompilationReceipt(ctx context.Context, receipt explorer.C if receipt.Project != "" && receipt.ExplorerID != "" { return s.GetCompilationReceiptForExplorer(ctx, receipt.Project, receipt.ExplorerID, receipt.ID) } - return s.GetCompilationReceipt(ctx, receipt.ID) -} - -func (s *Store) GetCompilationReceipt(ctx context.Context, id string) (*explorer.CompilationReceipt, error) { - return s.readCompilationReceipt(ctx, `FOR d IN @@c FILTER d._key == @key RETURN d`, map[string]any{"@c": CompilationReceiptsCollection, "key": id}) + return s.GetCompilationReceiptForExplorer(ctx, receipt.Project, receipt.ExplorerID, receipt.ID) } func (s *Store) GetCompilationReceiptForExplorer(ctx context.Context, project, explorerID, id string) (*explorer.CompilationReceipt, error) { @@ -250,43 +206,6 @@ func sameReceipt(a, b explorer.CompilationReceipt) bool { return leftErr == nil && rightErr == nil && left == right } -func (s *Store) CompilationReceiptStats(ctx context.Context, project string) (explorer.ReceiptStoreStats, error) { - var row struct { - Count int `json:"count"` - ApproxBytes int64 `json:"approxBytes"` - OldestCreatedAt string `json:"oldestCreatedAt"` - UnreferencedCount int `json:"unreferencedCount"` - } - err := s.client.QueryRows(ctx, `LET referenced = (FOR r IN @@revisions FILTER r.compilationReceiptId != null AND (@project == "" OR r.project == @project) RETURN r.compilationReceiptId) LET receipts = (FOR d IN @@receipts FILTER @project == "" OR d.project == @project RETURN d) RETURN {count: LENGTH(receipts), approxBytes: SUM(FOR d IN receipts RETURN LENGTH(TO_STRING(d))), oldestCreatedAt: MIN(FOR d IN receipts RETURN d.createdAt), unreferencedCount: LENGTH(FOR d IN receipts FILTER d._key NOT IN referenced RETURN 1)}`, 1, map[string]any{"@receipts": CompilationReceiptsCollection, "@revisions": RevisionsCollection, "project": project}, func(value map[string]any) error { - decoded, err := decode[struct { - Count int `json:"count"` - ApproxBytes int64 `json:"approxBytes"` - OldestCreatedAt string `json:"oldestCreatedAt"` - UnreferencedCount int `json:"unreferencedCount"` - }](value) - if err != nil { - return err - } - row.Count, row.ApproxBytes, row.OldestCreatedAt, row.UnreferencedCount = decoded.Count, decoded.ApproxBytes, decoded.OldestCreatedAt, decoded.UnreferencedCount - return nil - }) - if err != nil { - return explorer.ReceiptStoreStats{}, err - } - stats := explorer.ReceiptStoreStats{Count: row.Count, ApproxBytes: row.ApproxBytes, UnreferencedCount: row.UnreferencedCount} - if row.OldestCreatedAt != "" { - parsed, parseErr := time.Parse(time.RFC3339Nano, row.OldestCreatedAt) - if parseErr != nil { - parsed, parseErr = time.Parse(time.RFC3339, row.OldestCreatedAt) - } - if parseErr != nil { - return explorer.ReceiptStoreStats{}, fmt.Errorf("invalid receipt oldestCreatedAt: %w", parseErr) - } - stats.OldestCreatedAt = parsed - } - return stats, nil -} - func (s *Store) PublishAuthoring(ctx context.Context, receipt explorer.CompilationReceipt, revision explorer.Revision) (*explorer.Revision, error) { if err := validateReceipt(receipt); err != nil { return nil, err @@ -350,19 +269,6 @@ func (s *Store) PublishAuthoring(ctx context.Context, receipt explorer.Compilati return out, err } -func (s *Store) PurgeDraftAuthoring(ctx context.Context) error { - return s.client.WithTransaction(ctx, store.TransactionCollections{Write: []string{ExplorersCollection, CompilationReceiptsCollection}, Read: []string{RevisionsCollection}}, func(txCtx context.Context, tx store.Transaction) error { - // UNSET returns the complete cleaned document. Use REPLACE here: UPDATE - // merges that result back into the original document, which leaves every - // retired draft field in place and makes the cutover appear to succeed - // while preserving the legacy state. - if err := tx.QueryRows(txCtx, `FOR d IN @@explorers REPLACE d WITH UNSET(d, "draftConfig", "draftVersion", "draftDigest", "draftAuthoringBundle", "draftIntentDigest", "draftReceiptId", "draftIdentityMappings", "draftDefinition", "authoringBundle", "intentDigest", "receiptPointer", "identityMappings", "version", "digest") IN @@explorers RETURN {purged: true}`, 100000, map[string]any{"@explorers": ExplorersCollection}, func(map[string]any) error { return nil }); err != nil { - return err - } - return tx.QueryRows(txCtx, `LET referenced = (FOR r IN @@revisions FILTER r.compilationReceiptId != null RETURN DISTINCT r.compilationReceiptId) FOR receipt IN @@receipts FILTER receipt._key NOT IN referenced REMOVE receipt IN @@receipts RETURN {purged: true}`, 100000, map[string]any{"@revisions": RevisionsCollection, "@receipts": CompilationReceiptsCollection}, func(map[string]any) error { return nil }) - }) -} - func (s *Store) InsertRevision(ctx context.Context, revision explorer.Revision) (*explorer.Revision, error) { if revision.ID == "" { return nil, fmt.Errorf("revision ID is required") @@ -448,35 +354,6 @@ type activationState struct { prior map[string]any } -func (s *Store) ActivateInteractive(ctx context.Context, project, explorerID, revisionID string) error { - return s.activateOwnerRevision(ctx, project, explorerID, revisionID, explorer.ManagementInteractive, []string{ExplorersCollection, RevisionsCollection}) -} - -func (s *Store) ActivateRepository(ctx context.Context, project, revisionID string) error { - return s.activateOwnerRevision(ctx, project, "default", revisionID, explorer.ManagementRepository, []string{ExplorersCollection, RevisionsCollection}) -} - -func (s *Store) activateOwnerRevision(ctx context.Context, project, explorerID, revisionID string, management explorer.ManagementMode, writeCollections []string) error { - return s.client.WithTransaction(ctx, store.TransactionCollections{Write: writeCollections}, func(txCtx context.Context, tx store.Transaction) error { - row, found, err := readActivationRow(txCtx, tx, activationReadAQL, map[string]any{ - "@explorers": ExplorersCollection, "@revisions": RevisionsCollection, - "explorerKey": explorerKey(project, explorerID), "revisionKey": revisionID, - "project": project, "explorerId": explorerID, "management": management, - }) - if err != nil { - return err - } - if !found { - return explorer.ErrDraftConflict - } - state, err := activationStateFromRow(row) - if err != nil { - return err - } - return activateRevisionAndOwner(txCtx, tx, state, time.Now().UTC()) - }) -} - // ActivateRepositoryGeneration is the repository-only composite visibility // switch. It validates all pointers first, then performs each single-collection // modification inside one Arango transaction so no partial activation is diff --git a/internal/explorer/arango/store_test.go b/internal/explorer/arango/store_test.go index db130514..9e61ecf0 100644 --- a/internal/explorer/arango/store_test.go +++ b/internal/explorer/arango/store_test.go @@ -103,18 +103,6 @@ func TestActivationUsesTransactionsAndSingleModificationQueries(t *testing.T) { name string call func(context.Context, *Store) error }{ - { - name: "interactive", - call: func(ctx context.Context, store *Store) error { - return store.ActivateInteractive(ctx, "project-a", "explorer-a", "revision-a") - }, - }, - { - name: "repository", - call: func(ctx context.Context, store *Store) error { - return store.ActivateRepository(ctx, "project-a", "revision-a") - }, - }, { name: "repository generation", call: func(ctx context.Context, store *Store) error { diff --git a/internal/explorer/authoring_errors.go b/internal/explorer/authoring_errors.go new file mode 100644 index 00000000..bab1cf5f --- /dev/null +++ b/internal/explorer/authoring_errors.go @@ -0,0 +1,31 @@ +package explorer + +type AuthoringDiagnostic struct { + Severity string `json:"severity"` + Stage string `json:"stage"` + Code string `json:"code"` + JSONPath string `json:"jsonPath"` + Message string `json:"message"` + Details map[string]any `json:"details,omitempty"` + RequestID string `json:"requestId,omitempty"` +} + +type AuthoringError struct { + Status int + Diagnostic AuthoringDiagnostic + Cause error +} + +func (e *AuthoringError) Error() string { + if e == nil { + return "Explorer authoring error" + } + return e.Diagnostic.Code + ": " + e.Diagnostic.Message +} + +func (e *AuthoringError) Unwrap() error { + if e == nil { + return nil + } + return e.Cause +} diff --git a/internal/explorer/authoring_v1.go b/internal/explorer/authoring_v1.go deleted file mode 100644 index 627286d7..00000000 --- a/internal/explorer/authoring_v1.go +++ /dev/null @@ -1,470 +0,0 @@ -package explorer - -// This file is the versioned Explorer authoring wire contract. It is kept in -// the Explorer domain package so HTTP, ETL, and repository bootstrap callers -// share one decoder and one canonical digest implementation. - -import ( - "bytes" - "crypto/sha256" - "encoding/hex" - "encoding/json" - "fmt" - "io" - "sort" - "strings" -) - -const ( - ExplorerAuthoringV1APIVersion = "loom.calypr.org/explorer-authoring/v1" - ExplorerAuthoringV1Kind = "ExplorerAuthoringBundle" - ExplorerBuilderV1Kind = "ExplorerBuilderDocument" -) - -// ExplorerAuthoringBundleV1 is the portable authoring artifact. Intent is -// the only durable browser-facing representation. The compiled recipe is -// held by CompilationReceipt and never appears in this document. -type ExplorerAuthoringBundleV1 struct { - APIVersion string `json:"apiVersion"` - Kind string `json:"kind"` - Project string `json:"project"` - ExplorerID string `json:"explorerId"` - Title string `json:"title,omitempty"` - // Document is accepted as a compatibility input for the original V1 - // single-output packet. Canonical output always uses Documents so one - // Explorer can retain all of its output-backed tabs. - Document ExplorerBuilderDocumentV1 `json:"document"` - Documents []ExplorerBuilderDocumentV1 `json:"documents,omitempty"` - Tabs []ExplorerTabV1 `json:"tabs,omitempty"` - IntentDigest string `json:"intentDigest,omitempty"` -} - -// MarshalJSON emits only the canonical plural Builder shape. Document remains -// a decode-only compatibility field so legacy packets can be migrated without -// leaking the singular form back into current Builder responses. -func (b ExplorerAuthoringBundleV1) MarshalJSON() ([]byte, error) { - documents := b.AuthoringDocuments() - if documents == nil { - documents = []ExplorerBuilderDocumentV1{} - } - tabs := b.Tabs - if tabs == nil { - tabs = []ExplorerTabV1{} - } - return json.Marshal(struct { - APIVersion string `json:"apiVersion"` - Kind string `json:"kind"` - Project string `json:"project"` - ExplorerID string `json:"explorerId"` - Title string `json:"title,omitempty"` - Documents []ExplorerBuilderDocumentV1 `json:"documents"` - Tabs []ExplorerTabV1 `json:"tabs"` - IntentDigest string `json:"intentDigest,omitempty"` - }{b.APIVersion, b.Kind, b.Project, b.ExplorerID, b.Title, documents, tabs, b.IntentDigest}) -} - -// ExplorerBuilderDocumentV1 contains authoring intent only. In particular, -// it has no recipe expression, select, alias, generated public column, or -// physical/storage identity. -type ExplorerBuilderDocumentV1 struct { - Kind string `json:"kind"` - Output ExplorerOutputIdentityV1 `json:"output"` - BaseNodeID string `json:"baseNodeId"` - RowNodeID string `json:"rowNodeId"` - RouteEdgeIDs []string `json:"routeEdgeIds,omitempty"` - RouteOccurrences []ExplorerRouteOccurrenceV1 `json:"routeOccurrences,omitempty"` - CandidateIDs []string `json:"candidateIds,omitempty"` - CandidateOccurrences []ExplorerCandidateOccurrenceV1 `json:"candidateOccurrences,omitempty"` - Presentation map[string]ExplorerPresentationBindingV1 `json:"presentation,omitempty"` -} - -type ExplorerOutputIdentityV1 struct { - ID string `json:"id"` - Title string `json:"title,omitempty"` -} - -// ExplorerTabV1 describes the visible tab/view layer without exposing recipe -// fields or generated columns. Output-backed tabs may be ordered independently -// of the recipe output order, and outputs not referenced by a tab remain valid -// materialization outputs without becoming visible tabs. -type ExplorerTabV1 struct { - ID string `json:"id"` - Title string `json:"title"` - OutputID string `json:"outputId"` - Order int `json:"order"` - Visible *bool `json:"visible,omitempty"` -} - -// Route occurrences identify a node occurrence in a route, rather than only -// a resource type. That distinction is required when a route repeats a -// resource type. -type ExplorerRouteOccurrenceV1 struct { - ID string `json:"id"` - Index int `json:"index"` - NodeID string `json:"nodeId"` - IncomingEdgeID string `json:"incomingEdgeId,omitempty"` -} - -// Candidate occurrences make candidate resolution unambiguous for repeated -// resource types and for candidates that are valid at more than one node. -type ExplorerCandidateOccurrenceV1 struct { - CandidateID string `json:"candidateId"` - OccurrenceID string `json:"occurrenceId"` - // ProjectionMode is populated by the V2 adapter. Legacy stored V1 - // documents omit it and use the compiler-proven candidate default. - ProjectionMode string `json:"projectionMode,omitempty"` -} - -// Presentation is keyed by the server-owned emission ID. No presentation -// object can name a recipe field or generated public column. -type ExplorerPresentationBindingV1 struct { - Label string `json:"label,omitempty"` - Visible *bool `json:"visible,omitempty"` - Order *int `json:"order,omitempty"` - Table *ExplorerTableBindingV1 `json:"table,omitempty"` - Filter *ExplorerFilterBindingV1 `json:"filter,omitempty"` - Chart *ExplorerChartBindingV1 `json:"chart,omitempty"` -} - -type ExplorerTableBindingV1 struct { - Pinned bool `json:"pinned,omitempty"` -} - -type ExplorerFilterBindingV1 struct { - Label string `json:"label,omitempty"` -} - -type ExplorerChartBindingV1 struct { - Type string `json:"type"` - Title string `json:"title,omitempty"` -} - -type AuthoringDiagnostic struct { - Severity string `json:"severity"` - Stage string `json:"stage"` - Code string `json:"code"` - JSONPath string `json:"jsonPath"` - Message string `json:"message"` - Details map[string]any `json:"details,omitempty"` - RequestID string `json:"requestId,omitempty"` -} - -type AuthoringError struct { - Status int - Diagnostic AuthoringDiagnostic - Cause error -} - -func (e *AuthoringError) Error() string { - if e == nil { - return "Explorer authoring error" - } - return e.Diagnostic.Code + ": " + e.Diagnostic.Message -} -func (e *AuthoringError) Unwrap() error { - if e == nil { - return nil - } - return e.Cause -} - -func malformedAuthoring(stage, path, code, message string, cause error) error { - return &AuthoringError{Status: 400, Cause: cause, Diagnostic: AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: code, JSONPath: path, Message: message}} -} -func semanticAuthoring(stage, path, code, message string, details map[string]any) error { - return &AuthoringError{Status: 422, Diagnostic: AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: code, JSONPath: path, Message: message, Details: details}} -} -func conflictAuthoring(stage, code, message string, details map[string]any) error { - return &AuthoringError{Status: 409, Diagnostic: AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: code, Message: message, Details: details}} -} - -// DecodeAuthoringBundleV1 rejects unknown fields, duplicate fields, trailing -// JSON, and all recipe-shaped fields. It is intentionally separate from the -// recipe decoder: accepting a recipe here would recreate the old browser -// compiler protocol. -func DecodeAuthoringBundleV1(raw []byte) (ExplorerAuthoringBundleV1, error) { - return decodeAuthoringBundleV1(raw, false) -} - -// DecodeAuthoringBundleV1ForMigration accepts the same strict wire shape as -// DecodeAuthoringBundleV1, but defers intentDigest verification until the -// server has resolved legacy intent against the current catalog. Stored -// bundles from before candidateOccurrences was canonical may have a digest -// for that legacy shape and must still be repairable by the authoring server. -func DecodeAuthoringBundleV1ForMigration(raw []byte) (ExplorerAuthoringBundleV1, error) { - return decodeAuthoringBundleV1(raw, true) -} - -func decodeAuthoringBundleV1(raw []byte, ignoreIntentDigest bool) (ExplorerAuthoringBundleV1, error) { - if err := rejectDuplicateJSONKeys(raw); err != nil { - return ExplorerAuthoringBundleV1{}, malformedAuthoring("decode", "$", "MALFORMED_AUTHORING_REQUEST", err.Error(), err) - } - var bundle ExplorerAuthoringBundleV1 - dec := json.NewDecoder(bytes.NewReader(raw)) - dec.DisallowUnknownFields() - if err := dec.Decode(&bundle); err != nil { - return ExplorerAuthoringBundleV1{}, malformedAuthoring("decode", "$", "MALFORMED_AUTHORING_REQUEST", err.Error(), err) - } - var trailing any - if err := dec.Decode(&trailing); err != io.EOF { - if err == nil { - err = fmt.Errorf("multiple JSON values") - } - return ExplorerAuthoringBundleV1{}, malformedAuthoring("decode", "$", "MALFORMED_AUTHORING_REQUEST", err.Error(), err) - } - if ignoreIntentDigest { - bundle.IntentDigest = "" - } - validationErr := bundle.Validate() - if validationErr != nil { - return ExplorerAuthoringBundleV1{}, validationErr - } - return bundle, nil -} - -// RejectDuplicateJSONKeys is shared by the versioned HTTP envelope decoder so -// every authoring entry point has the same strict wire behavior. -func RejectDuplicateJSONKeys(raw []byte) error { return rejectDuplicateJSONKeys(raw) } - -func (b ExplorerAuthoringBundleV1) Validate() error { - if b.APIVersion != ExplorerAuthoringV1APIVersion || b.Kind != ExplorerAuthoringV1Kind { - return malformedAuthoring("protocol", "$.apiVersion", "UNSUPPORTED_AUTHORING_PROTOCOL", "unsupported Explorer authoring protocol or kind", nil) - } - if strings.TrimSpace(b.Project) == "" || strings.TrimSpace(b.ExplorerID) == "" { - return malformedAuthoring("protocol", "$.project", "MISSING_AUTHORING_IDENTITY", "project and explorerId are required", nil) - } - documents := b.AuthoringDocuments() - // An empty document list is the canonical unpublished Explorer model. - // Preview/publish reject it as non-executable, while Builder reads and - // canonical local editing may carry it safely. - if len(b.Documents) > 0 && b.Document.Kind != "" { - return malformedAuthoring("protocol", "$.document", "DUPLICATE_AUTHORING_DOCUMENTS", "use documents or document, not both", nil) - } - seenOutputs := map[string]bool{} - for i, document := range documents { - if err := document.validateAt(fmt.Sprintf("$.documents[%d]", i)); err != nil { - return err - } - if seenOutputs[document.Output.ID] { - return semanticAuthoring("intent", fmt.Sprintf("$.documents[%d].output.id", i), "DUPLICATE_OUTPUT_ID", "output IDs must be unique within an Explorer", nil) - } - seenOutputs[document.Output.ID] = true - } - seenTabs := map[string]bool{} - seenOrders := map[int]bool{} - for i, tab := range b.Tabs { - path := fmt.Sprintf("$.tabs[%d]", i) - if !idPattern.MatchString(tab.ID) || strings.TrimSpace(tab.Title) == "" || !idPattern.MatchString(tab.OutputID) { - return malformedAuthoring("protocol", path, "INVALID_EXPLORER_TAB", "tab id, title, and outputId are required and must be stable identifiers", nil) - } - if seenTabs[tab.ID] { - return semanticAuthoring("intent", path+".id", "DUPLICATE_TAB_ID", "tab IDs must be unique", nil) - } - if seenOrders[tab.Order] { - return semanticAuthoring("intent", path+".order", "DUPLICATE_TAB_ORDER", "tab order values must be unique", nil) - } - if !seenOutputs[tab.OutputID] { - return semanticAuthoring("intent", path+".outputId", "TAB_OUTPUT_MISSING", "tab must reference an output document in the same bundle", nil) - } - seenTabs[tab.ID], seenOrders[tab.Order] = true, true - } - if b.IntentDigest != "" { - digest, err := b.DocumentDigest() - if err != nil { - return err - } - if b.IntentDigest != digest { - return conflictAuthoring("digest", "INTENT_DIGEST_MISMATCH", "intentDigest does not match the canonical document", map[string]any{"expected": digest, "received": b.IntentDigest}) - } - } - return nil -} - -func (d ExplorerBuilderDocumentV1) Validate() error { - return d.validateAt("$.document") -} - -func (d ExplorerBuilderDocumentV1) validateAt(path string) error { - if d.Kind != ExplorerBuilderV1Kind { - return malformedAuthoring("protocol", path+".kind", "UNSUPPORTED_DOCUMENT_VERSION", "unsupported builder document kind", nil) - } - if strings.TrimSpace(d.Output.ID) == "" { - return malformedAuthoring("protocol", path+".output.id", "MISSING_OUTPUT_ID", "output.id is required", nil) - } - if strings.TrimSpace(d.BaseNodeID) == "" || strings.TrimSpace(d.RowNodeID) == "" { - return malformedAuthoring("protocol", path+".baseNodeId", "MISSING_ROUTE_NODE", "baseNodeId and rowNodeId are required", nil) - } - for i, edge := range d.RouteEdgeIDs { - if strings.TrimSpace(edge) == "" { - return malformedAuthoring("protocol", fmt.Sprintf("%s.routeEdgeIds[%d]", path, i), "EMPTY_ROUTE_EDGE_ID", "route edge IDs must not be empty", nil) - } - } - occurrences := map[string]bool{} - for i, occurrence := range d.RouteOccurrences { - if strings.TrimSpace(occurrence.ID) == "" || strings.TrimSpace(occurrence.NodeID) == "" { - return malformedAuthoring("protocol", fmt.Sprintf("%s.routeOccurrences[%d]", path, i), "INVALID_ROUTE_OCCURRENCE", "route occurrence id and nodeId are required", nil) - } - if occurrences[occurrence.ID] { - return semanticAuthoring("intent", fmt.Sprintf("%s.routeOccurrences[%d].id", path, i), "DUPLICATE_ROUTE_OCCURRENCE", "route occurrence IDs must be unique", nil) - } - occurrences[occurrence.ID] = true - } - candidates := map[string]bool{} - for i, candidate := range d.CandidateIDs { - if strings.TrimSpace(candidate) == "" { - return malformedAuthoring("protocol", fmt.Sprintf("%s.candidateIds[%d]", path, i), "EMPTY_CANDIDATE_ID", "candidate IDs must not be empty", nil) - } - if candidates[candidate] { - return semanticAuthoring("intent", fmt.Sprintf("%s.candidateIds[%d]", path, i), "DUPLICATE_CANDIDATE_ID", "candidate IDs must be unique", nil) - } - candidates[candidate] = true - } - for i, candidate := range d.CandidateOccurrences { - if !candidates[candidate.CandidateID] { - return semanticAuthoring("intent", fmt.Sprintf("%s.candidateOccurrences[%d].candidateId", path, i), "CANDIDATE_REFERENCE_MISSING", "candidate occurrence must reference candidateIds", nil) - } - if !occurrences[candidate.OccurrenceID] && candidate.OccurrenceID != "base" { - return semanticAuthoring("intent", fmt.Sprintf("%s.candidateOccurrences[%d].occurrenceId", path, i), "STALE_ROUTE_OCCURRENCE", "candidate occurrence references an unknown route occurrence", nil) - } - } - for emissionID := range d.Presentation { - if strings.TrimSpace(emissionID) == "" { - return malformedAuthoring("protocol", path+".presentation", "EMPTY_EMISSION_ID", "presentation keys must be emission IDs", nil) - } - } - return nil -} - -func (b ExplorerAuthoringBundleV1) CanonicalDocumentJSON() ([]byte, error) { - validationCopy := b - validationCopy.IntentDigest = "" - if err := validationCopy.Validate(); err != nil { - return nil, err - } - return json.Marshal(struct { - Documents []ExplorerBuilderDocumentV1 `json:"documents"` - Tabs []ExplorerTabV1 `json:"tabs,omitempty"` - }{Documents: b.AuthoringDocuments(), Tabs: b.Tabs}) -} -func (b ExplorerAuthoringBundleV1) DocumentDigest() (string, error) { - raw, err := b.CanonicalDocumentJSON() - if err != nil { - return "", err - } - sum := sha256.Sum256(raw) - return "sha256:" + hex.EncodeToString(sum[:]), nil -} -func (b ExplorerAuthoringBundleV1) CanonicalJSON() ([]byte, error) { - if err := b.Validate(); err != nil { - return nil, err - } - digest, err := b.DocumentDigest() - if err != nil { - return nil, err - } - return json.Marshal(struct { - APIVersion string `json:"apiVersion"` - Kind string `json:"kind"` - Project string `json:"project"` - ExplorerID string `json:"explorerId"` - Title string `json:"title,omitempty"` - Documents []ExplorerBuilderDocumentV1 `json:"documents"` - Tabs []ExplorerTabV1 `json:"tabs,omitempty"` - IntentDigest string `json:"intentDigest"` - }{b.APIVersion, b.Kind, b.Project, b.ExplorerID, b.Title, b.AuthoringDocuments(), b.Tabs, digest}) -} - -// AuthoringDocuments returns the normalized multi-output view of the bundle. -// The singular Document field is retained only so older V1 callers can be -// read and recompiled while all canonical artifacts use Documents. -func (b ExplorerAuthoringBundleV1) AuthoringDocuments() []ExplorerBuilderDocumentV1 { - if len(b.Documents) > 0 { - return append([]ExplorerBuilderDocumentV1(nil), b.Documents...) - } - if b.Document.Kind != "" || b.Document.Output.ID != "" || b.Document.BaseNodeID != "" { - return []ExplorerBuilderDocumentV1{b.Document} - } - return nil -} - -// AuthoringTabs returns explicit tab order when supplied. A single legacy V1 -// document keeps the historical default view; a multi-output bundle defaults -// to one tab per output when the caller omits tabs. -func (b ExplorerAuthoringBundleV1) AuthoringTabs() []ExplorerTabV1 { - if len(b.Tabs) > 0 { - return append([]ExplorerTabV1(nil), b.Tabs...) - } - documents := b.AuthoringDocuments() - tabs := make([]ExplorerTabV1, 0, len(documents)) - for i, document := range documents { - id := document.Output.ID - if len(documents) == 1 { - id = "default" - } - title := document.Output.Title - if strings.TrimSpace(title) == "" { - title = document.Output.ID - } - tabs = append(tabs, ExplorerTabV1{ID: id, Title: title, OutputID: document.Output.ID, Order: i}) - } - return tabs -} - -func rejectDuplicateJSONKeys(raw []byte) error { - dec := json.NewDecoder(bytes.NewReader(raw)) - var walk func(string) error - walk = func(path string) error { - tok, err := dec.Token() - if err != nil { - return err - } - if delim, ok := tok.(json.Delim); ok { - switch delim { - case '{': - seen := map[string]bool{} - for dec.More() { - keyToken, err := dec.Token() - if err != nil { - return err - } - key := keyToken.(string) - if seen[key] { - return fmt.Errorf("duplicate JSON object key %q at %s", key, path) - } - seen[key] = true - if err := walk(path + "." + key); err != nil { - return err - } - } - _, err = dec.Token() - return err - case '[': - i := 0 - for dec.More() { - if err := walk(fmt.Sprintf("%s[%d]", path, i)); err != nil { - return err - } - i++ - } - _, err = dec.Token() - return err - } - } - return nil - } - if err := walk("$"); err != nil { - return err - } - return nil -} - -// PresentationEmissionIDs returns sorted keys for deterministic diagnostics -// and test assertions without changing the wire representation. -func (d ExplorerBuilderDocumentV1) PresentationEmissionIDs() []string { - ids := make([]string, 0, len(d.Presentation)) - for id := range d.Presentation { - ids = append(ids, id) - } - sort.Strings(ids) - return ids -} diff --git a/internal/explorer/authoring_v1_test.go b/internal/explorer/authoring_v1_test.go deleted file mode 100644 index 0ddf4201..00000000 --- a/internal/explorer/authoring_v1_test.go +++ /dev/null @@ -1,214 +0,0 @@ -package explorer - -import ( - "context" - "encoding/json" - "strings" - "sync" - "testing" -) - -func TestAuthoringBundleV1StrictDecodeAndCanonicalDigest(t *testing.T) { - raw := []byte(`{"apiVersion":"loom.calypr.org/explorer-authoring/v1","kind":"ExplorerAuthoringBundle","project":"p","explorerId":"e","document":{"kind":"ExplorerBuilderDocument","output":{"id":"out"},"baseNodeId":"n_base","rowNodeId":"n_base","candidateIds":["s_id"],"presentation":{}}}`) - bundle, err := DecodeAuthoringBundleV1(raw) - if err != nil { - t.Fatal(err) - } - digest, err := bundle.DocumentDigest() - if err != nil { - t.Fatal(err) - } - canonical, err := bundle.CanonicalJSON() - if err != nil { - t.Fatal(err) - } - if !strings.Contains(string(canonical), digest) { - t.Fatalf("canonical bundle does not carry digest: %s", canonical) - } - if _, err := DecodeAuthoringBundleV1([]byte(strings.Replace(string(raw), `"candidateIds":["s_id"]`, `"candidateIds":["s_id"],"recipe":{"direction":"OUTBOUND"}`, 1))); err == nil { - t.Fatal("accepted recipe-shaped authoring field") - } - if _, err := DecodeAuthoringBundleV1([]byte(strings.Replace(string(raw), `"candidateIds":["s_id"]`, `"candidateIds":["s_id"],"children":[]`, 1))); err == nil { - t.Fatal("accepted children field") - } - if _, err := DecodeAuthoringBundleV1([]byte(strings.Replace(string(raw), `"candidateIds":["s_id"]`, `"candidateIds":["s_id"],"candidateIds":["s_id"]`, 1))); err == nil { - t.Fatal("accepted duplicate field") - } -} - -func TestAuthoringBundleV1RejectsDigestMismatch(t *testing.T) { - raw := []byte(`{"apiVersion":"loom.calypr.org/explorer-authoring/v1","kind":"ExplorerAuthoringBundle","project":"p","explorerId":"e","intentDigest":"sha256:bad","document":{"kind":"ExplorerBuilderDocument","output":{"id":"out"},"baseNodeId":"n_base","rowNodeId":"n_base"}}`) - if _, err := DecodeAuthoringBundleV1(raw); err == nil || !strings.Contains(err.Error(), "INTENT_DIGEST_MISMATCH") { - t.Fatalf("error=%v", err) - } -} - -func TestReceiptIDIsContentAddressed(t *testing.T) { - r := CompilationReceipt{Project: "p", ExplorerID: "e", IntentDigest: "sha256:a", SnapshotToken: "sha256:s", SourceGeneration: "g"} - first, err := ReceiptID(r) - if err != nil { - t.Fatal(err) - } - second, err := ReceiptID(r) - if err != nil { - t.Fatal(err) - } - if first == "" || first != second || !strings.HasPrefix(first, "receipt_") { - t.Fatalf("receipt IDs=%q,%q", first, second) - } -} - -func TestReceiptIDNormalizesJSONRepresentation(t *testing.T) { - base := CompilationReceipt{ - Project: "p", - ExplorerID: "e", - IntentDigest: "sha256:a", - SnapshotToken: "sha256:s", - SourceGeneration: "g", - CompiledConfig: json.RawMessage(`{"views":[{"columns":{"z":2,"a":1}}],"apiVersion":"loom.calypr.org/explorer-config/v2"}`), - } - reordered := base - reordered.CompiledConfig = json.RawMessage(`{"apiVersion":"loom.calypr.org/explorer-config/v2","views":[{"columns":{"a":1,"z":2}}]}`) - - first, err := ReceiptID(base) - if err != nil { - t.Fatal(err) - } - second, err := ReceiptID(reordered) - if err != nil { - t.Fatal(err) - } - if first != second { - t.Fatalf("JSON representation changed receipt ID: %q != %q", first, second) - } -} - -func TestReceiptIDSurvivesDocumentRoundTrip(t *testing.T) { - receipt := CompilationReceipt{ - Project: "p", - ExplorerID: "e", - IntentDigest: "sha256:a", - SnapshotToken: "sha256:s", - SourceGeneration: "g", - CompiledConfig: json.RawMessage(`{"views":[{"columns":{"z":2,"a":1}}],"apiVersion":"loom.calypr.org/explorer-config/v2"}`), - } - original, err := ReceiptID(receipt) - if err != nil { - t.Fatal(err) - } - - // This mirrors the Arango store's document conversion: marshal the typed - // receipt into a generic JSON document, then decode it again. - raw, err := json.Marshal(receipt) - if err != nil { - t.Fatal(err) - } - var document map[string]any - if err := json.Unmarshal(raw, &document); err != nil { - t.Fatal(err) - } - raw, err = json.Marshal(document) - if err != nil { - t.Fatal(err) - } - var roundTripped CompilationReceipt - if err := json.Unmarshal(raw, &roundTripped); err != nil { - t.Fatal(err) - } - - loaded, err := ReceiptID(roundTripped) - if err != nil { - t.Fatal(err) - } - if original != loaded { - t.Fatalf("Arango-like round trip changed receipt ID: %q != %q", original, loaded) - } -} - -func TestReceiptIDChangesWhenContentChanges(t *testing.T) { - receipt := CompilationReceipt{ - Project: "p", - ExplorerID: "e", - IntentDigest: "sha256:a", - SnapshotToken: "sha256:s", - SourceGeneration: "g", - CompiledConfig: json.RawMessage(`{"apiVersion":"loom.calypr.org/explorer-config/v2","views":[]}`), - } - original, err := ReceiptID(receipt) - if err != nil { - t.Fatal(err) - } - receipt.CompiledConfig = json.RawMessage(`{"apiVersion":"loom.calypr.org/explorer-config/v2","views":[{"id":"new"}]}`) - changed, err := ReceiptID(receipt) - if err != nil { - t.Fatal(err) - } - if original == changed { - t.Fatal("receipt ID did not change after content changed") - } -} - -func TestMemoryStorePurgesOrphanAuthoringReceipts(t *testing.T) { - store := NewMemoryStore() - service, err := NewService(store) - if err != nil { - t.Fatal(err) - } - ctx := context.Background() - for _, id := range []string{"receipt_kept", "receipt_orphan"} { - if _, err := service.StoreCompilationReceipt(ctx, CompilationReceipt{ID: id, Project: "p", ExplorerID: "e"}); err != nil { - t.Fatal(err) - } - } - if _, err := store.InsertRevision(ctx, Revision{ID: "r1", Project: "p", ExplorerID: "e", CompilationReceiptID: "receipt_kept"}); err != nil { - t.Fatal(err) - } - if err := service.PurgeDraftAuthoring(ctx); err != nil { - t.Fatal(err) - } - if _, err := service.CompilationReceipt(ctx, "receipt_kept"); err != nil { - t.Fatalf("referenced receipt removed: %v", err) - } - if _, err := service.CompilationReceipt(ctx, "receipt_orphan"); err != ErrNotFound { - t.Fatalf("orphan receipt error=%v", err) - } -} - -func TestMemoryStoreAuthoringActivationIsLastWriterWins(t *testing.T) { - store := NewMemoryStore() - ctx := context.Background() - if _, err := store.CreateInteractive(ctx, Explorer{Project: "p", ExplorerID: "e", ManagementMode: ManagementInteractive}); err != nil { - t.Fatal(err) - } - for _, revision := range []Revision{ - {ID: "r1", Project: "p", ExplorerID: "e", Status: RevisionReady}, - {ID: "r2", Project: "p", ExplorerID: "e", Status: RevisionReady}, - } { - if _, err := store.InsertRevision(ctx, revision); err != nil { - t.Fatal(err) - } - } - start := make(chan struct{}) - errs := make(chan error, 2) - var wait sync.WaitGroup - for _, revisionID := range []string{"r1", "r2"} { - wait.Add(1) - go func(id string) { - defer wait.Done() - <-start - errs <- store.ActivateInteractive(ctx, "p", "e", id) - }(revisionID) - } - close(start) - wait.Wait() - close(errs) - for err := range errs { - if err != nil { - t.Fatal(err) - } - } - owner, err := store.Get(ctx, "p", "e") - if err != nil || (owner.ActiveRevisionID != "r1" && owner.ActiveRevisionID != "r2") { - t.Fatalf("last-writer-wins activation owner=%#v err=%v", owner, err) - } -} diff --git a/internal/explorer/authoringv2/migration.go b/internal/explorer/authoringv2/migration.go deleted file mode 100644 index ca6d59e0..00000000 --- a/internal/explorer/authoringv2/migration.go +++ /dev/null @@ -1,80 +0,0 @@ -package authoringv2 - -import ( - "fmt" - - "github.com/calypr/loom/internal/explorer" -) - -// MigrateV1Document is the only V1-to-V2 direction. It imports authoring -// intent, never a compiled recipe or a server-resolved binding. V1's row node -// is intentionally ignored: V2 derives its tail from routeSteps. -func MigrateV1Document(input explorer.ExplorerBuilderDocumentV1) (Document, error) { - if err := input.Validate(); err != nil { - return Document{}, fmt.Errorf("migrate V1 document: %w", err) - } - title := input.Output.Title - if title == "" { - title = input.Output.ID - } - out := Document{ - APIVersion: APIVersion, - Kind: APIVersionKind(), - Output: Output{ID: input.Output.ID, Title: title}, - RootNodeID: input.BaseNodeID, - RouteSteps: make([]RouteStep, 0, len(input.RouteEdgeIDs)), - Selections: make([]Selection, 0, len(input.CandidateIDs)), - Presentation: make(map[string]Presentation, len(input.Presentation)), - } - for index, edgeID := range input.RouteEdgeIDs { - occurrenceIndex := index - if len(input.RouteOccurrences) == len(input.RouteEdgeIDs)+1 { - occurrenceIndex++ - } - occurrenceID := "" - if occurrenceIndex < len(input.RouteOccurrences) { - occurrenceID = input.RouteOccurrences[occurrenceIndex].ID - } - out.RouteSteps = append(out.RouteSteps, RouteStep{EdgeID: edgeID, OccurrenceID: occurrenceID}) - } - if len(input.CandidateOccurrences) > 0 { - for _, occurrence := range input.CandidateOccurrences { - mode := occurrence.ProjectionMode - if mode == "" { - mode = "SCALAR" - } - out.Selections = append(out.Selections, Selection{CandidateID: occurrence.CandidateID, OccurrenceID: occurrence.OccurrenceID, ProjectionMode: mode}) - } - } else { - for _, candidateID := range input.CandidateIDs { - out.Selections = append(out.Selections, Selection{CandidateID: candidateID, OccurrenceID: RootOccurrenceID, ProjectionMode: "SCALAR"}) - } - } - for key, binding := range input.Presentation { - out.Presentation[key] = Presentation{Label: binding.Label, Visible: binding.Visible, Order: binding.Order} - } - if err := out.Validate(); err != nil { - return Document{}, fmt.Errorf("migrated V1 document is not valid V2 intent: %w", err) - } - return out, nil -} - -// MigrateV1Bundle imports every V1 output document in order. Catalog -// resolution is deliberately a later operation, so migration cannot invent -// stale IDs or accidentally create a compilation cycle. -func MigrateV1Bundle(input explorer.ExplorerAuthoringBundleV1) ([]Document, error) { - documents := input.AuthoringDocuments() - out := make([]Document, 0, len(documents)) - for i, document := range documents { - migrated, err := MigrateV1Document(document) - if err != nil { - return nil, fmt.Errorf("migrate V1 document %d: %w", i, err) - } - out = append(out, migrated) - } - return out, nil -} - -// APIVersionKind exists to keep migration call sites readable while making -// the protocol kind a single constant in the wire package. -func APIVersionKind() string { return Kind } diff --git a/internal/explorer/authoringv2/migration_test.go b/internal/explorer/authoringv2/migration_test.go deleted file mode 100644 index fae0d494..00000000 --- a/internal/explorer/authoringv2/migration_test.go +++ /dev/null @@ -1,45 +0,0 @@ -package authoringv2 - -import ( - "strings" - "testing" - - "github.com/calypr/loom/internal/explorer" -) - -func TestMigrateV1DropsRowAndExecutionFields(t *testing.T) { - visible := true - order := 2 - input := explorer.ExplorerBuilderDocumentV1{ - Kind: explorer.ExplorerBuilderV1Kind, - Output: explorer.ExplorerOutputIdentityV1{ID: "out", Title: "Output"}, - BaseNodeID: "patient", RowNodeID: "legacy-row", - RouteEdgeIDs: []string{"patient-encounter"}, - RouteOccurrences: []explorer.ExplorerRouteOccurrenceV1{{ID: "encounter-occurrence", NodeID: "encounter", IncomingEdgeID: "patient-encounter"}}, - CandidateIDs: []string{"encounter-id"}, - CandidateOccurrences: []explorer.ExplorerCandidateOccurrenceV1{{CandidateID: "encounter-id", OccurrenceID: "encounter-occurrence"}}, - Presentation: map[string]explorer.ExplorerPresentationBindingV1{"encounter-id": {Label: "Encounter", Visible: &visible, Order: &order}}, - } - migrated, err := MigrateV1Document(input) - if err != nil { - t.Fatal(err) - } - if migrated.RootNodeID != "patient" || len(migrated.RouteSteps) != 1 || migrated.RouteSteps[0].OccurrenceID != "encounter-occurrence" { - t.Fatalf("unexpected migrated route: %#v", migrated) - } - if migrated.Selections[0].ProjectionMode != "SCALAR" || migrated.Selections[0].CandidateID != "encounter-id" { - t.Fatalf("unexpected migrated selection: %#v", migrated.Selections) - } - if migrated.Output.ID != "out" || migrated.Output.Title != "Output" { - t.Fatalf("output was not migrated: %#v", migrated.Output) - } - raw, err := migrated.CanonicalJSON() - if err != nil { - t.Fatal(err) - } - for _, forbidden := range []string{"rowNodeId", "legacy-row", "selector", "aql", "physicalCollection"} { - if strings.Contains(string(raw), forbidden) { - t.Fatalf("forbidden V1/backend field leaked: %q", forbidden) - } - } -} diff --git a/internal/explorer/authoringv2/semantic_types.go b/internal/explorer/authoringv2/semantic_types.go new file mode 100644 index 00000000..dbd3823f --- /dev/null +++ b/internal/explorer/authoringv2/semantic_types.go @@ -0,0 +1,252 @@ +package authoringv2 + +import ( + "fmt" + "regexp" + "sort" + "strings" +) + +const ( + LifecycleNew = "NEW" + LifecycleReady = "READY" +) + +type ExplorerMetadata struct { + Title string `json:"title"` + Description string `json:"description,omitempty"` +} + +// RouteNode is one semantic occurrence in a document route tree. Relationship +// is empty only for the root; every child names the relationship from its +// parent. Resource identities are stable FHIR resource types, not catalog IDs. +type RouteNode struct { + OccurrenceID string `json:"occurrenceId"` + ResourceType string `json:"resourceType"` + Relationship string `json:"relationship,omitempty"` + Children []RouteNode `json:"children,omitempty"` +} + +type ColumnSource struct { + Kind string `json:"kind"` + FieldPath string `json:"fieldPath,omitempty"` + Match string `json:"match,omitempty"` + ProjectionMode string `json:"projectionMode,omitempty"` +} + +const ( + SourceField = "field" + SourceIdentifierBySystem = "identifierBySystem" + SourceExtensionByURL = "extensionByUrl" + SourceCodingBySystem = "codingBySystem" + SourceObservationComponentByCode = "observationComponentByCode" + SourceProjectID = "projectId" +) + +type Column struct { + Column string `json:"column"` + Label string `json:"label"` + LogicalType string `json:"logicalType,omitempty"` + OccurrenceID string `json:"occurrenceId"` + Source ColumnSource `json:"source"` + Table *TablePresentation `json:"table,omitempty"` + Filter *FilterPresentation `json:"filter,omitempty"` + Chart *ChartPresentation `json:"chart,omitempty"` +} + +type FixedFilter struct { + Column string `json:"column"` + Values []string `json:"values"` +} + +type ActionColumn struct { + Column string `json:"column"` + ExportHeader string `json:"exportHeader,omitempty"` +} + +type Action struct { + Type string `json:"type"` + Title string `json:"title"` + FileName string `json:"fileName,omitempty"` + Columns []ActionColumn `json:"columns,omitempty"` +} + +type SharedFilterBinding struct { + OutputID string `json:"outputId"` + Column string `json:"column"` +} + +type FileActions struct { + Extensions map[string][]string `json:"extensions"` + Actions map[string]string `json:"actions"` +} + +var physicalColumnPattern = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*$`) + +func (d Document) semantic() bool { + return strings.TrimSpace(d.RootResourceType) != "" || strings.TrimSpace(d.Route.ResourceType) != "" || len(d.Columns) != 0 +} + +func (d Document) UsesSemanticColumns() bool { return d.semantic() } + +func (d Document) semanticOccurrences() (map[string]RouteNode, error) { + if !d.semantic() { + return nil, nil + } + if strings.TrimSpace(d.RootResourceType) == "" { + return nil, fmt.Errorf("rootResourceType is required") + } + if d.Route.OccurrenceID != RootOccurrenceID || d.Route.ResourceType != d.RootResourceType || strings.TrimSpace(d.Route.Relationship) != "" { + return nil, fmt.Errorf("route root must be occurrence %q with resourceType %q and no relationship", RootOccurrenceID, d.RootResourceType) + } + occurrences := map[string]RouteNode{} + var walk func(RouteNode, string) error + walk = func(node RouteNode, path string) error { + if emptyID(node.OccurrenceID) || strings.TrimSpace(node.ResourceType) == "" { + return fmt.Errorf("%s occurrenceId and resourceType are required", path) + } + if _, duplicate := occurrences[node.OccurrenceID]; duplicate { + return fmt.Errorf("duplicate route occurrence id %q", node.OccurrenceID) + } + occurrences[node.OccurrenceID] = node + for i, child := range node.Children { + if strings.TrimSpace(child.Relationship) == "" { + return fmt.Errorf("%s.children[%d].relationship is required", path, i) + } + if err := walk(child, fmt.Sprintf("%s.children[%d]", path, i)); err != nil { + return err + } + } + return nil + } + if err := walk(d.Route, "route"); err != nil { + return nil, err + } + return occurrences, nil +} + +func (s ColumnSource) validate(path string) error { + mode := strings.ToUpper(strings.TrimSpace(s.ProjectionMode)) + if mode == "" { + mode = "FIRST" + } + if mode != "VALUE" && mode != "FIRST" && mode != "ALL" && mode != "DISTINCT" { + return fmt.Errorf("%s.projectionMode %q is unsupported", path, s.ProjectionMode) + } + switch s.Kind { + case SourceField: + if strings.TrimSpace(s.FieldPath) == "" || strings.TrimSpace(s.Match) != "" { + return fmt.Errorf("%s field source requires fieldPath and forbids match", path) + } + case SourceIdentifierBySystem, SourceExtensionByURL, SourceCodingBySystem, SourceObservationComponentByCode: + if strings.TrimSpace(s.Match) == "" { + return fmt.Errorf("%s %s source requires match", path, s.Kind) + } + case SourceProjectID: + if strings.TrimSpace(s.FieldPath) != "" || strings.TrimSpace(s.Match) != "" { + return fmt.Errorf("%s projectId source has no parameters", path) + } + default: + return fmt.Errorf("%s source kind %q is unsupported", path, s.Kind) + } + return nil +} + +func (d Document) validateSemantic() error { + occurrences, err := d.semanticOccurrences() + if err != nil { + return err + } + seen := map[string]bool{} + for i, column := range d.Columns { + path := fmt.Sprintf("columns[%d]", i) + if !physicalColumnPattern.MatchString(column.Column) { + return fmt.Errorf("%s.column %q is not a valid physical column", path, column.Column) + } + if seen[column.Column] { + return fmt.Errorf("duplicate column %q", column.Column) + } + seen[column.Column] = true + if strings.TrimSpace(column.Label) == "" { + return fmt.Errorf("%s.label is required", path) + } + if _, ok := occurrences[column.OccurrenceID]; !ok { + return fmt.Errorf("%s references unknown occurrence %q", path, column.OccurrenceID) + } + if err := column.Source.validate(path + ".source"); err != nil { + return err + } + if column.Table != nil && column.Table.Order != nil && *column.Table.Order < 0 { + return fmt.Errorf("%s.table.order must not be negative", path) + } + if column.Table != nil && column.Table.CellRenderer != "" && column.Table.CellRenderer != "fileActions" { + return fmt.Errorf("%s.table.cellRenderer is unsupported", path) + } + if column.Filter != nil && column.Filter.Order != nil && *column.Filter.Order < 0 { + return fmt.Errorf("%s.filter.order must not be negative", path) + } + if column.Chart != nil { + if strings.TrimSpace(column.Chart.Type) == "" { + return fmt.Errorf("%s.chart.type is required", path) + } + if column.Chart.Order != nil && *column.Chart.Order < 0 { + return fmt.Errorf("%s.chart.order must not be negative", path) + } + } + } + for i, fixed := range d.FixedFilters { + if !seen[fixed.Column] || len(fixed.Values) == 0 { + return fmt.Errorf("fixedFilters[%d] must reference a declared column and contain values", i) + } + } + for i, action := range d.Actions { + if strings.TrimSpace(action.Type) == "" || strings.TrimSpace(action.Title) == "" { + return fmt.Errorf("actions[%d].type and title are required", i) + } + for j, binding := range action.Columns { + if !seen[binding.Column] { + return fmt.Errorf("actions[%d].columns[%d] references unknown column %q", i, j, binding.Column) + } + } + } + return nil +} + +func (w Workspace) validateSemanticBindings() error { + columns := map[string]map[string]bool{} + for _, document := range w.Documents { + columns[document.Output.ID] = map[string]bool{} + for _, column := range document.Columns { + columns[document.Output.ID][column.Column] = true + } + } + for name, bindings := range w.SharedFilters { + if strings.TrimSpace(name) == "" || len(bindings) == 0 { + return fmt.Errorf("sharedFilters names and bindings must be non-empty") + } + for i, binding := range bindings { + if !columns[binding.OutputID][binding.Column] { + return fmt.Errorf("sharedFilters[%q][%d] references unknown output column", name, i) + } + } + } + if w.FileActions != nil { + for extension, actions := range w.FileActions.Extensions { + if strings.TrimSpace(extension) == "" || len(actions) == 0 { + return fmt.Errorf("fileActions.extensions entries must be non-empty") + } + for _, action := range actions { + if _, ok := w.FileActions.Actions[action]; !ok { + return fmt.Errorf("fileActions extension %q references unknown action %q", extension, action) + } + } + } + } + return nil +} + +func sortedRouteChildren(children []RouteNode) []RouteNode { + result := append([]RouteNode(nil), children...) + sort.SliceStable(result, func(i, j int) bool { return result[i].OccurrenceID < result[j].OccurrenceID }) + return result +} diff --git a/internal/explorer/authoringv2/types.go b/internal/explorer/authoringv2/types.go index 757ea24b..aa2363fa 100644 --- a/internal/explorer/authoringv2/types.go +++ b/internal/explorer/authoringv2/types.go @@ -50,18 +50,27 @@ type CatalogCandidateV2 = CatalogCandidate // path from RootNodeID. Its root occurrence is always "base" and its tail is // computed from the path; neither is a second authored node identity. type Document struct { - APIVersion string `json:"-"` - Kind string `json:"kind"` - Output Output `json:"output"` - RootNodeID string `json:"rootNodeId"` - RouteSteps []RouteStep `json:"routeSteps"` - Selections []Selection `json:"selections"` - Presentation map[string]Presentation `json:"presentation"` + APIVersion string `json:"-"` + Kind string `json:"kind"` + Output Output `json:"output"` + RootResourceType string `json:"rootResourceType,omitempty"` + Route RouteNode `json:"route,omitempty"` + Columns []Column `json:"columns,omitempty"` + FixedFilters []FixedFilter `json:"fixedFilters,omitempty"` + Actions []Action `json:"actions,omitempty"` + + // The opaque, linear authoring model is retained only for source-compatible + // internal tests while the hard-cut wire decoder rejects those fields. + RootNodeID string `json:"-"` + RouteSteps []RouteStep `json:"-"` + Selections []Selection `json:"-"` + Presentation map[string]Presentation `json:"-"` } type Output struct { - ID string `json:"id"` - Title string `json:"title"` + ID string `json:"id"` + Title string `json:"title"` + RowLabel string `json:"rowLabel,omitempty"` } type RouteStep struct { @@ -78,10 +87,13 @@ type Selection struct { // Workspace is the atomic authoring unit. Documents are independent table // intents; tabs provide their ordered, visible runtime presentation. type Workspace struct { - APIVersion string `json:"apiVersion"` - Kind string `json:"kind"` - Documents []Document `json:"documents"` - Tabs []Tab `json:"tabs"` + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Explorer ExplorerMetadata `json:"explorer"` + Documents []Document `json:"documents"` + Tabs []Tab `json:"tabs"` + SharedFilters map[string][]SharedFilterBinding `json:"sharedFilters,omitempty"` + FileActions *FileActions `json:"fileActions,omitempty"` } type Tab struct { @@ -104,14 +116,19 @@ type Presentation struct { } type TablePresentation struct { - Pinned bool `json:"pinned"` + Visible *bool `json:"visible,omitempty"` + Order *int `json:"order,omitempty"` + Pinned bool `json:"pinned,omitempty"` + CellRenderer string `json:"cellRenderer,omitempty"` } type FilterPresentation struct { Label string `json:"label,omitempty"` + Order *int `json:"order,omitempty"` } type ChartPresentation struct { Type string `json:"type"` Title string `json:"title,omitempty"` + Order *int `json:"order,omitempty"` } func PresentationKey(candidateID, occurrenceID, projectionMode string) string { @@ -165,6 +182,7 @@ type CatalogEdge struct { type CatalogCandidate struct { ID string `json:"candidateId"` NodeID string `json:"nodeId"` + FieldPath string `json:"fieldPath"` Label string `json:"label"` LogicalType string `json:"logicalType"` Repeated bool `json:"repeated"` @@ -194,9 +212,10 @@ type RoutePolicy struct { // BuilderState joins one workspace to the one catalog snapshot that proves it. type BuilderState struct { - APIVersion string `json:"apiVersion"` - Kind string `json:"kind"` - Workspace *Workspace `json:"workspace,omitempty"` + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` + LifecycleState string `json:"lifecycleState"` + Workspace *Workspace `json:"workspace"` // Document is retained only as a source-compatible internal migration aid. Document *Document `json:"-"` Catalog CatalogSnapshot `json:"catalog"` @@ -263,6 +282,9 @@ func (d Document) Validate() error { if emptyID(d.Output.ID) || strings.TrimSpace(d.Output.Title) == "" { return fmt.Errorf("output id and title are required") } + if d.semantic() { + return d.validateSemantic() + } if emptyID(d.RootNodeID) { return fmt.Errorf("rootNodeId is required") } @@ -322,6 +344,13 @@ func (w Workspace) Validate() error { if w.APIVersion != APIVersion || w.Kind != WorkspaceKind { return fmt.Errorf("unsupported V2 workspace protocol or kind") } + semanticWorkspace := false + for _, document := range w.Documents { + semanticWorkspace = semanticWorkspace || document.semantic() + } + if semanticWorkspace && strings.TrimSpace(w.Explorer.Title) == "" { + return fmt.Errorf("explorer.title is required") + } outputs, tabs, tabOutputs, orders := map[string]bool{}, map[string]bool{}, map[string]bool{}, map[int]bool{} for i, d := range w.Documents { if err := d.Validate(); err != nil { @@ -360,6 +389,9 @@ func (w Workspace) Validate() error { return fmt.Errorf("INVALID_TAB_ORDER: orders must be contiguous from zero") } } + if err := w.validateSemanticBindings(); err != nil { + return err + } return nil } @@ -376,6 +408,18 @@ func (w Workspace) ValidateForPublication() error { if !visibleOutputs[document.Output.ID] { continue } + if document.semantic() { + visible := 0 + for _, column := range document.Columns { + if column.Table != nil && (column.Table.Visible == nil || *column.Table.Visible) { + visible++ + } + } + if visible == 0 { + return fmt.Errorf("NO_VISIBLE_COLUMNS: documents[%d]", i) + } + continue + } hidden := 0 for _, presentation := range document.Presentation { if presentation.Visible != nil && !*presentation.Visible { @@ -480,6 +524,22 @@ func (s BuilderState) Validate() error { if err := s.Catalog.Validate(); err != nil { return err } + if s.LifecycleState == "" { + if s.Workspace == nil { + s.LifecycleState = LifecycleNew + } else { + s.LifecycleState = LifecycleReady + } + } + if s.LifecycleState != LifecycleNew && s.LifecycleState != LifecycleReady { + return fmt.Errorf("unsupported lifecycleState %q", s.LifecycleState) + } + if s.LifecycleState == LifecycleNew && s.Workspace != nil { + return fmt.Errorf("NEW Builder state must have workspace null") + } + if s.LifecycleState == LifecycleReady && s.Workspace == nil { + return fmt.Errorf("READY Builder state requires workspace") + } workspace := s.Workspace if workspace == nil && s.Document != nil { workspace = &Workspace{APIVersion: APIVersion, Kind: WorkspaceKind, Documents: []Document{*s.Document}, Tabs: []Tab{{ID: s.Document.Output.ID, Title: s.Document.Output.Title, OutputID: s.Document.Output.ID, Order: 0, Visible: true}}} @@ -492,6 +552,9 @@ func (s BuilderState) Validate() error { } for i := range workspace.Documents { document := workspace.Documents[i] + if document.semantic() { + continue + } one := s one.Workspace = nil one.Document = &document @@ -821,38 +884,6 @@ func DecodeWorkspace(raw []byte) (Workspace, error) { return out, nil } -func DecodeExplorerBuilderDocumentV2(raw []byte) (ExplorerBuilderDocumentV2, error) { - return DecodeDocument(raw) -} -func DecodeCatalog(raw []byte) (CatalogSnapshot, error) { - var out CatalogSnapshot - if err := strictDecode(raw, &out); err != nil { - return out, err - } - if err := out.Validate(); err != nil { - return out, err - } - return out, nil -} - -func DecodeExplorerBuilderCatalogV2(raw []byte) (ExplorerBuilderCatalogV2, error) { - return DecodeCatalog(raw) -} -func DecodeBuilderState(raw []byte) (BuilderState, error) { - var out BuilderState - if err := strictDecode(raw, &out); err != nil { - return out, err - } - if err := out.Validate(); err != nil { - return out, err - } - return out, nil -} - -func DecodeExplorerBuilderStateV2(raw []byte) (ExplorerBuilderStateV2, error) { - return DecodeBuilderState(raw) -} - func strictDecode(raw []byte, target any) error { if err := rejectDuplicateKeys(raw); err != nil { return fmt.Errorf("strict decode: %w", err) diff --git a/internal/explorer/bootstrap/bootstrap.go b/internal/explorer/bootstrap/bootstrap.go deleted file mode 100644 index 039c9b64..00000000 --- a/internal/explorer/bootstrap/bootstrap.go +++ /dev/null @@ -1,353 +0,0 @@ -// Package bootstrap contains the offline/admin-only conversion from the -// legacy repository default recipe/config to the V1 intent contract. Nothing -// in this package has a runtime store dependency. -package bootstrap - -import ( - "crypto/sha256" - "encoding/hex" - "encoding/json" - "fmt" - "sort" - "strings" - - "github.com/calypr/loom/internal/dataframe/recipe" - "github.com/calypr/loom/internal/explorer" -) - -type Mapping struct { - LegacyPath string `json:"legacyPath"` - LegacyFieldName string `json:"legacyFieldName,omitempty"` - OutputID string `json:"outputId"` - CandidateID string `json:"candidateId"` - OccurrenceID string `json:"occurrenceId"` - EmissionID string `json:"emissionId"` -} - -type Report struct { - Equivalent bool `json:"equivalent"` - LegacyRecipeDigest string `json:"legacyRecipeDigest"` - AuthoringDocumentDigest string `json:"authoringDocumentDigest"` - Mappings []Mapping `json:"mappings"` - Unmapped []string `json:"unmapped,omitempty"` - Ambiguous []string `json:"ambiguous,omitempty"` -} - -type ConversionError struct{ Report Report } - -func (e *ConversionError) Error() string { return "legacy default conversion is not exact" } - -// ConvertDefault converts every legacy recipe output into one V1 builder -// document and converts each legacy view into an ordered V1 tab. Recipe -// operations that cannot be represented by V1 intent are rejected; no field is -// guessed or silently dropped. -func ConvertDefault(rawConfig []byte, catalog explorer.Catalog, project string) (explorer.ExplorerAuthoringBundleV1, Report, error) { - cfg, legacy, err := explorer.DecodeDefaultConfigV2(rawConfig, project) - if err != nil { - return explorer.ExplorerAuthoringBundleV1{}, Report{}, fmt.Errorf("decode legacy default: %w", err) - } - report := Report{} - report.LegacyRecipeDigest, _ = legacy.Digest() - nodeIDs, err := uniqueNodeIDs(catalog) - if err != nil { - report.Ambiguous = append(report.Ambiguous, "catalog.nodes") - return explorer.ExplorerAuthoringBundleV1{}, report, &ConversionError{Report: report} - } - documents := make([]explorer.ExplorerBuilderDocumentV1, 0, len(legacy.Outputs)) - documentByLegacyOutput := make(map[string]int, len(legacy.Outputs)) - allMappings := make([]Mapping, 0) - for outputIndex, output := range legacy.Outputs { - document, mappings, conversionErr := convertOutput(cfg, output, outputIndex, catalog, nodeIDs, &report) - if conversionErr != nil { - return explorer.ExplorerAuthoringBundleV1{}, report, conversionErr - } - documentByLegacyOutput[output.Name] = len(documents) - documents = append(documents, document) - allMappings = append(allMappings, mappings...) - } - if err := mapPresentation(cfg, documentByLegacyOutput, documents, allMappings, &report); err != nil { - return explorer.ExplorerAuthoringBundleV1{}, report, err - } - tabs := make([]explorer.ExplorerTabV1, 0, len(cfg.Views)) - for index, view := range cfg.Views { - documentIndex, ok := documentByLegacyOutput[view.Output] - if !ok { - report.Unmapped = append(report.Unmapped, fmt.Sprintf("views[%d].output", index)) - return explorer.ExplorerAuthoringBundleV1{}, report, &ConversionError{Report: report} - } - tabs = append(tabs, explorer.ExplorerTabV1{ID: explorer.StableExplorerID(view.ID), Title: view.Title, OutputID: documents[documentIndex].Output.ID, Order: index}) - } - for i := range documents { - sort.Strings(documents[i].CandidateIDs) - } - bundle := explorer.ExplorerAuthoringBundleV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, Project: project, ExplorerID: "default", Title: cfg.Explorer.Title, Tabs: tabs} - if len(documents) == 1 { - // Keep the in-memory compatibility field populated for callers that have - // not yet moved to the canonical multi-document representation. - bundle.Document = documents[0] - } else { - bundle.Documents = documents - } - bundle.IntentDigest, err = bundle.DocumentDigest() - if err != nil { - return explorer.ExplorerAuthoringBundleV1{}, report, err - } - report.AuthoringDocumentDigest = bundle.IntentDigest - report.Equivalent = len(report.Unmapped) == 0 && len(report.Ambiguous) == 0 - if !report.Equivalent { - return explorer.ExplorerAuthoringBundleV1{}, report, &ConversionError{Report: report} - } - return bundle, report, nil -} - -func convertOutput(cfg explorer.ConfigV2, output recipe.Output, outputIndex int, catalog explorer.Catalog, nodeIDs map[string]string, report *Report) (explorer.ExplorerBuilderDocumentV1, []Mapping, error) { - baseNode, ok := nodeIDs[output.RootResourceType] - if !ok { - report.Unmapped = append(report.Unmapped, fmt.Sprintf("outputs[%d].rootResourceType", outputIndex)) - return explorer.ExplorerBuilderDocumentV1{}, nil, &ConversionError{Report: *report} - } - document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: explorer.StableExplorerID(output.Name), Title: titleForOutput(cfg, output.Name)}, BaseNodeID: baseNode, RowNodeID: baseNode, Presentation: map[string]explorer.ExplorerPresentationBindingV1{}} - currentNode := baseNode - mappingsBefore := len(report.Mappings) - var walkTraversals func([]recipe.Traversal, string, string, int) error - walkTraversals = func(traversals []recipe.Traversal, parentNode, parentOccurrence string, depth int) error { - if len(traversals) > 1 { - report.Ambiguous = append(report.Ambiguous, fmt.Sprintf("traversal[%d]", depth)) - return &ConversionError{Report: *report} - } - for index, traversal := range traversals { - if len(traversal.Traversals) > 1 { - report.Ambiguous = append(report.Ambiguous, fmt.Sprintf("traversal[%d].traversals", depth)) - return &ConversionError{Report: *report} - } - childNode, edgeID, err := exactEdge(catalog, parentNode, traversal.Name, traversal.ToResourceType) - if err != nil { - report.Ambiguous = append(report.Ambiguous, fmt.Sprintf("traversal[%d]", depth)) - return &ConversionError{Report: *report} - } - occurrenceID := fmt.Sprintf("route_%d", len(document.RouteEdgeIDs)) - document.RouteEdgeIDs = append(document.RouteEdgeIDs, edgeID) - document.RouteOccurrences = append(document.RouteOccurrences, explorer.ExplorerRouteOccurrenceV1{ID: occurrenceID, Index: len(document.RouteEdgeIDs) - 1, NodeID: childNode, IncomingEdgeID: edgeID}) - if err := mapFields(traversal.Fields, childNode, occurrenceID, traversalPath(parentOccurrence, index), catalog, &document, report); err != nil { - return err - } - if err := walkTraversals(traversal.Traversals, childNode, occurrenceID, depth+1); err != nil { - return err - } - currentNode = childNode - } - return nil - } - if err := mapFields(output.Fields, baseNode, "base", fmt.Sprintf("outputs[%d]", outputIndex), catalog, &document, report); err != nil { - return explorer.ExplorerBuilderDocumentV1{}, nil, err - } - if err := walkTraversals(output.Traversals, baseNode, "root", 0); err != nil { - return explorer.ExplorerBuilderDocumentV1{}, nil, err - } - document.RowNodeID = currentNode - for i := mappingsBefore; i < len(report.Mappings); i++ { - report.Mappings[i].OutputID = document.Output.ID - } - return document, append([]Mapping(nil), report.Mappings[mappingsBefore:]...), nil -} - -func uniqueNodeIDs(catalog explorer.Catalog) (map[string]string, error) { - out := map[string]string{} - for _, node := range catalog.Nodes { - if old, ok := out[node.ResourceType]; ok && old != node.ID { - return nil, fmt.Errorf("resource type %q has multiple node IDs", node.ResourceType) - } - out[node.ResourceType] = node.ID - } - return out, nil -} -func exactEdge(catalog explorer.Catalog, parentNode, label, childType string) (string, string, error) { - var child, edge string - for _, candidate := range catalog.Edges { - fromMatches := candidate.FromNodeID == parentNode - toMatches := candidate.ToNodeID == parentNode - other := "" - if fromMatches { - other = candidate.ToNodeID - } - if toMatches { - other = candidate.FromNodeID - } - if (fromMatches || toMatches) && candidate.Label == label { - node, ok := catalogNodeByID(catalog, other) - if !ok || node.ResourceType != childType { - continue - } - if child != "" { - return "", "", fmt.Errorf("ambiguous edge") - } - child, edge = other, candidate.ID - } - } - if edge == "" { - return "", "", fmt.Errorf("unmapped edge") - } - return child, edge, nil -} -func catalogNodeByID(catalog explorer.Catalog, id string) (explorer.CatalogNode, bool) { - for _, node := range catalog.Nodes { - if node.ID == id { - return node, true - } - } - return explorer.CatalogNode{}, false -} - -func mapFields(fields []recipe.Field, nodeID, occurrenceID, path string, catalog explorer.Catalog, document *explorer.ExplorerBuilderDocumentV1, report *Report) error { - for index, field := range fields { - if field.Expr.Select == "" || field.Expr.Call != "" || field.Expr.Literal != nil || field.Expr.Document != nil { - report.Unmapped = append(report.Unmapped, fmt.Sprintf("%s.fields[%d].expr", path, index)) - return &ConversionError{Report: *report} - } - selectPath := strings.TrimSpace(field.Expr.Select) - if dot := strings.IndexByte(selectPath, '.'); dot > 0 { - prefix := selectPath[:dot] - if prefix == "root" || strings.HasPrefix(prefix, "route_") { - selectPath = selectPath[dot+1:] - } - } - matches := []explorer.CatalogSelection{} - for _, selection := range catalog.Selections { - if selection.NodeID != nodeID { - continue - } - if field.FieldRef != "" && selection.FieldRef == field.FieldRef { - matches = append(matches, selection) - continue - } - if field.FieldRef == "" && selection.Select == selectPath { - matches = append(matches, selection) - } - } - if len(matches) != 1 { - if len(matches) == 0 { - report.Unmapped = append(report.Unmapped, fmt.Sprintf("%s.fields[%d]", path, index)) - } else { - report.Ambiguous = append(report.Ambiguous, fmt.Sprintf("%s.fields[%d]", path, index)) - } - return &ConversionError{Report: *report} - } - candidate := matches[0].ID - found := false - for _, old := range document.CandidateIDs { - if old == candidate { - found = true - } - } - if !found { - document.CandidateIDs = append(document.CandidateIDs, candidate) - } - if occurrenceID != "base" { - for _, ref := range document.CandidateOccurrences { - if ref.CandidateID == candidate && ref.OccurrenceID == occurrenceID { - report.Ambiguous = append(report.Ambiguous, fmt.Sprintf("%s.fields[%d]", path, index)) - return &ConversionError{Report: *report} - } - } - document.CandidateOccurrences = append(document.CandidateOccurrences, explorer.ExplorerCandidateOccurrenceV1{CandidateID: candidate, OccurrenceID: occurrenceID}) - } - emissionID := explorer.OpaqueID("em_", document.Output.ID+"\x00"+occurrenceID+"\x00"+candidate) - report.Mappings = append(report.Mappings, Mapping{LegacyPath: fmt.Sprintf("%s.fields[%d]", path, index), LegacyFieldName: field.Name, CandidateID: candidate, OccurrenceID: occurrenceID, EmissionID: emissionID}) - } - return nil -} - -func mapPresentation(cfg explorer.ConfigV2, documentByLegacyOutput map[string]int, documents []explorer.ExplorerBuilderDocumentV1, mappings []Mapping, report *Report) error { - for viewIndex, view := range cfg.Views { - documentIndex, ok := documentByLegacyOutput[view.Output] - if !ok { - report.Unmapped = append(report.Unmapped, fmt.Sprintf("views[%d].output", viewIndex)) - return &ConversionError{Report: *report} - } - document := &documents[documentIndex] - for index, column := range view.Table.Columns { - mapping, ok, ambiguous := findMappingByFieldName(mappings, document.Output.ID, column.Column) - if ambiguous { - report.Ambiguous = append(report.Ambiguous, fmt.Sprintf("views[%s].table.columns[%d]", view.ID, index)) - return &ConversionError{Report: *report} - } - if !ok { - report.Unmapped = append(report.Unmapped, fmt.Sprintf("views[%s].table.columns[%d]", view.ID, index)) - return &ConversionError{Report: *report} - } - binding := document.Presentation[mapping.EmissionID] - binding.Label = firstNonEmpty(column.Label, column.Column) - visible := column.Visible - binding.Visible = &visible - document.Presentation[mapping.EmissionID] = binding - } - for _, filter := range view.Filters { - mapping, ok, ambiguous := findMappingByFieldName(mappings, document.Output.ID, filter.Column) - if ambiguous { - report.Ambiguous = append(report.Ambiguous, "views.filters") - return &ConversionError{Report: *report} - } - if !ok { - report.Unmapped = append(report.Unmapped, "views.filters") - return &ConversionError{Report: *report} - } - binding := document.Presentation[mapping.EmissionID] - if filter.Label != "" { - binding.Filter = &explorer.ExplorerFilterBindingV1{Label: filter.Label} - } - document.Presentation[mapping.EmissionID] = binding - } - for _, chart := range view.Charts { - mapping, ok, ambiguous := findMappingByFieldName(mappings, document.Output.ID, chart.Column) - if ambiguous { - report.Ambiguous = append(report.Ambiguous, "views.charts") - return &ConversionError{Report: *report} - } - if !ok { - report.Unmapped = append(report.Unmapped, "views.charts") - return &ConversionError{Report: *report} - } - binding := document.Presentation[mapping.EmissionID] - binding.Chart = &explorer.ExplorerChartBindingV1{Type: chart.Type, Title: chart.Title} - document.Presentation[mapping.EmissionID] = binding - } - } - return nil -} - -func findMappingByFieldName(mappings []Mapping, outputID, name string) (Mapping, bool, bool) { - var found Mapping - count := 0 - for _, mapping := range mappings { - if mapping.OutputID == outputID && mapping.LegacyFieldName == name { - found = mapping - count++ - } - } - return found, count == 1, count > 1 -} -func titleForOutput(cfg explorer.ConfigV2, output string) string { - for _, view := range cfg.Views { - if view.Output == output { - return view.Title - } - } - return output -} -func firstNonEmpty(values ...string) string { - for _, value := range values { - if strings.TrimSpace(value) != "" { - return value - } - } - return "Explorer" -} -func traversalPath(parent string, index int) string { - return fmt.Sprintf("%s.traversals[%d]", parent, index) -} - -func (r Report) CanonicalJSON() ([]byte, error) { return json.Marshal(r) } -func Digest(raw []byte) string { - sum := sha256.Sum256(raw) - return "sha256:" + hex.EncodeToString(sum[:]) -} diff --git a/internal/explorer/bootstrap/bootstrap_test.go b/internal/explorer/bootstrap/bootstrap_test.go deleted file mode 100644 index 6f2260e0..00000000 --- a/internal/explorer/bootstrap/bootstrap_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package bootstrap - -import ( - "strings" - "testing" - - "github.com/calypr/loom/internal/explorer" -) - -func TestConvertDefaultIsExactAndProducesIntentOnlyBundle(t *testing.T) { - raw := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Default","management":"repository"},"recipe":{"recipeSchemaVersion":1,"name":"legacy","translationVersion":"v1","outputs":[{"name":"patient","rootResourceType":"Patient","rowGrain":"patient","fields":[{"name":"id","fieldRef":"Patient.id","expr":{"select":"root.id"}}]}]},"views":[{"id":"patient","title":"Patients","output":"patient","table":{"columns":[{"column":"id","label":"Patient ID","visible":true}]}}]}`) - catalog := explorer.Catalog{Nodes: []explorer.CatalogNode{{ID: "n_patient", ResourceType: "Patient"}}, Selections: map[string]explorer.CatalogSelection{"s_patient_id": {ID: "s_patient_id", NodeID: "n_patient", FieldRef: "Patient.id", Select: "id"}}} - bundle, report, err := ConvertDefault(raw, catalog, "project-a") - if err != nil { - t.Fatal(err) - } - if !report.Equivalent || len(report.Mappings) != 1 || len(bundle.Document.CandidateIDs) != 1 { - t.Fatalf("report=%#v bundle=%#v", report, bundle) - } - canonical, err := bundle.CanonicalJSON() - if err != nil { - t.Fatal(err) - } - if strings.Contains(string(canonical), "select") || strings.Contains(string(canonical), "expr") || strings.Contains(string(canonical), "recipe") { - t.Fatalf("legacy recipe leaked into bundle: %s", canonical) - } -} - -func TestConvertDefaultPreservesMultipleOutputsAndTabs(t *testing.T) { - raw := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Default","management":"repository"},"recipe":{"recipeSchemaVersion":1,"name":"legacy","translationVersion":"v1","outputs":[{"name":"patient","rootResourceType":"Patient","rowGrain":"patient","fields":[{"name":"id","fieldRef":"Patient.id","expr":{"select":"root.id"}}]},{"name":"specimen","rootResourceType":"Specimen","rowGrain":"specimen","fields":[{"name":"id","fieldRef":"Specimen.id","expr":{"select":"root.id"}}]}]},"views":[{"id":"patient","title":"Patients","output":"patient","table":{"columns":[{"column":"id","label":"Patient ID","visible":true}]}},{"id":"specimen","title":"Specimens","output":"specimen","table":{"columns":[{"column":"id","label":"Specimen ID","visible":true}]}}]}`) - catalog := explorer.Catalog{ - Nodes: []explorer.CatalogNode{{ID: "n_patient", ResourceType: "Patient"}, {ID: "n_specimen", ResourceType: "Specimen"}}, - Selections: map[string]explorer.CatalogSelection{ - "s_patient_id": {ID: "s_patient_id", NodeID: "n_patient", FieldRef: "Patient.id", Select: "id"}, - "s_specimen_id": {ID: "s_specimen_id", NodeID: "n_specimen", FieldRef: "Specimen.id", Select: "id"}, - }, - } - bundle, report, err := ConvertDefault(raw, catalog, "project-a") - if err != nil { - t.Fatal(err) - } - if !report.Equivalent || len(bundle.Documents) != 2 || len(bundle.Tabs) != 2 || len(report.Mappings) != 2 { - t.Fatalf("report=%#v bundle=%#v", report, bundle) - } - canonical, err := bundle.CanonicalJSON() - if err != nil { - t.Fatal(err) - } - if strings.Contains(string(canonical), "select") || strings.Contains(string(canonical), "expr") || !strings.Contains(string(canonical), `"documents"`) || !strings.Contains(string(canonical), `"tabs"`) { - t.Fatalf("multi-output conversion leaked recipe or lost tabs: %s", canonical) - } -} - -func TestConvertDefaultFailsOnUnmappedField(t *testing.T) { - raw := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Default","management":"repository"},"recipe":{"recipeSchemaVersion":1,"name":"legacy","translationVersion":"v1","outputs":[{"name":"patient","rootResourceType":"Patient","rowGrain":"patient","fields":[{"name":"missing","expr":{"select":"root.missing"}}]}]}}`) - catalog := explorer.Catalog{Nodes: []explorer.CatalogNode{{ID: "n_patient", ResourceType: "Patient"}}, Selections: map[string]explorer.CatalogSelection{}} - _, report, err := ConvertDefault(raw, catalog, "project-a") - if err == nil || len(report.Unmapped) == 0 { - t.Fatalf("err=%v report=%#v", err, report) - } -} diff --git a/internal/explorer/canonical_json.go b/internal/explorer/canonical_json.go index 44afb283..3636f0b2 100644 --- a/internal/explorer/canonical_json.go +++ b/internal/explorer/canonical_json.go @@ -33,3 +33,48 @@ func canonicalJSONBytes(raw []byte) ([]byte, error) { } return canonical, nil } + +func rejectDuplicateJSONKeys(raw []byte) error { + decoder := json.NewDecoder(bytes.NewReader(raw)) + var walk func(string) error + walk = func(path string) error { + token, err := decoder.Token() + if err != nil { + return err + } + delim, ok := token.(json.Delim) + if !ok { + return nil + } + switch delim { + case '{': + seen := map[string]bool{} + for decoder.More() { + keyToken, err := decoder.Token() + if err != nil { + return err + } + key := keyToken.(string) + if seen[key] { + return fmt.Errorf("duplicate JSON object key %q at %s", key, path) + } + seen[key] = true + if err := walk(path + "." + key); err != nil { + return err + } + } + _, err = decoder.Token() + return err + case '[': + for index := 0; decoder.More(); index++ { + if err := walk(fmt.Sprintf("%s[%d]", path, index)); err != nil { + return err + } + } + _, err = decoder.Token() + return err + } + return nil + } + return walk("$") +} diff --git a/internal/explorer/capability/builder.go b/internal/explorer/capability/builder.go index 5d113234..256ca622 100644 --- a/internal/explorer/capability/builder.go +++ b/internal/explorer/capability/builder.go @@ -93,48 +93,6 @@ type CompilerProbe interface { ProbeCandidate(context.Context, Candidate) (CandidateProof, error) } -// Function adapters keep tests and small integrations free of boilerplate. -type ProbeFuncs struct { - Node func(context.Context, Node) (NodeProof, error) - Edge func(context.Context, Edge) (EdgeProof, error) - Candidate func(context.Context, Candidate) (CandidateProof, error) -} - -func (p ProbeFuncs) ProbeNode(ctx context.Context, n Node) (NodeProof, error) { - if p.Node == nil { - return NodeProof{}, fmt.Errorf("node probe is not configured") - } - return p.Node(ctx, n) -} -func (p ProbeFuncs) ProbeEdge(ctx context.Context, e Edge) (EdgeProof, error) { - if p.Edge == nil { - return EdgeProof{}, fmt.Errorf("edge probe is not configured") - } - return p.Edge(ctx, e) -} -func (p ProbeFuncs) ProbeCandidate(ctx context.Context, c Candidate) (CandidateProof, error) { - if p.Candidate == nil { - return CandidateProof{}, fmt.Errorf("candidate probe is not configured") - } - return p.Candidate(ctx, c) -} - -type SliceObserver struct { - Resources []ResourceObservation - Relationships []RelationshipObservation - Fields []FieldObservation -} - -func (s SliceObserver) ListResources(context.Context) ([]ResourceObservation, error) { - return append([]ResourceObservation(nil), s.Resources...), nil -} -func (s SliceObserver) ListRelationships(context.Context) ([]RelationshipObservation, error) { - return append([]RelationshipObservation(nil), s.Relationships...), nil -} -func (s SliceObserver) ListFields(context.Context) ([]FieldObservation, error) { - return append([]FieldObservation(nil), s.Fields...), nil -} - type Builder struct { Identity SnapshotIdentity Policy Policy diff --git a/internal/explorer/capability/builder_test.go b/internal/explorer/capability/builder_test.go index 43695d30..0ad579ac 100644 --- a/internal/explorer/capability/builder_test.go +++ b/internal/explorer/capability/builder_test.go @@ -2,10 +2,56 @@ package capability import ( "context" + "fmt" "reflect" "testing" ) +type ProbeFuncs struct { + Node func(context.Context, Node) (NodeProof, error) + Edge func(context.Context, Edge) (EdgeProof, error) + Candidate func(context.Context, Candidate) (CandidateProof, error) +} + +func (p ProbeFuncs) ProbeNode(ctx context.Context, node Node) (NodeProof, error) { + if p.Node == nil { + return NodeProof{}, fmt.Errorf("node probe is not configured") + } + return p.Node(ctx, node) +} + +func (p ProbeFuncs) ProbeEdge(ctx context.Context, edge Edge) (EdgeProof, error) { + if p.Edge == nil { + return EdgeProof{}, fmt.Errorf("edge probe is not configured") + } + return p.Edge(ctx, edge) +} + +func (p ProbeFuncs) ProbeCandidate(ctx context.Context, candidate Candidate) (CandidateProof, error) { + if p.Candidate == nil { + return CandidateProof{}, fmt.Errorf("candidate probe is not configured") + } + return p.Candidate(ctx, candidate) +} + +type SliceObserver struct { + Resources []ResourceObservation + Relationships []RelationshipObservation + Fields []FieldObservation +} + +func (s SliceObserver) ListResources(context.Context) ([]ResourceObservation, error) { + return append([]ResourceObservation(nil), s.Resources...), nil +} + +func (s SliceObserver) ListRelationships(context.Context) ([]RelationshipObservation, error) { + return append([]RelationshipObservation(nil), s.Relationships...), nil +} + +func (s SliceObserver) ListFields(context.Context) ([]FieldObservation, error) { + return append([]FieldObservation(nil), s.Fields...), nil +} + func testIdentity() SnapshotIdentity { return SnapshotIdentity{Project: "p", Generation: "g", AuthorizationScopeDigest: "scope", SchemaDigest: "schema", ResourceInventoryDigest: "inventory", RelationshipDigest: "relationships", FieldDigest: "fields", ProtocolVersion: "protocol-1", CompilerVersion: "compiler-1", TraversalPolicyVersion: "route-1", ProjectionPolicyVersion: "projection-1"} } diff --git a/internal/explorer/capabilitystore/repository.go b/internal/explorer/capabilitystore/repository.go index a07ebdfc..22f37ec7 100644 --- a/internal/explorer/capabilitystore/repository.go +++ b/internal/explorer/capabilitystore/repository.go @@ -3,15 +3,11 @@ package capabilitystore import ( - "bytes" "context" "crypto/sha256" "encoding/hex" "errors" "fmt" - "reflect" - "sort" - "sync" "github.com/calypr/loom/internal/explorer/capability" ) @@ -35,95 +31,6 @@ type Repository interface { // the rest of Explorer. type Store = Repository -type identityKey struct { - Identity capability.SnapshotIdentity -} - -// MemoryStore is a concurrency-safe, defensive-copy repository for tests and -// local deployments. The values held by the store are never handed directly -// to callers. -type MemoryStore struct { - mu sync.RWMutex - byToken map[string]capability.Snapshot - byIdentity map[identityKey]map[string]struct{} -} - -func NewMemoryStore() *MemoryStore { - return &MemoryStore{byToken: make(map[string]capability.Snapshot), byIdentity: make(map[identityKey]map[string]struct{})} -} - -func NewMemoryRepository() *MemoryStore { return NewMemoryStore() } - -func (s *MemoryStore) Put(ctx context.Context, snapshot capability.Snapshot) (*capability.Snapshot, error) { - if err := contextErr(ctx); err != nil { - return nil, err - } - if err := validate(snapshot); err != nil { - return nil, err - } - - s.mu.Lock() - defer s.mu.Unlock() - if previous, ok := s.byToken[snapshot.Token]; ok { - if !bytes.Equal(previous.CanonicalPayload(), snapshot.CanonicalPayload()) { - return nil, fmt.Errorf("%w: %s", ErrTokenCollision, snapshot.Token) - } - out := clone(previous) - return &out, nil - } - - stored := clone(snapshot) - s.byToken[stored.Token] = stored - key := identityKey{Identity: stored.Identity} - if s.byIdentity[key] == nil { - s.byIdentity[key] = make(map[string]struct{}) - } - s.byIdentity[key][stored.Token] = struct{}{} - out := clone(stored) - return &out, nil -} - -func (s *MemoryStore) GetByToken(ctx context.Context, token string) (*capability.Snapshot, error) { - if err := contextErr(ctx); err != nil { - return nil, err - } - s.mu.RLock() - defer s.mu.RUnlock() - value, ok := s.byToken[token] - if !ok { - return nil, ErrNotFound - } - out := clone(value) - return &out, nil -} - -func (s *MemoryStore) GetByIdentity(ctx context.Context, identity capability.SnapshotIdentity) (*capability.Snapshot, error) { - if err := contextErr(ctx); err != nil { - return nil, err - } - s.mu.RLock() - defer s.mu.RUnlock() - tokens := s.byIdentity[identityKey{Identity: identity}] - if len(tokens) == 0 { - return nil, ErrNotFound - } - ordered := make([]string, 0, len(tokens)) - for token := range tokens { - ordered = append(ordered, token) - } - sort.Strings(ordered) - for _, status := range []capability.Status{capability.StatusReady, capability.StatusBuilding, capability.StatusFailed} { - for _, token := range ordered { - value := s.byToken[token] - if value.Status == status { - out := clone(value) - return &out, nil - } - } - } - return nil, ErrNotFound -} - func validate(snapshot capability.Snapshot) error { if snapshot.Token == "" { return fmt.Errorf("%w: token is required", ErrInvalidSnapshot) @@ -146,89 +53,3 @@ func snapshotToken(snapshot capability.Snapshot) string { sum := sha256.Sum256(snapshot.CanonicalPayload()) return "sha256:" + hex.EncodeToString(sum[:]) } - -func contextErr(ctx context.Context) error { - if ctx == nil { - return nil - } - select { - case <-ctx.Done(): - return ctx.Err() - default: - return nil - } -} - -func clone(in capability.Snapshot) capability.Snapshot { - out := in.Clone() - for i := range out.Diagnostics { - out.Diagnostics[i].Details = cloneDetails(out.Diagnostics[i].Details) - } - return out -} - -// cloneDetails recursively copies JSON-like diagnostic values. Snapshot.Clone -// already copies the outer map; this closes the less obvious alias through a -// nested map or slice in Details. -func cloneDetails(in map[string]any) map[string]any { - if in == nil { - return nil - } - out := make(map[string]any, len(in)) - for key, value := range in { - cloned := cloneValue(reflect.ValueOf(value)) - if cloned.IsValid() { - out[key] = cloned.Interface() - } else { - out[key] = nil - } - } - return out -} - -func cloneValue(value reflect.Value) reflect.Value { - if !value.IsValid() { - return reflect.ValueOf((*any)(nil)).Elem() - } - switch value.Kind() { - case reflect.Interface: - if value.IsNil() { - return reflect.Zero(value.Type()) - } - copied := cloneValue(value.Elem()) - out := reflect.New(value.Type()).Elem() - out.Set(copied) - return out - case reflect.Map: - if value.IsNil() { - return reflect.Zero(value.Type()) - } - out := reflect.MakeMapWithSize(value.Type(), value.Len()) - iter := value.MapRange() - for iter.Next() { - out.SetMapIndex(cloneValue(iter.Key()), cloneValue(iter.Value())) - } - return out - case reflect.Slice: - if value.IsNil() { - return reflect.Zero(value.Type()) - } - out := reflect.MakeSlice(value.Type(), value.Len(), value.Len()) - reflect.Copy(out, value) - for i := 0; i < out.Len(); i++ { - out.Index(i).Set(cloneValue(value.Index(i))) - } - return out - case reflect.Pointer: - if value.IsNil() { - return reflect.Zero(value.Type()) - } - out := reflect.New(value.Type().Elem()) - out.Elem().Set(cloneValue(value.Elem())) - return out - default: - return value - } -} - -var _ Repository = (*MemoryStore)(nil) diff --git a/internal/explorer/capabilitystore/repository_test.go b/internal/explorer/capabilitystore/repository_test.go deleted file mode 100644 index 9aa5ed12..00000000 --- a/internal/explorer/capabilitystore/repository_test.go +++ /dev/null @@ -1,92 +0,0 @@ -package capabilitystore - -import ( - "context" - "errors" - "testing" - - "github.com/calypr/loom/internal/explorer/capability" -) - -func testSnapshot(status capability.Status, complete bool) capability.Snapshot { - return capability.NewSnapshot( - capability.SnapshotIdentity{ - Project: "project-a", Generation: "generation-a", AuthorizationScopeDigest: "scope-a", - SchemaDigest: "schema-a", RelationshipDigest: "relationship-a", FieldDigest: "field-a", - ProtocolVersion: "protocol-a", CompilerVersion: "compiler-a", TraversalPolicyVersion: "traversal-a", ProjectionPolicyVersion: "projection-a", - }, - capability.Policy{Route: capability.RoutePolicy{Version: "route-a"}, Projection: capability.ProjectionPolicy{Version: "projection-a", Modes: []capability.ProjectionMode{capability.ProjectionFirst}}}, - status, complete, false, - []capability.Node{{ID: "node-a", ResourceType: "Patient", RowRootEligible: true, SupportedOperations: []capability.Operation{capability.OperationSelect}}}, - nil, nil, - []capability.Diagnostic{{Code: "notice", Message: "kept", Details: map[string]any{"nested": map[string]any{"value": "original"}}}}, - ) -} - -func TestMemoryStoreIsIdempotentAndDefensive(t *testing.T) { - ctx := context.Background() - store := NewMemoryStore() - want := testSnapshot(capability.StatusReady, true) - got, err := store.Put(ctx, want) - if err != nil { - t.Fatal(err) - } - got.Nodes[0].SupportedOperations[0] = capability.OperationFilter - got.Diagnostics[0].Details["nested"].(map[string]any)["value"] = "changed" - gotAgain, err := store.Put(ctx, want) - if err != nil { - t.Fatal(err) - } - if gotAgain.Nodes[0].SupportedOperations[0] != capability.OperationSelect { - t.Fatal("Put returned an aliased node slice") - } - read, err := store.GetByToken(ctx, want.Token) - if err != nil { - t.Fatal(err) - } - if read.Diagnostics[0].Details["nested"].(map[string]any)["value"] != "original" { - t.Fatal("nested diagnostic data was aliased") - } - if read.Token != want.Token { - t.Fatalf("token=%q, want %q", read.Token, want.Token) - } -} - -func TestMemoryStoreIdentityPrefersReadyAndRetainsFailedDiagnostics(t *testing.T) { - ctx := context.Background() - store := NewMemoryStore() - failed := testSnapshot(capability.StatusFailed, false) - if _, err := store.Put(ctx, failed); err != nil { - t.Fatal(err) - } - got, err := store.GetByIdentity(ctx, failed.Identity) - if err != nil || got.Status != capability.StatusFailed { - t.Fatalf("failed lookup=(%v, %v)", got, err) - } - ready := testSnapshot(capability.StatusReady, true) - if _, err := store.Put(ctx, ready); err != nil { - t.Fatal(err) - } - got, err = store.GetByIdentity(ctx, ready.Identity) - if err != nil || got.Status != capability.StatusReady { - t.Fatalf("ready lookup=(%v, %v)", got, err) - } -} - -func TestMemoryStoreRejectsUnusableReadyAndTokenCollision(t *testing.T) { - ctx := context.Background() - store := NewMemoryStore() - unusable := testSnapshot(capability.StatusReady, false) - if _, err := store.Put(ctx, unusable); !errors.Is(err, ErrInvalidSnapshot) { - t.Fatalf("Put unusable READY error=%v", err) - } - first := testSnapshot(capability.StatusFailed, false) - if _, err := store.Put(ctx, first); err != nil { - t.Fatal(err) - } - collision := testSnapshot(capability.StatusReady, true) - collision.Token = first.Token - if _, err := store.Put(ctx, collision); !errors.Is(err, ErrInvalidSnapshot) { - t.Fatalf("Put token collision error=%v", err) - } -} diff --git a/internal/explorer/catalog.go b/internal/explorer/catalog.go deleted file mode 100644 index a5169e40..00000000 --- a/internal/explorer/catalog.go +++ /dev/null @@ -1,103 +0,0 @@ -package explorer - -import ( - "crypto/sha256" - "encoding/hex" - "encoding/json" - "sort" -) - -// Catalog is assembled server-side from scoped Loom catalog discovery. The -// browser receives only opaque IDs; source selectors never cross this seam. -type Catalog struct { - Nodes []CatalogNode - Edges []CatalogEdge - Selections map[string]CatalogSelection -} - -type CatalogNode struct { - ID string - ResourceType string -} - -type CatalogEdge struct{ ID, FromNodeID, ToNodeID, Label string } - -type CatalogSelection struct { - ID string - NodeID string - FieldRef string - Select string - LogicalType string - Cardinality string - ProjectionModes []string - DefaultProjectionMode string - FilterOperators []string - ChartOperations []string - Filterable bool - Chartable bool -} - -// DiscoveryResult makes incomplete discovery explicit. Production catalog -// adapters must never silently translate an upstream failure into an empty, -// apparently complete catalog. -type DiscoveryResult[T any] struct { - Values []T - Complete bool - Truncated bool - Diagnostics []Diagnostic -} -type CatalogSnapshot struct { - Project, Generation, AuthorizationScopeDigest string - Catalog Catalog - ResolvedSchemaDigest string - Complete bool - Truncated bool - Diagnostics []Diagnostic - Token string -} - -func NewCatalogSnapshot(project, generation, scope string, catalog Catalog, complete, truncated bool, diagnostics []Diagnostic) (CatalogSnapshot, error) { - return NewCatalogSnapshotWithSchema(project, generation, scope, "", catalog, complete, truncated, diagnostics) -} - -// NewCatalogSnapshotWithSchema is the compatibility snapshot constructor used -// while V1 authoring documents are migrated to compiler-owned capabilities. -// The schema digest is part of the content address: attaching it after token -// construction would allow a generated-schema change to reuse stale opaque -// node, edge, and selection IDs. -func NewCatalogSnapshotWithSchema(project, generation, scope, schemaDigest string, catalog Catalog, complete, truncated bool, diagnostics []Diagnostic) (CatalogSnapshot, error) { - nodes := append([]CatalogNode(nil), catalog.Nodes...) - sort.Slice(nodes, func(i, j int) bool { return nodes[i].ID < nodes[j].ID }) - edges := append([]CatalogEdge(nil), catalog.Edges...) - sort.Slice(edges, func(i, j int) bool { return edges[i].ID < edges[j].ID }) - selectionIDs := make([]string, 0, len(catalog.Selections)) - for id := range catalog.Selections { - selectionIDs = append(selectionIDs, id) - } - sort.Strings(selectionIDs) - identity := struct { - Project, Generation, Scope, SchemaDigest string - Nodes []CatalogNode - Edges []CatalogEdge - Selections []CatalogSelection - Complete, Truncated bool - }{Project: project, Generation: generation, Scope: scope, SchemaDigest: schemaDigest, Nodes: nodes, Edges: edges, Complete: complete, Truncated: truncated} - for _, id := range selectionIDs { - identity.Selections = append(identity.Selections, catalog.Selections[id]) - } - raw, err := json.Marshal(identity) - if err != nil { - return CatalogSnapshot{}, err - } - sum := sha256.Sum256(raw) - return CatalogSnapshot{Project: project, Generation: generation, AuthorizationScopeDigest: scope, Catalog: catalog, ResolvedSchemaDigest: schemaDigest, Complete: complete, Truncated: truncated, Diagnostics: append([]Diagnostic(nil), diagnostics...), Token: "sha256:" + hex.EncodeToString(sum[:])}, nil -} -func (s CatalogSnapshot) ValidateToken(token string) error { - if token == "" || token != s.Token { - return ErrStaleCatalog - } - if !s.Complete || s.Truncated { - return ErrIncompleteCatalog - } - return nil -} diff --git a/internal/explorer/catalog_test.go b/internal/explorer/catalog_test.go deleted file mode 100644 index 41de1d47..00000000 --- a/internal/explorer/catalog_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package explorer - -import "testing" - -func TestCatalogSnapshotBindsIdentityAndBlocksIncompleteDiscovery(t *testing.T) { - catalog := Catalog{Nodes: []CatalogNode{{ID: "n", ResourceType: "Patient"}}, Selections: map[string]CatalogSelection{"s": {ID: "s", NodeID: "n"}}} - a, err := NewCatalogSnapshot("p", "g", "scope", catalog, true, false, nil) - if err != nil { - t.Fatal(err) - } - if err := a.ValidateToken(a.Token); err != nil { - t.Fatal(err) - } - b, _ := NewCatalogSnapshot("p", "other", "scope", catalog, true, false, nil) - if a.Token == b.Token { - t.Fatal("generation did not affect snapshot") - } - incomplete, _ := NewCatalogSnapshot("p", "g", "scope", catalog, false, true, nil) - if err := incomplete.ValidateToken(incomplete.Token); err != ErrIncompleteCatalog { - t.Fatalf("err=%v", err) - } -} - -func TestCatalogSnapshotTokenBindsResolvedSchemaDigest(t *testing.T) { - catalog := Catalog{Selections: map[string]CatalogSelection{}} - a, err := NewCatalogSnapshotWithSchema("p", "g", "scope", "schema-a", catalog, true, false, nil) - if err != nil { - t.Fatal(err) - } - b, err := NewCatalogSnapshotWithSchema("p", "g", "scope", "schema-b", catalog, true, false, nil) - if err != nil { - t.Fatal(err) - } - if a.Token == b.Token { - t.Fatalf("schema-specific snapshots reused token %q", a.Token) - } - if a.ResolvedSchemaDigest != "schema-a" || b.ResolvedSchemaDigest != "schema-b" { - t.Fatalf("schema digests were not retained: a=%q b=%q", a.ResolvedSchemaDigest, b.ResolvedSchemaDigest) - } -} diff --git a/internal/explorer/compilation/semantic_compile.go b/internal/explorer/compilation/semantic_compile.go new file mode 100644 index 00000000..02a8a889 --- /dev/null +++ b/internal/explorer/compilation/semantic_compile.go @@ -0,0 +1,307 @@ +package compilation + +import ( + "context" + "encoding/json" + "fmt" + "sort" + "strings" + + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataframe/spec" + "github.com/calypr/loom/internal/explorer/authoringv2" + "github.com/calypr/loom/internal/explorer/capability" +) + +type semanticOccurrence struct { + node authoringv2.RouteNode + graph capability.Node + edge *capability.Edge +} + +type semanticRecipeNode struct { + fields []recipe.Field + dynamics []recipe.DynamicColumn + pivots []recipe.Pivot +} + +func compileSemanticDocument(ctx context.Context, project, explorerID string, document authoringv2.Document, snapshot capability.Snapshot) (Result, error) { + if err := contextErr(ctx); err != nil { + return Result{}, err + } + occurrences, order, err := resolveSemanticRoute(document, snapshot) + if err != nil { + return Result{}, err + } + root := occurrences[authoringv2.RootOccurrenceID] + rowGrain, ok := spec.InferRowGrain(root.graph.ResourceType) + if !ok || !root.graph.RowRootEligible { + return Result{}, fail("lower", "UNSUPPORTED_ROW_ROOT", "$.rootResourceType", "root resource type is not an eligible recipe row root", map[string]any{"resourceType": root.graph.ResourceType}, nil) + } + + nodes := make(map[string]*semanticRecipeNode, len(occurrences)) + for id := range occurrences { + nodes[id] = &semanticRecipeNode{} + } + emitted := make([]EmittedColumn, 0, len(document.Columns)) + mappings := make([]IdentityMapping, 0, len(document.Columns)) + presentation := PresentationConfig{OutputID: document.Output.ID, Title: document.Output.Title, Columns: make([]PresentationColumn, 0, len(document.Columns))} + contract := OutputContract{OutputID: document.Output.ID, Columns: make([]OutputColumn, 0, len(document.Columns))} + + for index, column := range document.Columns { + occurrence := occurrences[column.OccurrenceID] + alias := semanticAlias(column.OccurrenceID) + leaf, err := semanticColumnLeaf(column.Column, column.OccurrenceID) + if err != nil { + return Result{}, fail("lower", "COLUMN_ROUTE_PREFIX_MISMATCH", fmt.Sprintf("$.columns[%d].column", index), err.Error(), map[string]any{"column": column.Column, "occurrenceId": column.OccurrenceID}, err) + } + logicalType := firstNonEmpty(column.LogicalType, "string") + filterable, chartable := column.Filter != nil, column.Chart != nil + candidateID := "source_" + shortHash(column.OccurrenceID+"\x00"+column.Source.Kind+"\x00"+column.Source.FieldPath+"\x00"+column.Source.Match) + projectionMode := firstNonEmpty(strings.ToUpper(column.Source.ProjectionMode), "FIRST") + + switch column.Source.Kind { + case authoringv2.SourceField: + candidate, found := semanticFieldCandidate(snapshot, occurrence.graph.ID, column.Source.FieldPath) + if !found { + return Result{}, fail("intent", "STALE_FIELD", fmt.Sprintf("$.columns[%d].source.fieldPath", index), "field is not present on the resolved capability node", map[string]any{"resourceType": occurrence.graph.ResourceType, "fieldPath": column.Source.FieldPath}, nil) + } + candidateID = candidate.ID + logicalType = firstNonEmpty(column.LogicalType, candidate.LogicalType, "string") + filterable = filterable && supportsOperation(candidate.SupportedOperations, capability.OperationFilter) + chartable = chartable && supportsOperation(candidate.SupportedOperations, capability.OperationChart) + path := strings.TrimPrefix(strings.TrimSpace(column.Source.FieldPath), "root.") + nodes[column.OccurrenceID].fields = append(nodes[column.OccurrenceID].fields, recipe.Field{Name: leaf, FieldRef: column.Source.FieldPath, Expr: recipe.Expression{Select: alias + "." + path}, ValueMode: projectionValueMode(projectionMode)}) + case authoringv2.SourceProjectID: + literal, _ := json.Marshal(project) + nodes[column.OccurrenceID].fields = append(nodes[column.OccurrenceID].fields, recipe.Field{Name: leaf, FieldRef: "project.id", Expr: recipe.Expression{Literal: literal}, ValueMode: recipe.ValueModeFirst}) + case authoringv2.SourceObservationComponentByCode: + pivot, pivotErr := semanticObservationPivot(column, alias, leaf) + if pivotErr != nil { + return Result{}, fail("lower", "INVALID_TYPED_SOURCE", fmt.Sprintf("$.columns[%d].source", index), pivotErr.Error(), nil, pivotErr) + } + nodes[column.OccurrenceID].pivots = appendSemanticPivot(nodes[column.OccurrenceID].pivots, pivot) + default: + dynamic, dynamicErr := semanticFixedLookup(column, alias, leaf, logicalType) + if dynamicErr != nil { + return Result{}, fail("lower", "INVALID_TYPED_SOURCE", fmt.Sprintf("$.columns[%d].source", index), dynamicErr.Error(), nil, dynamicErr) + } + nodes[column.OccurrenceID].dynamics = append(nodes[column.OccurrenceID].dynamics, dynamic) + } + + visible := true + orderValue := index + pinned := false + if column.Table != nil { + if column.Table.Visible != nil { + visible = *column.Table.Visible + } + if column.Table.Order != nil { + orderValue = *column.Table.Order + } + pinned = column.Table.Pinned + } else { + visible = false + } + emissionID := column.Column + emission := EmittedColumn{EmissionID: emissionID, OutputID: document.Output.ID, NodeID: occurrence.graph.ID, SelectionID: candidateID, CandidateID: candidateID, OccurrenceID: column.OccurrenceID, ProjectionMode: projectionMode, PublicColumn: column.Column, LogicalType: logicalType, Filterable: filterable, Chartable: chartable} + emitted = append(emitted, emission) + mappings = append(mappings, IdentityMapping{OutputID: document.Output.ID, CandidateID: candidateID, OccurrenceID: column.OccurrenceID, ProjectionMode: projectionMode, EmissionIDs: []string{emissionID}}) + presented := PresentationColumn{EmissionID: emissionID, PublicColumn: column.Column, Label: column.Label, Visible: visible, Order: orderValue, Pinned: pinned} + if column.Filter != nil { + presented.FilterLabel = firstNonEmpty(column.Filter.Label, column.Label) + } + if column.Chart != nil { + presented.ChartType, presented.ChartTitle = column.Chart.Type, column.Chart.Title + } + presentation.Columns = append(presentation.Columns, presented) + contract.Columns = append(contract.Columns, OutputColumn{Column: column.Column, Label: column.Label, LogicalType: logicalType, Filterable: filterable, Chartable: chartable}) + } + + output := recipe.Output{Name: document.Output.ID, RootResourceType: root.graph.ResourceType, RowGrain: string(rowGrain), Fields: nodes[authoringv2.RootOccurrenceID].fields, Pivots: nodes[authoringv2.RootOccurrenceID].pivots, DynamicColumns: nodes[authoringv2.RootOccurrenceID].dynamics, CollisionPolicy: "error"} + output.Traversals = semanticTraversals(document.Route, occurrences, nodes) + bundle := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "explorer_" + safeName(project) + "_" + safeName(explorerID), TranslationVersion: TranslationVersion, Outputs: []recipe.Output{output}} + if err := bundle.Validate(); err != nil { + return Result{}, fail("lower", "INVALID_RECIPE", "$.recipe", err.Error(), nil, err) + } + digest, err := bundle.Digest() + if err != nil { + return Result{}, fail("lower", "RECIPE_DIGEST_FAILED", "$.recipe", "recipe digest could not be calculated", nil, err) + } + _ = order + return Result{Bundle: bundle, RecipeDigest: digest, EmittedColumns: emitted, IdentityMappings: mappings, Presentation: presentation, OutputContract: contract}, nil +} + +func resolveSemanticRoute(document authoringv2.Document, snapshot capability.Snapshot) (map[string]semanticOccurrence, []string, error) { + byType := map[string][]capability.Node{} + for _, node := range snapshot.Nodes { + byType[node.ResourceType] = append(byType[node.ResourceType], node) + } + result := map[string]semanticOccurrence{} + order := []string{} + usedEdges := map[string]bool{} + var walk func(authoringv2.RouteNode, *semanticOccurrence, string, int) error + walk = func(route authoringv2.RouteNode, parent *semanticOccurrence, path string, depth int) error { + if snapshot.Policy.Route.MaxHops > 0 && depth > snapshot.Policy.Route.MaxHops { + return fail("route", "ROUTE_TOO_LONG", path, "route exceeds capability route policy", map[string]any{"maxHops": snapshot.Policy.Route.MaxHops, "hops": depth}, nil) + } + var graph capability.Node + var edge *capability.Edge + if parent == nil { + matches := byType[route.ResourceType] + eligible := matches[:0] + for _, match := range matches { + if match.RowRootEligible { + eligible = append(eligible, match) + } + } + if len(eligible) != 1 { + return fail("route", "AMBIGUOUS_ROOT_RESOURCE", path+".resourceType", "root resource type must resolve to exactly one eligible capability node", map[string]any{"resourceType": route.ResourceType, "matches": len(eligible)}, nil) + } + graph = eligible[0] + } else { + matches := []capability.Edge{} + for _, candidate := range snapshot.Edges { + target, ok := snapshot.Node(candidate.ToNodeID) + if candidate.FromNodeID == parent.graph.ID && ok && target.ResourceType == route.ResourceType && candidate.Label == route.Relationship { + matches = append(matches, candidate) + } + } + if len(matches) != 1 { + return fail("route", "AMBIGUOUS_RELATIONSHIP", path+".relationship", "relationship must resolve to exactly one capability edge", map[string]any{"fromResourceType": parent.graph.ResourceType, "relationship": route.Relationship, "toResourceType": route.ResourceType, "matches": len(matches)}, nil) + } + selected := matches[0] + if usedEdges[selected.ID] && !snapshot.Policy.Route.AllowsRepeatedEdges { + return fail("route", "REPEATED_EDGE_NOT_ALLOWED", path+".relationship", "route policy does not allow repeated edges", nil, nil) + } + if selected.FromNodeID == selected.ToNodeID && !snapshot.Policy.Route.AllowsSelfLoops { + return fail("route", "SELF_LOOP_NOT_ALLOWED", path+".relationship", "route policy does not allow self loops", nil, nil) + } + usedEdges[selected.ID] = true + edge = &selected + graph, _ = snapshot.Node(selected.ToNodeID) + } + current := semanticOccurrence{node: route, graph: graph, edge: edge} + result[route.OccurrenceID] = current + order = append(order, route.OccurrenceID) + children := append([]authoringv2.RouteNode(nil), route.Children...) + sort.SliceStable(children, func(i, j int) bool { return children[i].OccurrenceID < children[j].OccurrenceID }) + for i := range children { + if err := walk(children[i], ¤t, fmt.Sprintf("%s.children[%d]", path, i), depth+1); err != nil { + return err + } + } + return nil + } + if err := walk(document.Route, nil, "$.route", 0); err != nil { + return nil, nil, err + } + return result, order, nil +} + +func semanticTraversals(route authoringv2.RouteNode, occurrences map[string]semanticOccurrence, nodes map[string]*semanticRecipeNode) []recipe.Traversal { + children := append([]authoringv2.RouteNode(nil), route.Children...) + sort.SliceStable(children, func(i, j int) bool { return children[i].OccurrenceID < children[j].OccurrenceID }) + result := make([]recipe.Traversal, 0, len(children)) + for _, child := range children { + occurrence := occurrences[child.OccurrenceID] + node := nodes[child.OccurrenceID] + result = append(result, recipe.Traversal{Name: recipeName(occurrence.edge.Label, occurrence.edge.ID), Alias: semanticAlias(child.OccurrenceID), ToResourceType: occurrence.graph.ResourceType, MatchMode: recipe.MatchOptional, Fields: node.fields, Pivots: node.pivots, DynamicColumns: node.dynamics, Traversals: semanticTraversals(child, occurrences, nodes)}) + } + return result +} + +func semanticAlias(occurrenceID string) string { + if occurrenceID == authoringv2.RootOccurrenceID { + return "root" + } + alias := safeName(occurrenceID) + if split := strings.LastIndex(alias, "__"); split >= 0 { + return alias[split+2:] + } + return alias +} + +func semanticColumnLeaf(column, occurrenceID string) (string, error) { + if occurrenceID == authoringv2.RootOccurrenceID { + return column, nil + } + // Occurrence IDs encode the complete authored route path, while recipe + // traversal aliases are local to their parent. Strip the complete prefix + // here; physical lowering reconstructs it from the nested aliases. + prefix := safeName(occurrenceID) + "__" + if !strings.HasPrefix(column, prefix) || strings.TrimPrefix(column, prefix) == "" { + return "", fmt.Errorf("column for occurrence %q must begin with %q", occurrenceID, prefix) + } + return strings.TrimPrefix(column, prefix), nil +} + +func semanticFieldCandidate(snapshot capability.Snapshot, nodeID, fieldPath string) (capability.Candidate, bool) { + want := strings.TrimPrefix(strings.TrimSpace(fieldPath), "root.") + for _, candidate := range snapshot.Candidates { + actual := strings.TrimPrefix(strings.TrimSpace(candidate.FieldPath), "root.") + if candidate.NodeID == nodeID && actual == want { + return candidate, true + } + } + return capability.Candidate{}, false +} + +func semanticFixedLookup(column authoringv2.Column, alias, leaf, logicalType string) (recipe.DynamicColumn, error) { + empty := "" + fieldPath := strings.Trim(strings.TrimSpace(column.Source.FieldPath), ".") + sourcePath, keyPath := "", "" + var value recipe.Expression + switch column.Source.Kind { + case authoringv2.SourceIdentifierBySystem: + sourcePath, keyPath = firstNonEmpty(fieldPath, "identifier[]"), "item.system" + value = recipe.Expression{Select: "item.value"} + case authoringv2.SourceExtensionByURL: + sourcePath, keyPath = firstNonEmpty(fieldPath, "extension[]"), "item.url" + value = coalesceString("item.valueString", "item.valueCode", "item.valueInteger", "item.valueDecimal", "item.valueBoolean", "item.valueDate", "item.valueDateTime", "item.valueUri") + case authoringv2.SourceCodingBySystem: + sourcePath, keyPath = firstNonEmpty(fieldPath, "code.coding[]"), "item.system" + value = coalesceString("item.display", "item.code") + default: + return recipe.DynamicColumn{}, fmt.Errorf("unsupported source kind %q", column.Source.Kind) + } + key := recipe.Expression{Select: keyPath} + return recipe.DynamicColumn{Name: "fixed_" + shortHash(column.Column), ColumnPrefix: &empty, Source: recipe.Expression{Select: alias + "." + sourcePath}, Key: &key, Value: &value, Columns: []string{leaf}, MaxColumns: 1, ColumnTypes: map[string]string{leaf: logicalType}, ColumnSourceKeys: map[string]string{leaf: column.Source.Match}}, nil +} + +func semanticObservationPivot(column authoringv2.Column, alias, leaf string) (recipe.Pivot, error) { + separator := "__" + column.Source.Match + if !strings.HasSuffix(leaf, separator) || strings.TrimSuffix(leaf, separator) == "" { + return recipe.Pivot{}, fmt.Errorf("observation component column %q must end with %q", column.Column, separator) + } + name := strings.TrimSuffix(leaf, separator) + sourcePath := firstNonEmpty(strings.Trim(strings.TrimSpace(column.Source.FieldPath), "."), "component[]") + prefix := alias + "." + sourcePath + return recipe.Pivot{ + Name: name, + ColumnExpr: recipe.Expression{Select: prefix + ".code.coding[].code"}, + ValueExpr: recipe.Expression{Select: prefix + ".valueString"}, + ValueFallbacks: []recipe.Expression{{Select: prefix + ".valueCodeableConcept.text"}, {Select: prefix + ".valueQuantity.value"}, {Select: prefix + ".valueInteger"}}, + ItemSource: recipe.Expression{Select: alias + "." + sourcePath}, + ItemResourceType: "ObservationComponent", + Columns: []string{column.Source.Match}, + }, nil +} + +func appendSemanticPivot(pivots []recipe.Pivot, pivot recipe.Pivot) []recipe.Pivot { + for i := range pivots { + if pivots[i].Name == pivot.Name { + pivots[i].Columns = append(pivots[i].Columns, pivot.Columns...) + return pivots + } + } + return append(pivots, pivot) +} + +func coalesceString(paths ...string) recipe.Expression { + args := make([]recipe.Expression, 0, len(paths)) + for _, path := range paths { + args = append(args, recipe.Expression{Select: path}) + } + return recipe.Expression{Call: "coalesce_string", Args: args} +} diff --git a/internal/explorer/compilation/translate.go b/internal/explorer/compilation/translate.go index 2f0bce5b..8ae772a6 100644 --- a/internal/explorer/compilation/translate.go +++ b/internal/explorer/compilation/translate.go @@ -20,7 +20,7 @@ import ( "github.com/calypr/loom/internal/explorer/capability" ) -const TranslationVersion = "authoring-v2-native-1" +const TranslationVersion = "authoring-v2-native-3" // Error is a structured translation failure. Stage, Code, Path, and Details // are intentionally transport-neutral so an HTTP adapter can map it to its @@ -206,6 +206,9 @@ func Compile(ctx context.Context, project, explorerID string, document authoring if err := validateSnapshot(snapshot); err != nil { return Result{}, err } + if document.UsesSemanticColumns() { + return compileSemanticDocument(ctx, project, explorerID, document, snapshot) + } occurrences, routeEdges, err := resolveRoute(document, snapshot) if err != nil { return Result{}, err @@ -306,15 +309,11 @@ func Compile(ctx context.Context, project, explorerID string, document authoring } contract := OutputContract{OutputID: document.Output.ID} for _, c := range emitted { - contract.Columns = append(contract.Columns, OutputColumn{EmissionID: c.EmissionID, PublicColumn: c.PublicColumn, CandidateID: c.CandidateID, OccurrenceID: c.OccurrenceID, ProjectionMode: c.ProjectionMode, Label: presentation.Columns[len(contract.Columns)].Label, LogicalType: c.LogicalType, Filterable: c.Filterable, Chartable: c.Chartable}) + contract.Columns = append(contract.Columns, OutputColumn{Column: c.PublicColumn, Label: presentation.Columns[len(contract.Columns)].Label, LogicalType: c.LogicalType, Filterable: c.Filterable, Chartable: c.Chartable}) } return Result{Bundle: bundle, RecipeDigest: digest, EmittedColumns: emitted, IdentityMappings: mappings, Presentation: presentation, OutputContract: contract}, nil } -func Translate(project, explorerID string, document authoringv2.Document, snapshot capability.Snapshot) (Result, error) { - return Compile(context.Background(), project, explorerID, document, snapshot) -} - type occurrence struct { ID, NodeID, ResourceType string RowRootEligible bool diff --git a/internal/explorer/compilation/translate_test.go b/internal/explorer/compilation/translate_test.go index 341ede32..22f58c0b 100644 --- a/internal/explorer/compilation/translate_test.go +++ b/internal/explorer/compilation/translate_test.go @@ -7,6 +7,7 @@ import ( "strings" "testing" + "github.com/calypr/loom/internal/dataframe/recipe" "github.com/calypr/loom/internal/explorer/authoringv2" "github.com/calypr/loom/internal/explorer/capability" ) @@ -101,6 +102,79 @@ func TestCompileNativeV2DefaultsPresentationToCandidateLabel(t *testing.T) { } } +func TestCompileSemanticWorkspacePreservesAuthoredColumnsAndTypedSources(t *testing.T) { + visible, order := true, 0 + document := authoringv2.Document{ + Kind: authoringv2.Kind, + Output: authoringv2.Output{ID: "patient_output", Title: "Patients", RowLabel: "People"}, + RootResourceType: "Patient", + Route: authoringv2.RouteNode{OccurrenceID: "base", ResourceType: "Patient", Children: []authoringv2.RouteNode{{OccurrenceID: "encounter", ResourceType: "Encounter", Relationship: "encounters"}}}, + Columns: []authoringv2.Column{ + {Column: "patient_id", Label: "Patient ID", LogicalType: "string", OccurrenceID: "base", Source: authoringv2.ColumnSource{Kind: authoringv2.SourceField, FieldPath: "id", ProjectionMode: "VALUE"}, Table: &authoringv2.TablePresentation{Visible: &visible, Order: &order}}, + {Column: "encounter__code", Label: "Encounter code", LogicalType: "string", OccurrenceID: "encounter", Source: authoringv2.ColumnSource{Kind: authoringv2.SourceField, FieldPath: "code.coding[].code", ProjectionMode: "FIRST"}}, + {Column: "project_id", Label: "Project", LogicalType: "string", OccurrenceID: "base", Source: authoringv2.ColumnSource{Kind: authoringv2.SourceProjectID}}, + }, + } + result, err := Compile(context.Background(), "project-a", "explorer-a", document, fixtureSnapshot()) + if err != nil { + t.Fatal(err) + } + want := []string{"patient_id", "encounter__code", "project_id"} + for index, column := range result.OutputContract.Columns { + if column.Column != want[index] || result.EmittedColumns[index].PublicColumn != want[index] { + t.Fatalf("column %d = %#v emission=%#v", index, column, result.EmittedColumns[index]) + } + } + if got := result.Bundle.Outputs[0].Traversals[0].Alias; got != "encounter" { + t.Fatalf("traversal alias = %q", got) + } + if got := string(result.Bundle.Outputs[0].Fields[1].Expr.Literal); got != `"project-a"` { + t.Fatalf("project binding = %s", got) + } +} + +func TestCompileSemanticWorkspacePreservesSiblingBranchesDeterministically(t *testing.T) { + visible := true + document := authoringv2.Document{ + Kind: authoringv2.Kind, + Output: authoringv2.Output{ID: "patient_output", Title: "Patients"}, + RootResourceType: "Patient", + Route: authoringv2.RouteNode{ + OccurrenceID: "base", ResourceType: "Patient", + Children: []authoringv2.RouteNode{ + {OccurrenceID: "encounter_b", ResourceType: "Encounter", Relationship: "encounters"}, + {OccurrenceID: "encounter_a", ResourceType: "Encounter", Relationship: "encounters"}, + }, + }, + Columns: []authoringv2.Column{ + {Column: "patient_id", Label: "Patient ID", OccurrenceID: "base", Source: authoringv2.ColumnSource{Kind: authoringv2.SourceField, FieldPath: "id", ProjectionMode: "VALUE"}, Table: &authoringv2.TablePresentation{Visible: &visible}}, + {Column: "encounter_a__code", Label: "Encounter A", OccurrenceID: "encounter_a", Source: authoringv2.ColumnSource{Kind: authoringv2.SourceField, FieldPath: "code.coding[].code", ProjectionMode: "FIRST"}, Table: &authoringv2.TablePresentation{Visible: &visible}}, + {Column: "encounter_b__code", Label: "Encounter B", OccurrenceID: "encounter_b", Source: authoringv2.ColumnSource{Kind: authoringv2.SourceField, FieldPath: "code.coding[].code", ProjectionMode: "FIRST"}, Table: &authoringv2.TablePresentation{Visible: &visible}}, + }, + } + + first, err := Compile(context.Background(), "project-a", "explorer-a", document, fixtureSnapshot()) + if err != nil { + t.Fatal(err) + } + traversals := first.Bundle.Outputs[0].Traversals + if len(traversals) != 2 || traversals[0].Alias != "encounter_a" || traversals[1].Alias != "encounter_b" { + t.Fatalf("sibling traversals = %#v", traversals) + } + if traversals[0].Fields[0].Name != "code" || traversals[1].Fields[0].Name != "code" { + t.Fatalf("sibling fields = %#v", traversals) + } + + document.Route.Children[0], document.Route.Children[1] = document.Route.Children[1], document.Route.Children[0] + second, err := Compile(context.Background(), "project-a", "explorer-a", document, fixtureSnapshot()) + if err != nil { + t.Fatal(err) + } + if first.RecipeDigest != second.RecipeDigest { + t.Fatalf("sibling order changed recipe identity: %q != %q", first.RecipeDigest, second.RecipeDigest) + } +} + func TestCompileAllowsRepeatedSelfLoopAndLongFiniteRoutes(t *testing.T) { snapshot := fixtureSnapshot() document := fixtureDocument() @@ -127,3 +201,36 @@ func TestCompileRejectsMismatchesWithStructuredErrors(t *testing.T) { t.Fatalf("projection error=%#v", err) } } + +func TestSemanticObservationPivotFreezesOnlyAuthoredComponentColumns(t *testing.T) { + column := authoringv2.Column{ + Column: "observation__observation_component_values__GENE_SYMBOL", + OccurrenceID: "observation", + Source: authoringv2.ColumnSource{ + Kind: authoringv2.SourceObservationComponentByCode, + FieldPath: "component[]", + Match: "GENE_SYMBOL", + }, + } + pivot, err := semanticObservationPivot(column, "observation", "observation_component_values__GENE_SYMBOL") + if err != nil { + t.Fatal(err) + } + if pivot.Name != "observation_component_values" || len(pivot.Columns) != 1 || pivot.Columns[0] != "GENE_SYMBOL" || pivot.ItemResourceType != "ObservationComponent" { + t.Fatalf("pivot = %#v", pivot) + } + merged := appendSemanticPivot([]recipe.Pivot{pivot}, recipe.Pivot{Name: pivot.Name, Columns: []string{"TIMEPOINT_LABEL"}}) + if len(merged) != 1 || len(merged[0].Columns) != 2 { + t.Fatalf("merged pivots = %#v", merged) + } +} + +func TestSemanticNestedOccurrenceUsesLocalAliasAndFullPhysicalPrefix(t *testing.T) { + if got := semanticAlias("patient__condition"); got != "condition" { + t.Fatalf("nested alias = %q", got) + } + leaf, err := semanticColumnLeaf("patient__condition__code_coding_code", "patient__condition") + if err != nil || leaf != "code_coding_code" { + t.Fatalf("nested physical leaf = %q, %v", leaf, err) + } +} diff --git a/internal/explorer/compilation/workspace_test.go b/internal/explorer/compilation/workspace_test.go index 8cbc2169..60a3fc2f 100644 --- a/internal/explorer/compilation/workspace_test.go +++ b/internal/explorer/compilation/workspace_test.go @@ -27,7 +27,7 @@ func TestCompileWorkspaceProducesOneArtifactWithFiveOutputs(t *testing.T) { t.Fatalf("emission[%d]=%#v", i, emission) } contract := result.OutputContracts[i] - if contract.OutputID != emission.OutputID || len(contract.Columns) != 1 || contract.Columns[0].ProjectionMode != emission.ProjectionMode || contract.Columns[0].Label == "" { + if contract.OutputID != emission.OutputID || len(contract.Columns) != 1 || contract.Columns[0].Column != emission.PublicColumn || contract.Columns[0].Label == "" { t.Fatalf("contract[%d]=%#v emission=%#v", i, contract, emission) } } diff --git a/internal/explorer/compilation_receipt.go b/internal/explorer/compilation_receipt.go index dc7716d3..39d09326 100644 --- a/internal/explorer/compilation_receipt.go +++ b/internal/explorer/compilation_receipt.go @@ -23,7 +23,7 @@ const ( CompilationReceiptFormatVersion = 2 // CompilationReceiptCompilerContractVersion changes when compilation // semantics change in a way that can alter a resolved receipt. - CompilationReceiptCompilerContractVersion = "loom.explorer.compiler/v4" + CompilationReceiptCompilerContractVersion = "loom.explorer.compiler/v6" // Short aliases make the current contract convenient for repositories and // callers that do not need to distinguish the receipt prefix. @@ -304,22 +304,3 @@ func (r CompilationReceipt) ValidateID() error { } return nil } - -// ValidateID is also available as a package helper for repository code that -// prefers functional validation. -func ValidateID(r CompilationReceipt) error { return r.ValidateID() } - -// CloneCompilationReceipt returns a deep copy suitable for memory stores and -// tests. JSON round-tripping also clones nested recipe slices and maps while -// retaining the persisted wire shape. -func CloneCompilationReceipt(in CompilationReceipt) (CompilationReceipt, error) { - raw, err := json.Marshal(in) - if err != nil { - return CompilationReceipt{}, err - } - var out CompilationReceipt - if err := json.Unmarshal(raw, &out); err != nil { - return CompilationReceipt{}, err - } - return out, nil -} diff --git a/internal/explorer/compilation_receipt_test.go b/internal/explorer/compilation_receipt_test.go index bf2de860..6ba24464 100644 --- a/internal/explorer/compilation_receipt_test.go +++ b/internal/explorer/compilation_receipt_test.go @@ -84,7 +84,7 @@ func TestCompilationReceiptValidateRejectsArtifactlessLegacyReceipt(t *testing.T } } -func TestCompilationReceiptValidateIDAndDeepClone(t *testing.T) { +func TestCompilationReceiptValidateID(t *testing.T) { r := testReceipt() var err error r.ID, err = ReceiptID(r) @@ -94,17 +94,8 @@ func TestCompilationReceiptValidateIDAndDeepClone(t *testing.T) { if err := r.Validate(); err != nil { t.Fatal(err) } - clone, err := CloneCompilationReceipt(r) - if err != nil { - t.Fatal(err) - } - clone.OutputFingerprints = map[string]string{"out": "fingerprint"} - clone.Warnings[0].Details = map[string]any{"source": "test"} - if r.OutputFingerprints != nil || r.Warnings[0].Details != nil { - t.Fatal("clone mutation changed original receipt") - } - clone.ID = "receipt_wrong" - if err := clone.ValidateID(); err == nil { + r.ID = "receipt_wrong" + if err := r.ValidateID(); err == nil { t.Fatal("accepted mismatched receipt ID") } } diff --git a/internal/explorer/config_v2.go b/internal/explorer/config_v2.go index 7c8a8b80..90e8f425 100644 --- a/internal/explorer/config_v2.go +++ b/internal/explorer/config_v2.go @@ -14,18 +14,10 @@ import ( "github.com/calypr/loom/internal/projectid" ) -// ConfigV2 is the portable Explorer artifact. Both repository and interactive -// packets may carry the complete human-facing presentation layer. A repository -// packet may also be baseline-only, in which case the presentation fields are -// omitted and the frontend derives a layout from live dataset metadata. It -// contains no catalog, selector, join, or other Builder implementation ID. const ConfigV2APIVersion = "loom.calypr.org/explorer-config/v2" var idPattern = regexp.MustCompile(`^[a-z][a-z0-9-]{0,63}$`) -// ConfigManagementForID returns the management value required inside a V2 -// packet for the durable Explorer identity. The repository default keeps its -// repository identity even though Builder users may edit and publish it. func ConfigManagementForID(explorerID string) string { if explorerID == "default" { return "repository" @@ -50,6 +42,7 @@ type ConfigExplorer struct { Description string `json:"description,omitempty"` Management string `json:"management"` } + type ConfigView struct { ID string `json:"id"` Title string `json:"title"` @@ -61,14 +54,16 @@ type ConfigView struct { FixedFilters map[string][]string `json:"fixedFilters,omitempty"` Actions []ConfigAction `json:"actions,omitempty"` } + type ConfigTable struct { Columns []ConfigColumn `json:"columns"` } type ConfigColumn struct { - Column string `json:"column"` - Label string `json:"label,omitempty"` - Visible bool `json:"visible"` - Pinned bool `json:"pinned,omitempty"` + Column string `json:"column"` + Label string `json:"label,omitempty"` + Visible bool `json:"visible"` + Pinned bool `json:"pinned,omitempty"` + CellRenderer string `json:"cellRenderer,omitempty"` } type ConfigFilter struct { Column string `json:"column"` @@ -80,11 +75,12 @@ type ConfigChart struct { Title string `json:"title,omitempty"` } type ConfigAction struct { - Type string `json:"type"` - Title string `json:"title"` - FileName string `json:"fileName,omitempty"` - Output string `json:"output,omitempty"` - Columns []string `json:"columns,omitempty"` + Type string `json:"type"` + Title string `json:"title"` + FileName string `json:"fileName,omitempty"` + Output string `json:"output,omitempty"` + Columns []string `json:"columns,omitempty"` + ExportHeaders map[string]string `json:"exportHeaders,omitempty"` } type SharedFilter struct { Output string `json:"output"` @@ -95,187 +91,18 @@ type FileActions struct { Actions map[string]string `json:"actions,omitempty"` } -// PresentationRepairError reports a presentation reference that cannot be -// repaired without making a view unusable. Ordinary stale references are -// removed by RepairConfigV2Presentation and returned as WARN diagnostics. -type PresentationRepairError struct { - Diagnostic Diagnostic -} - -func (e *PresentationRepairError) Error() string { - if e == nil { - return "invalid Explorer presentation" - } - return e.Diagnostic.Message -} - -// RepairConfigV2Presentation removes presentation references that are absent -// from the authoritative emitted output schema. The schema is deliberately -// supplied by the caller because recipe parsing alone cannot know dynamic or -// snapshot-dependent output columns. -func RepairConfigV2Presentation(cfg ConfigV2, available map[string]map[string]bool) (ConfigV2, []Diagnostic, error) { - if len(available) == 0 { - return cfg, nil, nil - } - diagnostics := make([]Diagnostic, 0) - stale := func(path, output, column, reference string) { - diagnostics = append(diagnostics, Diagnostic{ - Severity: "WARN", - Stage: "presentation", - Code: "STALE_PRESENTATION_REFERENCE", - FieldPath: path, - Message: fmt.Sprintf("removed stale %s presentation reference to output column %q", reference, column), - Details: map[string]any{ - "outputId": output, - "column": column, - "referenceKind": reference, - }, - }) - } - hasColumn := func(output, column string) bool { - columns, ok := available[output] - return ok && columns[column] - } - allColumns := func(column string) bool { - for _, columns := range available { - if columns[column] { - return true - } - } - return false - } - - for viewIndex := range cfg.Views { - view := &cfg.Views[viewIndex] - if _, ok := available[view.Output]; !ok { - return cfg, diagnostics, &PresentationRepairError{Diagnostic: Diagnostic{ - Severity: "ERROR", - Stage: "presentation", - Code: "STALE_PRESENTATION_OUTPUT", - FieldPath: fmt.Sprintf("$.views[%d].output", viewIndex), - Message: fmt.Sprintf("view %q references an output absent from the compiled schema", view.ID), - Details: map[string]any{"viewId": view.ID, "outputId": view.Output}, - }} - } - columns := view.Table.Columns[:0] - for columnIndex, column := range view.Table.Columns { - if hasColumn(view.Output, column.Column) { - columns = append(columns, column) - continue - } - stale(fmt.Sprintf("$.views[%d].table.columns[%d].column", viewIndex, columnIndex), view.Output, column.Column, "table") - } - view.Table.Columns = columns - if len(view.Table.Columns) == 0 { - return cfg, diagnostics, &PresentationRepairError{Diagnostic: Diagnostic{ - Severity: "ERROR", - Stage: "presentation", - Code: "STALE_PRESENTATION_EMPTY_VIEW", - FieldPath: fmt.Sprintf("$.views[%d].table.columns", viewIndex), - Message: fmt.Sprintf("view %q has no table columns after stale presentation repair", view.ID), - Details: map[string]any{"viewId": view.ID, "outputId": view.Output}, - }} - } - if view.RowLabel != "" && !hasColumn(view.Output, view.RowLabel) { - stale(fmt.Sprintf("$.views[%d].rowLabel", viewIndex), view.Output, view.RowLabel, "rowLabel") - view.RowLabel = "" - } - filters := view.Filters[:0] - for filterIndex, filter := range view.Filters { - if hasColumn(view.Output, filter.Column) { - filters = append(filters, filter) - continue - } - stale(fmt.Sprintf("$.views[%d].filters[%d].column", viewIndex, filterIndex), view.Output, filter.Column, "filter") - } - view.Filters = filters - charts := view.Charts[:0] - for chartIndex, chart := range view.Charts { - if hasColumn(view.Output, chart.Column) { - charts = append(charts, chart) - continue - } - stale(fmt.Sprintf("$.views[%d].charts[%d].column", viewIndex, chartIndex), view.Output, chart.Column, "chart") - } - view.Charts = charts - for column := range view.FixedFilters { - if hasColumn(view.Output, column) { - continue - } - stale(fmt.Sprintf("$.views[%d].fixedFilters.%s", viewIndex, column), view.Output, column, "fixedFilter") - delete(view.FixedFilters, column) - } - for actionIndex := range view.Actions { - action := &view.Actions[actionIndex] - kept := action.Columns[:0] - for columnIndex, column := range action.Columns { - if hasColumn(view.Output, column) { - kept = append(kept, column) - continue - } - stale(fmt.Sprintf("$.views[%d].actions[%d].columns[%d]", viewIndex, actionIndex, columnIndex), view.Output, column, "action") - } - action.Columns = kept - } - } - - for output, filters := range cfg.SharedFilters { - kept := filters[:0] - for index, filter := range filters { - if hasColumn(filter.Output, filter.Column) { - kept = append(kept, filter) - continue - } - stale(fmt.Sprintf("$.sharedFilters.%s[%d].column", output, index), filter.Output, filter.Column, "sharedFilter") - } - if len(kept) == 0 { - delete(cfg.SharedFilters, output) - } else { - cfg.SharedFilters[output] = kept - } - } - for extension, columns := range cfg.FileActions.Extensions { - kept := columns[:0] - for index, column := range columns { - if allColumns(column) { - kept = append(kept, column) - continue - } - stale(fmt.Sprintf("$.fileActions.extensions.%s[%d]", extension, index), "", column, "fileAction") - } - if len(kept) == 0 { - delete(cfg.FileActions.Extensions, extension) - } else { - cfg.FileActions.Extensions[extension] = kept - } - } - return cfg, diagnostics, nil -} - -// DecodeConfigV2 rejects the legacy explorerConfig/tabs envelope and every -// unknown field. The recipe gets its own strict decoder and validator. func DecodeConfigV2(raw []byte, project string) (ConfigV2, recipe.Bundle, error) { return DecodeDefaultConfigV2(raw, project) } -// DecodeDefaultConfigV2 validates the repository contract. Repository packets -// may be baseline-only or may include a complete presentation layer authored -// by ETL. In the latter case the packet is preserved losslessly and exposed as -// the default's activeConfig after publication. func DecodeDefaultConfigV2(raw []byte, project string) (ConfigV2, recipe.Bundle, error) { return decodeConfigV2(raw, project, "default", "repository") } -// DecodeInteractiveConfigV2 validates a complete interactive V2 document. It -// shares the exact recipe/presentation validator used by repository deployment -// while keeping ownership mode explicit. func DecodeInteractiveConfigV2(raw []byte, project, explorerID string) (ConfigV2, recipe.Bundle, error) { return decodeConfigV2(raw, project, explorerID, "interactive") } -// CanonicalConfigV2 validates raw and returns deterministic JSON plus its -// content digest. Generic JSON canonicalization preserves every V2 field, -// including presentation data that is not represented in recipe.Bundle. func CanonicalConfigV2(raw []byte, project, explorerID, management string) (ConfigV2, recipe.Bundle, []byte, string, error) { var cfg ConfigV2 var bundle recipe.Bundle diff --git a/internal/explorer/config_v2_test.go b/internal/explorer/config_v2_test.go index 23145f2e..c84f5460 100644 --- a/internal/explorer/config_v2_test.go +++ b/internal/explorer/config_v2_test.go @@ -46,41 +46,3 @@ func TestDecodeConfigV2RejectsLegacyAndUnknownFields(t *testing.T) { } } } - -func TestRepairConfigV2PresentationRemovesStaleReferences(t *testing.T) { - cfg := ConfigV2{ - APIVersion: ConfigV2APIVersion, - Kind: "ExplorerConfig", - Project: "project-a", - Explorer: ConfigExplorer{ID: "custom", Title: "Custom", Management: "interactive"}, - Views: []ConfigView{{ - ID: "patient", Title: "Patients", Output: "Patient", RowLabel: "stale", - Table: ConfigTable{Columns: []ConfigColumn{{Column: "id"}, {Column: "stale"}}}, - Filters: []ConfigFilter{{Column: "id"}, {Column: "stale"}}, - Charts: []ConfigChart{{Column: "id"}, {Column: "stale"}}, - FixedFilters: map[string][]string{"id": {"x"}, "stale": {"x"}}, - Actions: []ConfigAction{{Type: "download", Title: "Download", Columns: []string{"id", "stale"}}}, - }}, - SharedFilters: map[string][]SharedFilter{"patient": {{Output: "Patient", Column: "id"}, {Output: "Patient", Column: "stale"}}}, - FileActions: FileActions{Extensions: map[string][]string{"csv": {"id", "stale"}}}, - } - repaired, diagnostics, err := RepairConfigV2Presentation(cfg, map[string]map[string]bool{"Patient": {"id": true}}) - if err != nil { - t.Fatal(err) - } - view := repaired.Views[0] - if len(view.Table.Columns) != 1 || len(view.Filters) != 1 || len(view.Charts) != 1 || view.RowLabel != "" { - t.Fatalf("stale view references were not repaired: %#v", view) - } - if _, ok := view.FixedFilters["stale"]; ok || len(view.Actions[0].Columns) != 1 || len(repaired.SharedFilters["patient"]) != 1 || len(repaired.FileActions.Extensions["csv"]) != 1 { - t.Fatalf("stale secondary references were not repaired: %#v %#v %#v", view, repaired.SharedFilters, repaired.FileActions) - } - if len(diagnostics) != 8 { - t.Fatalf("diagnostics = %d, want 8: %#v", len(diagnostics), diagnostics) - } - for _, diagnostic := range diagnostics { - if diagnostic.Code != "STALE_PRESENTATION_REFERENCE" || diagnostic.Severity != "WARN" { - t.Fatalf("unexpected diagnostic: %#v", diagnostic) - } - } -} diff --git a/internal/explorer/memory_store.go b/internal/explorer/memory_store.go deleted file mode 100644 index 41f87b44..00000000 --- a/internal/explorer/memory_store.go +++ /dev/null @@ -1,499 +0,0 @@ -package explorer - -import ( - "context" - "encoding/json" - "reflect" - "sort" - "sync" - "time" -) - -// MemoryStore is used by service tests and local wiring; durable deployments -// use the Arango implementation. -type MemoryStore struct { - mu sync.Mutex - explorers map[string]Explorer - revisions map[string]Revision - receipts map[string]CompilationReceipt - configs map[string]RepositoryConfig - repositoryConfigs map[string]RepositoryConfig -} - -func NewMemoryStore() *MemoryStore { - return &MemoryStore{explorers: map[string]Explorer{}, revisions: map[string]Revision{}, receipts: map[string]CompilationReceipt{}, configs: map[string]RepositoryConfig{}, repositoryConfigs: map[string]RepositoryConfig{}} -} -func configKey(project, id string) string { return project + "\x00" + id } -func (s *MemoryStore) ListConfigs(_ context.Context, project string) ([]RepositoryConfig, error) { - s.mu.Lock() - defer s.mu.Unlock() - out := []RepositoryConfig{} - for _, value := range s.configs { - if value.Project == project { - out = append(out, value) - } - } - if value, ok := s.repositoryConfigs[project]; ok { - out = append(out, value) - } - sort.Slice(out, func(i, j int) bool { return out[i].ExplorerID < out[j].ExplorerID }) - return out, nil -} -func (s *MemoryStore) GetConfig(_ context.Context, project, id string) (*RepositoryConfig, error) { - s.mu.Lock() - defer s.mu.Unlock() - v, ok := s.configs[configKey(project, id)] - if !ok { - return nil, ErrNotFound - } - return &v, nil -} -func (s *MemoryStore) SaveConfig(_ context.Context, value RepositoryConfig) (*RepositoryConfig, error) { - s.mu.Lock() - defer s.mu.Unlock() - value.UpdatedAt = time.Now().UTC() - value.Config = append([]byte(nil), value.Config...) - s.configs[configKey(value.Project, value.ExplorerID)] = value - return &value, nil -} -func (s *MemoryStore) GetRepositoryConfig(ctx context.Context, project string) (*RepositoryConfig, error) { - s.mu.Lock() - defer s.mu.Unlock() - v, ok := s.repositoryConfigs[project] - if !ok { - return nil, ErrNotFound - } - return &v, nil -} -func (s *MemoryStore) SaveRepositoryConfig(ctx context.Context, value RepositoryConfig) (*RepositoryConfig, error) { - s.mu.Lock() - defer s.mu.Unlock() - value.ExplorerID, value.Management = "default", ManagementRepository - value.UpdatedAt = time.Now().UTC() - value.Config = append([]byte(nil), value.Config...) - s.repositoryConfigs[value.Project] = value - return &value, nil -} -func explorerKey(project, id string) string { return project + "\x00" + id } -func (s *MemoryStore) List(_ context.Context, project string) ([]Explorer, error) { - s.mu.Lock() - defer s.mu.Unlock() - out := []Explorer{} - for _, e := range s.explorers { - if e.Project == project { - out = append(out, e) - } - } - sort.Slice(out, func(i, j int) bool { return out[i].ExplorerID < out[j].ExplorerID }) - return out, nil -} -func (s *MemoryStore) Get(_ context.Context, p, id string) (*Explorer, error) { - s.mu.Lock() - defer s.mu.Unlock() - e, ok := s.explorers[explorerKey(p, id)] - if !ok { - return nil, ErrNotFound - } - return &e, nil -} -func (s *MemoryStore) CreateInteractive(_ context.Context, e Explorer) (*Explorer, error) { - s.mu.Lock() - defer s.mu.Unlock() - k := explorerKey(e.Project, e.ExplorerID) - if _, ok := s.explorers[k]; ok { - return nil, ErrDraftConflict - } - s.explorers[k] = e - return &e, nil -} -func (s *MemoryStore) CreateRepository(ctx context.Context, e Explorer) (*Explorer, error) { - return s.CreateInteractive(ctx, e) -} -func (s *MemoryStore) SaveDraft(_ context.Context, e Explorer, expected int64, expectedDigest ...string) (*Explorer, error) { - s.mu.Lock() - defer s.mu.Unlock() - k := explorerKey(e.Project, e.ExplorerID) - old, ok := s.explorers[k] - if !ok { - return nil, ErrNotFound - } - e.DraftVersion = old.DraftVersion + 1 - e.UpdatedAt = time.Now().UTC() - e.DraftConfig = append([]byte(nil), e.DraftConfig...) - e.ActiveConfig = append([]byte(nil), e.ActiveConfig...) - s.explorers[k] = e - return &e, nil -} -func (s *MemoryStore) InsertCompilationReceipt(_ context.Context, receipt CompilationReceipt) (*CompilationReceipt, error) { - s.mu.Lock() - defer s.mu.Unlock() - if err := validateCompilationReceipt(receipt); err != nil { - return nil, err - } - if prior, ok := s.receipts[receipt.ID]; ok { - if !sameCompilationReceipt(prior, receipt) { - return nil, ErrCorruptReceipt - } - copy := cloneReceipt(prior) - return ©, nil - } - s.receipts[receipt.ID] = cloneReceipt(receipt) - copy := cloneReceipt(receipt) - return ©, nil -} -func (s *MemoryStore) GetCompilationReceipt(_ context.Context, id string) (*CompilationReceipt, error) { - s.mu.Lock() - defer s.mu.Unlock() - receipt, ok := s.receipts[id] - if !ok { - return nil, ErrNotFound - } - if err := validateCompilationReceipt(receipt); err != nil { - return nil, err - } - copy := cloneReceipt(receipt) - return ©, nil -} - -func (s *MemoryStore) GetCompilationReceiptForExplorer(_ context.Context, project, explorerID, id string) (*CompilationReceipt, error) { - s.mu.Lock() - defer s.mu.Unlock() - receipt, ok := s.receipts[id] - if !ok || receipt.Project != project || receipt.ExplorerID != explorerID { - return nil, ErrNotFound - } - if err := validateCompilationReceipt(receipt); err != nil { - return nil, err - } - copy := cloneReceipt(receipt) - return ©, nil -} - -func (s *MemoryStore) GetCompilationReceiptByCompilationKey(_ context.Context, project, explorerID, compilationKey string) (*CompilationReceipt, error) { - s.mu.Lock() - defer s.mu.Unlock() - var found *CompilationReceipt - for _, receipt := range s.receipts { - if receipt.Project != project || receipt.ExplorerID != explorerID || receiptCompilationKey(receipt) != compilationKey { - continue - } - if err := validateCompilationReceipt(receipt); err != nil { - return nil, err - } - candidate := cloneReceipt(receipt) - if found == nil || candidate.ID < found.ID { - found = &candidate - } - } - if found == nil { - return nil, ErrNotFound - } - return found, nil -} - -func (s *MemoryStore) CompilationReceiptStats(_ context.Context, project string) (ReceiptStoreStats, error) { - s.mu.Lock() - defer s.mu.Unlock() - stats := ReceiptStoreStats{} - referenced := map[string]bool{} - for _, revision := range s.revisions { - if revision.CompilationReceiptID != "" { - referenced[revision.CompilationReceiptID] = true - } - } - for id, receipt := range s.receipts { - if project != "" && receipt.Project != project { - continue - } - if err := validateCompilationReceipt(receipt); err != nil { - return ReceiptStoreStats{}, err - } - stats.Count++ - if raw, err := json.Marshal(receipt); err == nil { - stats.ApproxBytes += int64(len(raw)) - } - if stats.OldestCreatedAt.IsZero() || (!receipt.CreatedAt.IsZero() && receipt.CreatedAt.Before(stats.OldestCreatedAt)) { - stats.OldestCreatedAt = receipt.CreatedAt - } - if !referenced[id] { - stats.UnreferencedCount++ - } - } - return stats, nil -} - -func (s *MemoryStore) PublishAuthoring(_ context.Context, receipt CompilationReceipt, revision Revision) (*Revision, error) { - s.mu.Lock() - defer s.mu.Unlock() - key := explorerKey(revision.Project, revision.ExplorerID) - owner, ok := s.explorers[key] - if !ok { - return nil, ErrNotFound - } - if existing, ok := s.revisions[revision.ID]; ok && owner.ActiveRevisionID == revision.ID { - copy := existing - return ©, nil - } - if receipt.ID == "" || revision.CompilationReceiptID != receipt.ID { - return nil, ErrImmutableRevision - } - if err := validateCompilationReceipt(receipt); err != nil { - return nil, err - } - if prior, ok := s.receipts[receipt.ID]; ok && !sameCompilationReceipt(prior, receipt) { - return nil, ErrCorruptReceipt - } - now := time.Now().UTC() - if owner.ActiveRevisionID != "" { - prior := s.revisions[owner.ActiveRevisionID] - prior.Status = RevisionSuperseded - s.revisions[prior.ID] = prior - } - revision.Status = RevisionActive - revision.ActivatedAt = &now - revision.Publication.State = string(RevisionActive) - revision.Publication.RevisionID = revision.ID - revision.Publication.UpdatedAt = now - if _, ok := s.receipts[receipt.ID]; !ok { - s.receipts[receipt.ID] = cloneReceipt(receipt) - } - s.revisions[revision.ID] = revision - owner.ActiveRevisionID = revision.ID - owner.ActiveConfig = append([]byte(nil), revision.Config...) - owner.RecipeDigest = revision.RecipeDigest - owner.ResolvedSchemaDigest = revision.ResolvedSchemaDigest - owner.SourceGeneration = revision.SourceGeneration - owner.Materializations = append([]Materialization(nil), revision.Materializations...) - owner.EmittedColumns = append([]EmittedColumn(nil), revision.EmittedColumns...) - owner.Dataset = revision.Dataset - owner.Publication = revision.Publication - owner.Diagnostics = append([]Diagnostic(nil), revision.Diagnostics...) - owner.UpdatedAt = now - s.explorers[key] = owner - copy := revision - return ©, nil -} -func cloneReceipt(in CompilationReceipt) CompilationReceipt { - return cloneReflect(reflect.ValueOf(in)).Interface().(CompilationReceipt) -} - -var timeType = reflect.TypeOf(time.Time{}) - -// cloneReflect keeps the memory adapter honest as the immutable receipt grows: -// nested recipe slices/maps and raw JSON must never alias caller-owned state. -func cloneReflect(v reflect.Value) reflect.Value { - if !v.IsValid() { - return v - } - if v.Type() == timeType { - return v - } - switch v.Kind() { - case reflect.Interface: - if v.IsNil() { - return reflect.Zero(v.Type()) - } - out := reflect.New(v.Type()).Elem() - value := cloneReflect(v.Elem()) - out.Set(value) - return out - case reflect.Ptr: - if v.IsNil() { - return reflect.Zero(v.Type()) - } - out := reflect.New(v.Type().Elem()) - out.Elem().Set(cloneReflect(v.Elem())) - return out - case reflect.Slice: - if v.IsNil() { - return reflect.Zero(v.Type()) - } - out := reflect.MakeSlice(v.Type(), v.Len(), v.Len()) - for i := 0; i < v.Len(); i++ { - out.Index(i).Set(cloneReflect(v.Index(i))) - } - return out - case reflect.Array: - out := reflect.New(v.Type()).Elem() - for i := 0; i < v.Len(); i++ { - out.Index(i).Set(cloneReflect(v.Index(i))) - } - return out - case reflect.Map: - if v.IsNil() { - return reflect.Zero(v.Type()) - } - out := reflect.MakeMapWithSize(v.Type(), v.Len()) - iter := v.MapRange() - for iter.Next() { - out.SetMapIndex(cloneReflect(iter.Key()), cloneReflect(iter.Value())) - } - return out - case reflect.Struct: - out := reflect.New(v.Type()).Elem() - out.Set(v) - for i := 0; i < v.NumField(); i++ { - if out.Field(i).CanSet() && v.Field(i).CanInterface() { - out.Field(i).Set(cloneReflect(v.Field(i))) - } - } - return out - default: - return v - } -} - -func receiptCompilationKey(receipt CompilationReceipt) string { - value := reflect.ValueOf(receipt) - field := value.FieldByName("CompilationKey") - if field.IsValid() && field.Kind() == reflect.String && field.String() != "" { - return field.String() - } - // IntentDigest was the pre-receipt compilation key and is retained as a - // compatibility fallback while old documents are being migrated. - return receipt.IntentDigest -} - -func (s *MemoryStore) PurgeDraftAuthoring(_ context.Context) error { - s.mu.Lock() - defer s.mu.Unlock() - referenced := map[string]bool{} - for _, revision := range s.revisions { - if revision.CompilationReceiptID != "" { - referenced[revision.CompilationReceiptID] = true - } - } - for id := range s.receipts { - if !referenced[id] { - delete(s.receipts, id) - } - } - for key, value := range s.explorers { - value.DraftConfig = nil - value.DraftVersion = 0 - value.DraftDigest = "" - s.explorers[key] = value - } - return nil -} -func (s *MemoryStore) InsertRevision(_ context.Context, r Revision) (*Revision, error) { - s.mu.Lock() - defer s.mu.Unlock() - if old, ok := s.revisions[r.ID]; ok { - return &old, nil - } - s.revisions[r.ID] = r - return &r, nil -} -func (s *MemoryStore) GetRevision(_ context.Context, id string) (*Revision, error) { - s.mu.Lock() - defer s.mu.Unlock() - r, ok := s.revisions[id] - if !ok { - return nil, ErrNotFound - } - return &r, nil -} -func (s *MemoryStore) TransitionRevision(_ context.Context, id string, status RevisionStatus, diags []Diagnostic) (*Revision, error) { - s.mu.Lock() - defer s.mu.Unlock() - r, ok := s.revisions[id] - if !ok { - return nil, ErrNotFound - } - r.Status = status - r.Diagnostics = append([]Diagnostic(nil), diags...) - now := time.Now().UTC() - if status == RevisionReady { - r.ReadyAt = &now - } - if status == RevisionFailed { - r.FailedAt = &now - } - s.revisions[id] = r - return &r, nil -} -func (s *MemoryStore) ActivateInteractive(_ context.Context, p, id, revisionID string) error { - s.mu.Lock() - defer s.mu.Unlock() - k := explorerKey(p, id) - e, ok := s.explorers[k] - if !ok { - return ErrNotFound - } - r, ok := s.revisions[revisionID] - if !ok { - return ErrNotFound - } - if r.Status != RevisionReady && !(r.Status == RevisionActive && e.ActiveRevisionID == revisionID) { - return ErrImmutableRevision - } - if r.Status == RevisionActive && e.ActiveRevisionID == revisionID { - return nil - } - if e.ActiveRevisionID != "" { - prior := s.revisions[e.ActiveRevisionID] - prior.Status = RevisionSuperseded - s.revisions[prior.ID] = prior - } - now := time.Now().UTC() - r.Status = RevisionActive - r.ActivatedAt = &now - s.revisions[r.ID] = r - e.ActiveRevisionID = r.ID - e.ActiveConfig = append([]byte(nil), r.Config...) - e.RecipeDigest = r.RecipeDigest - e.ResolvedSchemaDigest = r.ResolvedSchemaDigest - e.SourceGeneration = r.SourceGeneration - e.Dataset = r.Dataset - e.Publication = r.Publication - e.Publication.State = string(RevisionActive) - e.Publication.RevisionID = r.ID - e.Publication.UpdatedAt = now - e.EmittedColumns = append([]EmittedColumn(nil), r.EmittedColumns...) - e.Materializations = append([]Materialization(nil), r.Materializations...) - e.Diagnostics = append([]Diagnostic(nil), r.Diagnostics...) - s.explorers[k] = e - return nil -} -func (s *MemoryStore) ActivateRepository(_ context.Context, project, revisionID string) error { - s.mu.Lock() - defer s.mu.Unlock() - e, ok := s.explorers[explorerKey(project, "default")] - if !ok { - return ErrNotFound - } - r, ok := s.revisions[revisionID] - if !ok { - return ErrNotFound - } - if e.ManagementMode != ManagementRepository || (r.Status != RevisionReady && !(r.Status == RevisionActive && e.ActiveRevisionID == revisionID)) { - return ErrImmutableRevision - } - if e.ActiveRevisionID != "" && e.ActiveRevisionID != revisionID { - prior := s.revisions[e.ActiveRevisionID] - prior.Status = RevisionSuperseded - s.revisions[prior.ID] = prior - } - now := time.Now().UTC() - r.Status = RevisionActive - r.ActivatedAt = &now - s.revisions[r.ID] = r - e.ActiveRevisionID = r.ID - e.ActiveConfig = append([]byte(nil), r.Config...) - e.RecipeDigest = r.RecipeDigest - e.ResolvedSchemaDigest = r.ResolvedSchemaDigest - e.SourceGeneration = r.SourceGeneration - e.Materializations, e.Dataset = WithDataframeSelectors(r.Recipe, r.Materializations, r.Dataset) - e.Publication = r.Publication - e.Publication.State = string(RevisionActive) - e.Publication.RevisionID = r.ID - e.Publication.UpdatedAt = now - e.EmittedColumns = append([]EmittedColumn(nil), r.EmittedColumns...) - e.Diagnostics = append([]Diagnostic(nil), r.Diagnostics...) - s.explorers[explorerKey(project, "default")] = e - return nil -} -func (s *MemoryStore) ActivateRepositoryGeneration(ctx context.Context, project, _ string, revisionID string) error { - return s.ActivateRepository(ctx, project, revisionID) -} diff --git a/internal/explorer/output_contract.go b/internal/explorer/output_contract.go index dd639a9c..b9d38184 100644 --- a/internal/explorer/output_contract.go +++ b/internal/explorer/output_contract.go @@ -25,15 +25,19 @@ type PublicOutputContract struct { } type PublicOutputColumn struct { - EmissionID string `json:"emissionId"` - PublicColumn string `json:"publicColumn"` - CandidateID string `json:"candidateId"` - OccurrenceID string `json:"occurrenceId"` - ProjectionMode string `json:"projectionMode"` - Label string `json:"label"` - LogicalType string `json:"logicalType"` - Filterable bool `json:"filterable"` - Chartable bool `json:"chartable"` + Column string `json:"column"` + Label string `json:"label"` + LogicalType string `json:"logicalType"` + Filterable bool `json:"filterable"` + Chartable bool `json:"chartable"` + + // Compiler identities remain available to internal legacy tests only. They + // are deliberately absent from the V2 public contract. + EmissionID string `json:"-"` + PublicColumn string `json:"-"` + CandidateID string `json:"-"` + OccurrenceID string `json:"-"` + ProjectionMode string `json:"-"` } // DecodePublicOutputContracts strictly decodes the current contract shape. @@ -97,9 +101,7 @@ func DecodePublicOutputContracts(raw json.RawMessage) (PublicOutputContracts, er for columnIndex, column := range contract.Columns { path := fmt.Sprintf("outputs[%d].columns[%d]", outputIndex, columnIndex) for _, field := range []struct{ name, value string }{ - {"emissionId", column.EmissionID}, {"publicColumn", column.PublicColumn}, - {"candidateId", column.CandidateID}, {"occurrenceId", column.OccurrenceID}, - {"projectionMode", column.ProjectionMode}, {"label", column.Label}, + {"column", column.Column}, {"label", column.Label}, {"logicalType", column.LogicalType}, } { if strings.TrimSpace(field.value) == "" { @@ -169,25 +171,20 @@ func (c PublicOutputContract) ValidateAgainst(bundle recipe.Bundle, emitted []Em if len(c.Columns) != len(emitted) { return invalidOutputContract("column count %d does not match emitted column count %d", len(c.Columns), len(emitted)) } - seenEmission := make(map[string]struct{}, len(emitted)) seenPublic := make(map[string]struct{}, len(emitted)) for i, column := range emitted { if strings.TrimSpace(column.OutputID) != c.OutputID { return invalidOutputContract("emittedColumns[%d] belongs to output %q, want %q", i, column.OutputID, c.OutputID) } - if strings.TrimSpace(column.EmissionID) == "" || strings.TrimSpace(column.PublicColumn) == "" { + if strings.TrimSpace(column.PublicColumn) == "" { return invalidOutputContract("emittedColumns[%d] has an empty identity", i) } - if _, exists := seenEmission[column.EmissionID]; exists { - return invalidOutputContract("duplicate emissionId %q", column.EmissionID) - } if _, exists := seenPublic[column.PublicColumn]; exists { return invalidOutputContract("duplicate publicColumn %q", column.PublicColumn) } - seenEmission[column.EmissionID] = struct{}{} seenPublic[column.PublicColumn] = struct{}{} actual := c.Columns[i] - if actual.EmissionID != column.EmissionID || actual.PublicColumn != column.PublicColumn || actual.CandidateID != column.CandidateID || actual.OccurrenceID != column.OccurrenceID || actual.ProjectionMode != column.ProjectionMode || actual.Label != column.Label || actual.LogicalType != column.LogicalType || actual.Filterable != column.Filterable || actual.Chartable != column.Chartable { + if actual.Column != column.PublicColumn || actual.Label != column.Label || actual.LogicalType != column.LogicalType || actual.Filterable != column.Filterable || actual.Chartable != column.Chartable { return invalidOutputContract("columns[%d] does not match emittedColumns[%d]", i, i) } } diff --git a/internal/explorer/output_contract_test.go b/internal/explorer/output_contract_test.go index fb8ab83a..8fa54072 100644 --- a/internal/explorer/output_contract_test.go +++ b/internal/explorer/output_contract_test.go @@ -17,11 +17,11 @@ func contractFixture() (recipe.Bundle, []EmittedColumn, PublicOutputContracts) { } contract := PublicOutputContracts{Outputs: []PublicOutputContract{ {OutputID: "patients", Columns: []PublicOutputColumn{ - {EmissionID: "em_id", PublicColumn: "c_id_base", CandidateID: "c_id", OccurrenceID: "base", ProjectionMode: "VALUE", Label: "Patient ID", LogicalType: "string", Filterable: true, Chartable: false}, - {EmissionID: "em_name", PublicColumn: "c_name_base", CandidateID: "c_name", OccurrenceID: "base", ProjectionMode: "FIRST", Label: "Patient name", LogicalType: "string", Filterable: false, Chartable: true}, + {Column: "c_id_base", Label: "Patient ID", LogicalType: "string", Filterable: true, Chartable: false}, + {Column: "c_name_base", Label: "Patient name", LogicalType: "string", Filterable: false, Chartable: true}, }}, {OutputID: "specimens", Columns: []PublicOutputColumn{ - {EmissionID: "em_specimen", PublicColumn: "c_specimen_base", CandidateID: "c_specimen", OccurrenceID: "base", ProjectionMode: "VALUE", Label: "Specimen ID", LogicalType: "string", Filterable: true, Chartable: true}, + {Column: "c_specimen_base", Label: "Specimen ID", LogicalType: "string", Filterable: true, Chartable: true}, }}, }} return bundle, emitted, contract @@ -64,8 +64,8 @@ func TestPublicOutputContractsMatchBundleAndOrderedEmissions(t *testing.T) { "column order": func(_ *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContracts) { c.Outputs[0].Columns[0], c.Outputs[0].Columns[1] = c.Outputs[0].Columns[1], c.Outputs[0].Columns[0] }, - "projection metadata": func(_ *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContracts) { - c.Outputs[0].Columns[0].ProjectionMode = "FIRST" + "physical column": func(_ *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContracts) { + c.Outputs[0].Columns[0].Column = "forged" }, "label metadata": func(_ *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContracts) { c.Outputs[0].Columns[0].Label = "forged" @@ -73,7 +73,6 @@ func TestPublicOutputContractsMatchBundleAndOrderedEmissions(t *testing.T) { "column count": func(_ *recipe.Bundle, _ []EmittedColumn, c *PublicOutputContracts) { c.Outputs[0].Columns = c.Outputs[0].Columns[:1] }, - "duplicate emission": func(_ *recipe.Bundle, e []EmittedColumn, _ *PublicOutputContracts) { e[1].EmissionID = e[0].EmissionID }, "duplicate public column": func(_ *recipe.Bundle, e []EmittedColumn, _ *PublicOutputContracts) { e[1].PublicColumn = e[0].PublicColumn }, @@ -95,7 +94,7 @@ func TestPublicOutputContractsMatchBundleAndOrderedEmissions(t *testing.T) { func TestCompilationReceiptValidateRejectsMismatchedPublicContract(t *testing.T) { r := testReceipt() - r.PublicOutputContract = json.RawMessage(`{"outputs":[{"outputId":"out","columns":[{"emissionId":"em_bad","publicColumn":"c_bad","candidateId":"c_bad","occurrenceId":"base","projectionMode":"VALUE","label":"Bad","logicalType":"string","filterable":false,"chartable":false}]}]}`) + r.PublicOutputContract = json.RawMessage(`{"outputs":[{"outputId":"out","columns":[{"column":"c_bad","label":"Bad","logicalType":"string","filterable":false,"chartable":false}]}]}`) r.OutputContractDigest, _ = CompilationArtifactDigest(r.PublicOutputContract) r.CompilationKey, _ = CompilationKey(r) r.ID = "" diff --git a/internal/explorer/receipt_store_test.go b/internal/explorer/receipt_store_test.go deleted file mode 100644 index f4dc3228..00000000 --- a/internal/explorer/receipt_store_test.go +++ /dev/null @@ -1,82 +0,0 @@ -package explorer - -import ( - "context" - "errors" - "testing" - "time" - - "github.com/calypr/loom/internal/dataframe/recipe" -) - -func TestMemoryReceiptStoreIsTenantScopedAndImmutable(t *testing.T) { - ctx := context.Background() - store := NewMemoryStore() - receipt := CompilationReceipt{ - ID: "receipt-one", Project: "project-a", ExplorerID: "explorer-a", IntentDigest: "compile-a", - CreatedAt: time.Date(2026, 1, 2, 0, 0, 0, 0, time.UTC), - Bundle: recipe.Bundle{Outputs: []recipe.Output{{Name: "output", Fields: []recipe.Field{{Name: "field"}}}}}, - } - if _, err := store.InsertCompilationReceipt(ctx, receipt); err != nil { - t.Fatal(err) - } - // Mutating both the input and the returned value must not mutate storage. - receipt.Bundle.Outputs[0].Fields[0].Name = "caller-mutated" - got, err := store.GetCompilationReceiptForExplorer(ctx, "project-a", "explorer-a", "receipt-one") - if err != nil { - t.Fatal(err) - } - got.Bundle.Outputs[0].Fields[0].Name = "reader-mutated" - gotAgain, err := store.GetCompilationReceiptForExplorer(ctx, "project-a", "explorer-a", "receipt-one") - if err != nil { - t.Fatal(err) - } - if gotAgain.Bundle.Outputs[0].Fields[0].Name != "field" { - t.Fatalf("receipt nested recipe aliased storage: %q", gotAgain.Bundle.Outputs[0].Fields[0].Name) - } - if _, err := store.GetCompilationReceiptForExplorer(ctx, "project-b", "explorer-a", "receipt-one"); !errors.Is(err, ErrNotFound) { - t.Fatalf("cross-tenant lookup error=%v", err) - } -} - -func TestMemoryReceiptStoreDetectsImmutableCollisionAndFindsKey(t *testing.T) { - ctx := context.Background() - store := NewMemoryStore() - base := CompilationReceipt{ID: "receipt-same", Project: "p", ExplorerID: "e", IntentDigest: "key-a"} - if _, err := store.InsertCompilationReceipt(ctx, base); err != nil { - t.Fatal(err) - } - changed := base - changed.IntentDigest = "key-b" - if _, err := store.InsertCompilationReceipt(ctx, changed); !errors.Is(err, ErrCorruptReceipt) { - t.Fatalf("collision error=%v", err) - } - found, err := store.GetCompilationReceiptByCompilationKey(ctx, "p", "e", "key-a") - if err != nil || found.ID != base.ID { - t.Fatalf("key lookup=%#v, err=%v", found, err) - } -} - -func TestMemoryReceiptStoreStats(t *testing.T) { - ctx := context.Background() - store := NewMemoryStore() - old := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC) - for _, r := range []CompilationReceipt{ - {ID: "receipt-kept", Project: "p", ExplorerID: "e", IntentDigest: "a", CreatedAt: old}, - {ID: "receipt-orphan", Project: "p", ExplorerID: "e", IntentDigest: "b", CreatedAt: old.Add(time.Hour)}, - } { - if _, err := store.InsertCompilationReceipt(ctx, r); err != nil { - t.Fatal(err) - } - } - if _, err := store.InsertRevision(ctx, Revision{ID: "revision", Project: "p", ExplorerID: "e", CompilationReceiptID: "receipt-kept"}); err != nil { - t.Fatal(err) - } - stats, err := store.CompilationReceiptStats(ctx, "p") - if err != nil { - t.Fatal(err) - } - if stats.Count != 2 || stats.UnreferencedCount != 1 || stats.ApproxBytes <= 0 || !stats.OldestCreatedAt.Equal(old) { - t.Fatalf("stats=%+v", stats) - } -} diff --git a/internal/explorer/repository_revision_id_test.go b/internal/explorer/repository_revision_id_test.go new file mode 100644 index 00000000..ccb2d60c --- /dev/null +++ b/internal/explorer/repository_revision_id_test.go @@ -0,0 +1,15 @@ +package explorer + +import "testing" + +func TestRepositoryRevisionIDIncludesImmutableReceiptIdentity(t *testing.T) { + first := RepositoryRevisionID("program/project", "commit", "intent", "generation", "receipt-a") + replayed := RepositoryRevisionID("program/project", "commit", "intent", "generation", "receipt-a") + upgraded := RepositoryRevisionID("program/project", "commit", "intent", "generation", "receipt-b") + if first != replayed { + t.Fatalf("repository replay identity changed: %q != %q", first, replayed) + } + if first == upgraded { + t.Fatalf("compiler receipt upgrade reused revision identity %q", first) + } +} diff --git a/internal/explorer/service.go b/internal/explorer/service.go index 5432831c..92c5f6d2 100644 --- a/internal/explorer/service.go +++ b/internal/explorer/service.go @@ -2,16 +2,16 @@ package explorer import ( "context" - "crypto/rand" "crypto/sha256" "encoding/hex" "encoding/json" "errors" "fmt" + "net/url" "strings" "time" - "github.com/calypr/loom/internal/dataframe/publication" + "github.com/calypr/loom/internal/explorer/authoringv2" "github.com/calypr/loom/internal/projectid" ) @@ -38,51 +38,132 @@ func (s *Service) SaveRepositoryConfig(ctx context.Context, value RepositoryConf value.Project = projectid.Legacy(value.Project) return s.store.SaveRepositoryConfig(ctx, value) } -func (s *Service) ListConfigs(ctx context.Context, project string) ([]RepositoryConfig, error) { - return s.store.ListConfigs(ctx, projectid.Legacy(project)) -} -func (s *Service) Config(ctx context.Context, project, id string) (*RepositoryConfig, error) { - return s.store.GetConfig(ctx, projectid.Legacy(project), id) -} -func (s *Service) SaveConfig(ctx context.Context, value RepositoryConfig) (*RepositoryConfig, error) { - value.Project = projectid.Legacy(value.Project) - return s.store.SaveConfig(ctx, value) -} func (s *Service) Get(ctx context.Context, project, id string) (*Explorer, error) { return s.store.Get(ctx, projectid.Legacy(project), id) } -// EnsureRepositoryExplorer creates the repository-owned default identity when -// a migration is importing a configuration that has not previously been -// deployed through Loom. Existing identities are returned unchanged so the -// subsequent immutable revision publication can switch the active pointer in -// its normal transaction. -func (s *Service) EnsureRepositoryExplorer(ctx context.Context, project, id, title, actor string) (*Explorer, error) { +// LoadExplorerState returns the one canonical response for the public +// Explorer GET route. It loads the identity and immutable active revision +// together, then derives the renderer-facing projection from that revision. +// The HTTP layer should not reconstruct this response from individual legacy +// adapters. +func (s *Service) LoadExplorerState(ctx context.Context, project, id string) (ExplorerStateV1, error) { project = projectid.Canonical(project) - if id == "" { - id = "default" + id = strings.TrimSpace(id) + owner, err := s.Get(ctx, project, id) + if errors.Is(err, ErrNotFound) && id == "default" { + // Repository bootstrap can briefly expose its repository record before + // the Explorer identity is created. Preserve the read contract for that + // window without manufacturing editable authoring state. + repository, repositoryErr := s.RepositoryConfig(ctx, project) + if repositoryErr != nil { + return ExplorerStateV1{}, err + } + owner = &Explorer{ + Project: projectid.Legacy(project), + ExplorerID: "default", + Title: configV2Title(repository.Config), + ManagementMode: ManagementRepository, + ActiveRevisionID: repository.ActiveRevisionID, + Publication: repository.Publication, + UpdatedAt: repository.UpdatedAt, + } + err = nil } - if id != "default" { - return nil, fmt.Errorf("repository Explorer identity must be default") + if err != nil { + return ExplorerStateV1{}, err } - owner, err := s.store.Get(ctx, projectid.Legacy(project), id) - if err == nil { - return owner, nil + if owner == nil { + return ExplorerStateV1{}, fmt.Errorf("Explorer %s/%s resolved to an empty identity", project, id) } - if !errors.Is(err, ErrNotFound) { - return nil, err + + state := newExplorerStateResponse(owner) + if owner.ActiveRevisionID == "" { + markNotPublished(&state) + return state, nil } - if strings.TrimSpace(title) == "" { - title = "Explorer" + revision, err := s.Revision(ctx, owner.ActiveRevisionID) + if err != nil { + return ExplorerStateV1{}, fmt.Errorf("load active Explorer revision %q: %w", owner.ActiveRevisionID, err) + } + state.Active.RevisionID = revision.ID + state.Active.IntentDigest = revision.IntentDigest + state.Active.Status = string(revision.Status) + state.Active.Bundle = append([]byte(nil), revision.AuthoringBundle...) + state.Generated.RecipeDigest = revision.RecipeDigest + state.Generated.ResolvedSchemaDigest = revision.ResolvedSchemaDigest + state.Generated.SourceGeneration = revision.SourceGeneration + state.Generated.EmittedColumns = append([]EmittedColumn(nil), revision.EmittedColumns...) + state.Generated.Materializations, state.Generated.Dataset = WithDataframeSelectors(revision.Recipe, revision.Materializations, revision.Dataset) + state.Generated.Publication = revision.Publication + state.Generated.Publication.State = firstNonEmptyString(revision.Publication.State, string(revision.Status), ExplorerRuntimeV1NotPublished) + state.Generated.Publication.RevisionID = revision.ID + state.Generated.Diagnostics = append([]Diagnostic(nil), revision.Diagnostics...) + state.Runtime = s.BuildViewerProjection(revision) + if state.Runtime == nil || len(state.Runtime.Outputs) == 0 { + state.Generated.Publication.State = ExplorerRuntimeV1NotPublished + if state.Runtime != nil { + state.Runtime.Status = ExplorerRuntimeV1NotPublished + state.Runtime.Publication.State = ExplorerRuntimeV1NotPublished + } } - return s.store.CreateRepository(ctx, Explorer{ - Project: projectid.Legacy(project), - ExplorerID: id, - Title: title, - ManagementMode: ManagementRepository, - UpdatedBy: actor, - UpdatedAt: s.now(), - }) + return state, nil +} + +// BuildViewerProjection derives the renderer-facing state from one immutable +// revision. It is deliberately tolerant of revisions that contain an +// executable recipe but no authored presentation: the default table is +// generated from the query and publication metadata. +func (s *Service) BuildViewerProjection(revision *Revision) *ExplorerRuntimeV1 { + return buildViewerProjection(revision) +} + +func newExplorerStateResponse(owner *Explorer) ExplorerStateV1 { + project := projectid.Canonical(owner.Project) + state := ExplorerStateV1{ + APIVersion: ExplorerStateV1APIVersion, + Kind: ExplorerStateV1Kind, + Project: project, + ExplorerID: owner.ExplorerID, + Title: owner.Title, + Management: owner.ManagementMode, + Draft: ExplorerStateV1Draft{ + Bundle: append([]byte(nil), owner.DraftConfig...), + Version: owner.DraftVersion, + Digest: owner.DraftDigest, + }, + Generated: ExplorerStateV1Generated{ + RecipeDigest: owner.RecipeDigest, + ResolvedSchemaDigest: owner.ResolvedSchemaDigest, + SourceGeneration: owner.SourceGeneration, + EmittedColumns: append([]EmittedColumn(nil), owner.EmittedColumns...), + Materializations: append([]Materialization(nil), owner.Materializations...), + Dataset: owner.Dataset, + Publication: owner.Publication, + Diagnostics: append([]Diagnostic(nil), owner.Diagnostics...), + }, + ActiveURL: explorerURL(project, owner.ExplorerID), + UpdatedBy: owner.UpdatedBy, + UpdatedAt: owner.UpdatedAt, + } + return state +} + +func markNotPublished(state *ExplorerStateV1) { + state.Generated.Publication.State = ExplorerRuntimeV1NotPublished + state.Runtime = nil +} + +func configV2Title(raw json.RawMessage) string { + var config ConfigV2 + if json.Unmarshal(raw, &config) != nil || strings.TrimSpace(config.Explorer.Title) == "" { + return "Default" + } + return config.Explorer.Title +} + +func explorerURL(project, id string) string { + return "/api/v1/projects/" + url.PathEscape(project) + "/explorers/" + url.PathEscape(id) } // CreateEmptyInteractive creates only the Explorer identity. Unpublished @@ -94,6 +175,31 @@ func (s *Service) CreateEmptyInteractive(ctx context.Context, project, id, title } return s.store.CreateInteractive(ctx, Explorer{Project: projectid.Legacy(project), ExplorerID: id, Title: title, ManagementMode: ManagementInteractive, UpdatedBy: actor, UpdatedAt: s.now()}) } + +// SaveWorkspaceDraft persists canonical V2 authoring intent with optimistic +// concurrency. It never compiles, materializes, or changes the active pointer. +func (s *Service) SaveWorkspaceDraft(ctx context.Context, project, id string, workspace authoringv2.Workspace, expectedVersion int64, expectedDigest, actor string) (*Explorer, error) { + canonical, err := workspace.CanonicalJSON() + if err != nil { + return nil, err + } + digest, err := workspace.Digest() + if err != nil { + return nil, err + } + owner, err := s.Get(ctx, project, id) + if err != nil { + return nil, err + } + owner.DraftConfig = canonical + owner.DraftDigest = digest + owner.UpdatedBy = actor + owner.UpdatedAt = s.now() + if len(workspace.Tabs) > 0 && strings.TrimSpace(workspace.Tabs[0].Title) != "" { + owner.Title = workspace.Tabs[0].Title + } + return s.store.SaveDraft(ctx, *owner, expectedVersion, expectedDigest) +} func (s *Service) Revision(ctx context.Context, id string) (*Revision, error) { return s.store.GetRevision(ctx, id) } @@ -111,10 +217,6 @@ func (s *Service) FailRevision(ctx context.Context, id string, diagnostics []Dia return s.store.TransitionRevision(ctx, id, RevisionFailed, diagnostics) } -func (s *Service) CompilationReceipt(ctx context.Context, id string) (*CompilationReceipt, error) { - return s.store.GetCompilationReceipt(ctx, id) -} - // CompilationReceiptForExplorer performs the tenant-scoped lookup used by // execution and publication. The ID-only method above remains for legacy // callers during the receipt migration. @@ -126,26 +228,10 @@ func (s *Service) CompilationReceiptByCompilationKey(ctx context.Context, projec return s.store.GetCompilationReceiptByCompilationKey(ctx, projectid.Canonical(project), explorerID, compilationKey) } -func (s *Service) CompilationReceiptStats(ctx context.Context, project string) (ReceiptStoreStats, error) { - return s.store.CompilationReceiptStats(ctx, projectid.Canonical(project)) -} - func (s *Service) StoreCompilationReceipt(ctx context.Context, receipt CompilationReceipt) (*CompilationReceipt, error) { return s.store.InsertCompilationReceipt(ctx, receipt) } -func (s *Service) PurgeDraftAuthoring(ctx context.Context) error { - return s.store.PurgeDraftAuthoring(ctx) -} - -func (s *Service) InsertAuthoringRevision(ctx context.Context, revision Revision) (*Revision, error) { - if revision.ID == "" || revision.CompilationReceiptID == "" || revision.IntentDigest == "" { - return nil, fmt.Errorf("authoring revision identity is incomplete") - } - revision.Project = projectid.Legacy(revision.Project) - return s.store.InsertRevision(ctx, revision) -} - // PublishAuthoring atomically stores the server receipt and immutable revision // and switches the Explorer's active pointer. func (s *Service) PublishAuthoring(ctx context.Context, receipt CompilationReceipt, revision Revision) (*Revision, error) { @@ -157,223 +243,63 @@ func (s *Service) PublishAuthoring(ctx context.Context, receipt CompilationRecei return s.store.PublishAuthoring(ctx, receipt, revision) } -// NewInteractiveRevisionID is opaque and collision-resistant; repository -// revisions intentionally use the deterministic tuple identity instead. -func NewInteractiveRevisionID() (string, error) { - bytes := make([]byte, 16) - if _, err := rand.Read(bytes); err != nil { - return "", err - } - return "interactive_" + hex.EncodeToString(bytes), nil -} - // UpsertRepositoryV2 records the repository-owned default and its immutable -// ready revision after the external dataframe publication has succeeded. +// receipt-backed ready revision after dataframe publication has succeeded. // Activation is intentionally a separate call so callers can compose it with // the dataset release switch where the durable adapter supports that atomic // transaction. -func (s *Service) UpsertRepositoryV2(ctx context.Context, raw []byte, sourceCommit, sourceGeneration, actor string, compiled Compilation, resolvedSchemaDigest string, materializations []Materialization, dataset DatasetMetadata, publication PublicationMetadata) (*Explorer, *Revision, error) { - cfg, _, canonical, configDigest, err := CanonicalConfigV2(raw, "", "default", "repository") - if err != nil { - // The project is carried by the packet; decode once to obtain it while - // preserving the strict validator above. - var envelope struct { - Project string `json:"project"` - } - if decodeErr := json.Unmarshal(raw, &envelope); decodeErr != nil { - return nil, nil, err - } - cfg, _, canonical, configDigest, err = CanonicalConfigV2(raw, envelope.Project, "default", "repository") - if err != nil { - return nil, nil, err - } +func (s *Service) UpsertRepositoryV2(ctx context.Context, receipt CompilationReceipt, sourceCommit, actor string, materializations []Materialization, dataset DatasetMetadata, publication PublicationMetadata) (*Explorer, *Revision, error) { + if err := receipt.Validate(); err != nil { + return nil, nil, fmt.Errorf("invalid repository compilation receipt: %w", err) + } + if strings.TrimSpace(receipt.ExplorerID) != "default" { + return nil, nil, fmt.Errorf("repository compilation receipt must target default") } - project := projectid.Canonical(cfg.Project) + if len(receipt.NormalizedBundle) == 0 || len(receipt.CompiledConfig) == 0 || len(receipt.PublicOutputContract) == 0 { + return nil, nil, fmt.Errorf("repository compilation receipt is missing durable V2 artifacts") + } + project := projectid.Canonical(receipt.Project) storageProject := projectid.Legacy(project) + workspace := append(json.RawMessage(nil), receipt.NormalizedBundle...) + compiledConfig := append(json.RawMessage(nil), receipt.CompiledConfig...) + title := "Default" + if decoded, err := authoringv2.DecodeWorkspace(workspace); err == nil && len(decoded.Tabs) > 0 { + title = decoded.Tabs[0].Title + } + if _, err := s.StoreCompilationReceipt(ctx, receipt); err != nil { + return nil, nil, err + } owner, err := s.store.Get(ctx, storageProject, "default") if errors.Is(err, ErrNotFound) { - owner, err = s.store.CreateRepository(ctx, Explorer{Project: storageProject, ExplorerID: "default", Title: cfg.Explorer.Title, ManagementMode: ManagementRepository, DraftConfig: canonical, DraftVersion: 1, DraftDigest: configDigest, SourceGeneration: sourceGeneration, Dataset: dataset, Publication: publication, UpdatedBy: actor, UpdatedAt: s.now()}) + owner, err = s.store.CreateRepository(ctx, Explorer{Project: storageProject, ExplorerID: "default", Title: title, ManagementMode: ManagementRepository, DraftConfig: workspace, DraftVersion: 1, DraftDigest: receipt.IntentDigest, SourceGeneration: receipt.SourceGeneration, Dataset: dataset, Publication: publication, UpdatedBy: actor, UpdatedAt: s.now()}) } else if err == nil { - owner.Title, owner.DraftConfig, owner.DraftDigest, owner.SourceGeneration, owner.Dataset, owner.Publication, owner.UpdatedBy = cfg.Explorer.Title, canonical, configDigest, sourceGeneration, dataset, publication, actor + owner.Title, owner.DraftConfig, owner.DraftDigest, owner.SourceGeneration, owner.Dataset, owner.Publication, owner.UpdatedBy = title, workspace, receipt.IntentDigest, receipt.SourceGeneration, dataset, publication, actor owner, err = s.store.SaveDraft(ctx, *owner, owner.DraftVersion) } if err != nil { return nil, nil, err } - revisionID := RepositoryRevisionID(project, sourceCommit, configDigest, sourceGeneration) + revisionID := RepositoryRevisionID(project, sourceCommit, receipt.IntentDigest, receipt.SourceGeneration, receipt.ID) now := s.now() - revision, err := s.store.InsertRevision(ctx, Revision{ID: revisionID, Project: storageProject, ExplorerID: "default", Config: canonical, ConfigDigest: configDigest, Recipe: compiled.Bundle, RecipeDigest: compiled.RecipeDigest, ResolvedSchemaDigest: resolvedSchemaDigest, SourceGeneration: sourceGeneration, SourceCommit: sourceCommit, Dataset: dataset, Publication: publication, Materializations: append([]Materialization(nil), materializations...), EmittedColumns: append([]EmittedColumn(nil), compiled.EmittedColumns...), Status: RevisionReady, CreatedBy: actor, CreatedAt: now, ReadyAt: &now}) + revision, err := s.store.InsertRevision(ctx, Revision{ID: revisionID, Project: storageProject, ExplorerID: "default", Config: compiledConfig, ConfigDigest: receipt.IntentDigest, AuthoringBundle: workspace, IntentDigest: receipt.IntentDigest, CompilationReceiptID: receipt.ID, PublicOutputContract: append(json.RawMessage(nil), receipt.PublicOutputContract...), Recipe: receipt.Bundle, RecipeDigest: receipt.RecipeDigest, ResolvedSchemaDigest: receipt.ResolvedSchemaDigest, SourceGeneration: receipt.SourceGeneration, SourceCommit: sourceCommit, Dataset: dataset, Publication: publication, Materializations: append([]Materialization(nil), materializations...), EmittedColumns: append([]EmittedColumn(nil), receipt.EmittedColumns...), Status: RevisionReady, CreatedBy: actor, CreatedAt: now, ReadyAt: &now}) if err != nil { return nil, nil, err } return owner, revision, nil } -func (s *Service) ActivateInteractive(ctx context.Context, project, explorerID, revisionID string) error { - return s.store.ActivateInteractive(ctx, projectid.Legacy(project), explorerID, revisionID) -} -func (s *Service) ActivateRepository(ctx context.Context, project, revisionID string) error { - return s.store.ActivateRepository(ctx, projectid.Legacy(project), revisionID) -} func (s *Service) ActivateRepositoryGeneration(ctx context.Context, project, generation, revisionID string) error { return s.store.ActivateRepositoryGeneration(ctx, projectid.Legacy(project), generation, revisionID) } // RepositoryRevisionID is stable for retrying the same checked-out repository -// content against the same Loom generation. It intentionally has no Gecko -// organization/project identity component. -func RepositoryRevisionID(project, sourceCommit, definitionDigest, sourceGeneration string) string { - sum := sha256.Sum256([]byte(project + "\x00default\x00" + sourceCommit + "\x00" + definitionDigest + "\x00" + sourceGeneration)) +// content and immutable compilation receipt against the same Loom generation. +// Including the receipt identity prevents a compiler-contract upgrade from +// colliding with a revision produced under older lowering semantics. +func RepositoryRevisionID(project, sourceCommit, definitionDigest, sourceGeneration string, receiptIdentity ...string) string { + artifact := "" + if len(receiptIdentity) > 0 { + artifact = receiptIdentity[0] + } + sum := sha256.Sum256([]byte(project + "\x00default\x00" + sourceCommit + "\x00" + definitionDigest + "\x00" + sourceGeneration + "\x00" + artifact)) return "repository_" + hex.EncodeToString(sum[:]) } - -// CreateInteractiveV2 persists a complete custom V2 draft without compiling or -// materializing it. The repository default is created by repository deploys; -// it uses SaveDraftV2 for subsequent Builder edits. -func (s *Service) CreateInteractiveV2(ctx context.Context, project, id string, raw []byte, actor string) (*Explorer, error) { - if id == "default" { - return nil, fmt.Errorf("default Explorer already exists; edit its draft") - } - cfg, _, canonical, digest, err := CanonicalConfigV2(raw, project, id, "interactive") - if err != nil { - return nil, err - } - canonicalProject := projectid.Canonical(project) - return s.store.CreateInteractive(ctx, Explorer{ - Project: projectid.Legacy(canonicalProject), ExplorerID: id, Title: cfg.Explorer.Title, - ManagementMode: ManagementInteractive, DraftConfig: canonical, - DraftVersion: 1, DraftDigest: digest, UpdatedBy: actor, UpdatedAt: s.now(), - }) -} - -// SaveDraftV2 is the only V2 draft write path. It performs no compilation or -// materialization. Draft writes are intentionally last-write-wins: the -// expected version and digest are retained for API compatibility and -// observability, but a stale Builder cannot block the latest valid draft from -// being saved. -// The repository default is editable; its repository identity is retained in -// the packet so a later ETL deployment can still recognize it. -func (s *Service) SaveDraftV2(ctx context.Context, project, id string, raw []byte, expected int64, expectedDigest, actor string) (*Explorer, error) { - management := ConfigManagementForID(id) - cfg, _, canonical, digest, err := CanonicalConfigV2(raw, project, id, management) - if err != nil { - return nil, err - } - canonicalProject := projectid.Canonical(project) - storageProject := projectid.Legacy(canonicalProject) - current, err := s.store.Get(ctx, storageProject, id) - if errors.Is(err, ErrNotFound) && id == "default" { - repository, repositoryErr := s.store.GetRepositoryConfig(ctx, storageProject) - if repositoryErr != nil { - return nil, repositoryErr - } - baseVersion := repository.DraftVersion - if baseVersion == 0 { - baseVersion = 1 - } - baseDigest := repository.ConfigDigest - if baseDigest == "" { - _, _, _, baseDigest, _ = CanonicalConfigV2(repository.Config, project, "default", "repository") - } - updatedAt := repository.UpdatedAt - if updatedAt.IsZero() { - updatedAt = s.now() - } - current, err = s.store.CreateRepository(ctx, Explorer{ - Project: storageProject, ExplorerID: "default", Title: cfg.Explorer.Title, - ManagementMode: ManagementRepository, DraftConfig: append([]byte(nil), repository.Config...), - DraftVersion: baseVersion, DraftDigest: baseDigest, - ActiveRevisionID: repository.ActiveRevisionID, ActiveConfig: append([]byte(nil), repository.Config...), - SourceGeneration: repository.SourceGeneration, Materializations: append([]Materialization(nil), repository.Materializations...), - Dataset: repository.Dataset, Publication: repository.Publication, Diagnostics: append([]Diagnostic(nil), repository.Diagnostics...), - UpdatedBy: "repository", UpdatedAt: updatedAt, - }) - if errors.Is(err, ErrDraftConflict) { - current, err = s.store.Get(ctx, storageProject, id) - } - } - if err != nil { - return nil, err - } - expectedManagement := ManagementInteractive - if id == "default" { - expectedManagement = ManagementRepository - } - if current.ManagementMode != expectedManagement { - return nil, fmt.Errorf("Explorer management mode does not match its identity") - } - current.Title = cfg.Explorer.Title - current.DraftConfig = canonical - current.DraftDigest = digest - current.UpdatedBy = actor - return s.store.SaveDraft(ctx, *current, expected, expectedDigest) -} - -func (s *Service) InsertReadyRevisionV2(ctx context.Context, owner *Explorer, config []byte, configDigest string, compiled Compilation, resolvedSchemaDigest, sourceGeneration, actor string, materializations []Materialization) (*Revision, error) { - return s.InsertReadyRevisionV2WithMetadata(ctx, owner, config, configDigest, compiled, resolvedSchemaDigest, sourceGeneration, actor, materializations, datasetMetadata(sourceGeneration, resolvedSchemaDigest, materializations), PublicationMetadata{}) -} - -// InsertReadyRevisionV2WithMetadata records a configuration revision against -// an already materialized dataset. Callers that publish an Explorer -// configuration without rebuilding data pass the active release's frozen -// dataset/materialization metadata here so the revision remains queryable. -func (s *Service) InsertReadyRevisionV2WithMetadata(ctx context.Context, owner *Explorer, config []byte, configDigest string, compiled Compilation, resolvedSchemaDigest, sourceGeneration, actor string, materializations []Materialization, dataset DatasetMetadata, publication PublicationMetadata) (*Revision, error) { - if owner == nil || (owner.ManagementMode != ManagementInteractive && !(owner.ExplorerID == "default" && owner.ManagementMode == ManagementRepository)) { - return nil, fmt.Errorf("Explorer is not editable") - } - id, err := NewInteractiveRevisionID() - if err != nil { - return nil, err - } - now := s.now() - if dataset.Generation == "" { - dataset.Generation = sourceGeneration - } - if dataset.SchemaDigest == "" { - dataset.SchemaDigest = resolvedSchemaDigest - } - if publication.State == "" { - publication.State = string(RevisionReady) - } - if publication.Generation == "" { - publication.Generation = sourceGeneration - } - if publication.UpdatedAt.IsZero() { - publication.UpdatedAt = now - } - return s.store.InsertRevision(ctx, Revision{ - ID: id, Project: owner.Project, ExplorerID: owner.ExplorerID, - Config: append([]byte(nil), config...), ConfigDigest: configDigest, - Recipe: compiled.Bundle, RecipeDigest: compiled.RecipeDigest, - ResolvedSchemaDigest: resolvedSchemaDigest, SourceGeneration: sourceGeneration, - Dataset: dataset, - Publication: publication, - EmittedColumns: append([]EmittedColumn(nil), compiled.EmittedColumns...), - Materializations: append([]Materialization(nil), materializations...), - Status: RevisionReady, CreatedBy: actor, CreatedAt: now, ReadyAt: &now, - }) -} - -func datasetMetadata(generation, schemaDigest string, materializations []Materialization) DatasetMetadata { - outputs := make([]DatasetOutput, 0, len(materializations)) - for _, materialization := range materializations { - outputs = append(outputs, DatasetOutput{ - Name: materialization.Output, - State: string(RevisionReady), Queryable: true, - Selector: materialization.Selector, - Columns: append([]publication.PhysicalColumn(nil), materialization.Columns...), - }) - } - return DatasetMetadata{Generation: generation, SchemaDigest: schemaDigest, Outputs: outputs} -} - -func (s *Service) InsertFailedRevisionV2(ctx context.Context, owner *Explorer, config []byte, configDigest, sourceGeneration, actor string, diagnostics []Diagnostic) (*Revision, error) { - if owner == nil || (owner.ManagementMode != ManagementInteractive && !(owner.ExplorerID == "default" && owner.ManagementMode == ManagementRepository)) { - return nil, fmt.Errorf("Explorer is not editable") - } - id, err := NewInteractiveRevisionID() - if err != nil { - return nil, err - } - now := s.now() - return s.store.InsertRevision(ctx, Revision{ID: id, Project: owner.Project, ExplorerID: owner.ExplorerID, Config: append([]byte(nil), config...), ConfigDigest: configDigest, SourceGeneration: sourceGeneration, Diagnostics: append([]Diagnostic(nil), diagnostics...), Status: RevisionFailed, CreatedBy: actor, CreatedAt: now, FailedAt: &now}) -} diff --git a/internal/explorer/state_v1.go b/internal/explorer/state_v1.go index 077a6877..01637f0b 100644 --- a/internal/explorer/state_v1.go +++ b/internal/explorer/state_v1.go @@ -8,14 +8,11 @@ import ( ) const ( - ExplorerStateV1APIVersion = "loom.calypr.org/explorer-state/v1" - ExplorerStateV1Kind = "ExplorerState" - ExplorerBuilderStateV1Kind = "ExplorerBuilderState" + ExplorerStateV1APIVersion = "loom.calypr.org/explorer-state/v1" + ExplorerStateV1Kind = "ExplorerState" + ExplorerRuntimeV1NotPublished = "NOT_PUBLISHED" ) -// ExplorerSummaryV1 is the intentionally small collection projection. Builder -// intent, catalog data, and resolved bindings are available only from the -// selected Explorer's /authoring/v1/builder resource. type ExplorerSummaryV1 struct { Project string `json:"project"` ExplorerID string `json:"explorerId"` @@ -25,122 +22,6 @@ type ExplorerSummaryV1 struct { UpdatedAt time.Time `json:"updatedAt"` } -// ExplorerBuilderStateV1 is the complete, server-resolved editing model. The -// catalog and bindings are from the same immutable snapshot as Bundle. -type ExplorerBuilderStateV1 struct { - APIVersion string `json:"apiVersion"` - Kind string `json:"kind"` - Project string `json:"project"` - ExplorerID string `json:"explorerId"` - Title string `json:"title"` - Bundle ExplorerAuthoringBundleV1 `json:"bundle"` - Catalog ExplorerBuilderCatalogV1 `json:"catalog"` - Bindings []ExplorerResolvedBindingV1 `json:"bindings"` - Active ExplorerBuilderPublicationV1 `json:"active"` - Diagnostics []AuthoringDiagnostic `json:"diagnostics"` -} - -type ExplorerBuilderCatalogV1 struct { - SnapshotToken string `json:"snapshotToken"` - Generation string `json:"generation"` - ResolvedSchemaDigest string `json:"resolvedSchemaDigest,omitempty"` - AuthorizationScopeDigest string `json:"authorizationScopeDigest,omitempty"` - Nodes []ExplorerCatalogNodeV1 `json:"nodes"` - Edges []ExplorerCatalogEdgeV1 `json:"edges"` - Candidates []ExplorerCandidateV1 `json:"candidates"` -} - -type ExplorerCatalogNodeV1 struct { - NodeID string `json:"nodeId"` - ResourceType string `json:"resourceType"` -} -type ExplorerCatalogEdgeV1 struct { - EdgeID string `json:"edgeId"` - FromNodeID string `json:"fromNodeId"` - ToNodeID string `json:"toNodeId"` - Label string `json:"label"` -} -type ExplorerCandidateV1 struct { - CandidateID string `json:"candidateId"` - NodeID string `json:"nodeId"` - Label string `json:"label"` - LogicalType string `json:"logicalType"` - Filterable bool `json:"filterable"` - Chartable bool `json:"chartable"` -} - -type ExplorerResolvedBindingV1 struct { - OutputID string `json:"outputId"` - OutputTitle string `json:"outputTitle,omitempty"` - BaseNodeID string `json:"baseNodeId"` - BaseResourceType string `json:"baseResourceType"` - RowNodeID string `json:"rowNodeId"` - RowResourceType string `json:"rowResourceType"` - RowGrain string `json:"rowGrain"` - RouteKind string `json:"routeKind"` - RouteOccurrences []ExplorerResolvedOccurrenceV1 `json:"routeOccurrences"` - CandidateEmissions []ExplorerCandidateEmissionV1 `json:"candidateEmissions"` -} -type ExplorerResolvedOccurrenceV1 struct { - OccurrenceID string `json:"occurrenceId"` - Index int `json:"index"` - NodeID string `json:"nodeId"` - ResourceType string `json:"resourceType"` - IncomingEdgeID string `json:"incomingEdgeId,omitempty"` -} -type ExplorerCandidateEmissionV1 struct { - CandidateID string `json:"candidateId"` - OccurrenceID string `json:"occurrenceId"` - EmissionID string `json:"emissionId"` - // PublicColumn is the exact logical key returned in Builder preview rows. - // Browsers must never reconstruct this value from a label or identity. - PublicColumn string `json:"publicColumn"` - Label string `json:"label"` - LogicalType string `json:"logicalType"` - Filterable bool `json:"filterable"` - Chartable bool `json:"chartable"` -} - -// ExplorerPreviewColumnV1 is the authoritative bridge between an authoring -// emission and a preview row. EmissionID owns presentation; PublicColumn owns -// row lookup. -type ExplorerPreviewColumnV1 struct { - OutputID string `json:"outputId"` - CandidateID string `json:"candidateId"` - OccurrenceID string `json:"occurrenceId"` - EmissionID string `json:"emissionId"` - PublicColumn string `json:"publicColumn"` - Label string `json:"label"` - LogicalType string `json:"logicalType"` - Filterable bool `json:"filterable"` - Chartable bool `json:"chartable"` -} -type ExplorerBuilderPublicationV1 struct { - RevisionID string `json:"revisionId,omitempty"` - State string `json:"state,omitempty"` - Generation string `json:"generation,omitempty"` - IntentDigest string `json:"intentDigest,omitempty"` - PublishedAt time.Time `json:"publishedAt,omitempty"` - // Migration is a small, non-sensitive projection of immutable revision - // provenance. Raw source packets remain on the revision for rollback, but - // the Builder can still tell that its default was imported and identify the - // source/digests without downloading those packets. - Migration *ExplorerMigrationSummaryV1 `json:"migration,omitempty"` -} - -type ExplorerMigrationSummaryV1 struct { - Kind string `json:"kind"` - Source string `json:"source"` - SourceProject string `json:"sourceProject"` - SourceExplorerID string `json:"sourceExplorerId"` - OriginalConfigDigest string `json:"originalConfigDigest,omitempty"` - OriginalMappingDigest string `json:"originalMappingDigest,omitempty"` - MigratedAt time.Time `json:"migratedAt"` -} - -// ExplorerStateV1 is the server-owned lifecycle projection consumed by the -// Builder. It carries authoring bundles and publication metadata, but never -// exposes the legacy ExplorerConfig packet or the compiled recipe AST. type ExplorerStateV1 struct { APIVersion string `json:"apiVersion"` Kind string `json:"kind"` @@ -152,7 +33,10 @@ type ExplorerStateV1 struct { Draft ExplorerStateV1Draft `json:"draft"` Active ExplorerStateV1Active `json:"active"` Generated ExplorerStateV1Generated `json:"generated"` - Runtime *ExplorerRuntimeV1 `json:"runtime,omitempty"` + // Runtime is explicit so an Explorer with no executable query is still a + // valid response. Clients can inspect generated.publication.state or the + // null runtime instead of treating a missing field as a malformed payload. + Runtime *ExplorerRuntimeV1 `json:"runtime"` ActiveURL string `json:"activeUrl"` UpdatedBy string `json:"updatedBy,omitempty"` @@ -185,16 +69,14 @@ type ExplorerStateV1Generated struct { Diagnostics []Diagnostic `json:"diagnostics,omitempty"` } -// ExplorerRuntimeV1 is the renderer-ready projection of one active Explorer -// release. Loom owns this projection so browsers never need to reconstruct -// runtime bindings from authoring intent, compiled configuration, or physical -// publication metadata. type ExplorerRuntimeV1 struct { + Status string `json:"status"` Generation string `json:"generation,omitempty"` Publication PublicationMetadata `json:"publication,omitempty"` Schema ExplorerRuntimeSchemaV1 `json:"schema,omitempty"` Outputs []ExplorerRuntimeOutputV1 `json:"outputs"` SharedFilters map[string][]ExplorerRuntimeBindingV1 `json:"sharedFilters"` + FileActions FileActions `json:"fileActions,omitempty"` Diagnostics []Diagnostic `json:"diagnostics"` } @@ -214,12 +96,14 @@ type ExplorerRuntimeOutputV1 struct { Filters []ExplorerRuntimeBindingV1 `json:"filters"` Charts []ExplorerRuntimeBindingV1 `json:"charts"` FixedFilters map[string][]string `json:"fixedFilters"` + Actions []ConfigAction `json:"actions,omitempty"` Materialization *Materialization `json:"materialization,omitempty"` } type ExplorerRuntimeColumnV1 struct { - EmissionID string `json:"emissionId"` - Name string `json:"name"` + Column string `json:"column"` + EmissionID string `json:"-"` + Name string `json:"-"` Label string `json:"label"` LogicalType string `json:"logicalType"` Visible bool `json:"visible"` @@ -236,12 +120,16 @@ type ExplorerRuntimeTableV1 struct { } type ExplorerRuntimeTableColumnV1 struct { - EmissionID string `json:"emissionId"` - Visible bool `json:"visible"` + Column string `json:"column"` + Visible bool `json:"visible"` + Pinned bool `json:"pinned,omitempty"` + CellRenderer string `json:"cellRenderer,omitempty"` + EmissionID string `json:"-"` } type ExplorerRuntimeBindingV1 struct { - EmissionID string `json:"emissionId"` + Column string `json:"column"` + EmissionID string `json:"-"` OutputID string `json:"outputId,omitempty"` Label string `json:"label,omitempty"` Type string `json:"type,omitempty"` diff --git a/internal/explorer/store.go b/internal/explorer/store.go index 5ace5cb9..1354d29a 100644 --- a/internal/explorer/store.go +++ b/internal/explorer/store.go @@ -2,11 +2,7 @@ package explorer import ( "context" - "crypto/sha256" - "encoding/hex" "errors" - "strings" - "time" ) var ( @@ -21,60 +17,10 @@ var ( ErrCorruptReceipt = errors.New("corrupt compilation receipt") ) -// ReceiptStoreStats is intentionally read-only and approximate. ApproxBytes -// is a serialized-document estimate, suitable for capacity observations, not -// billing or quota enforcement. -type ReceiptStoreStats struct { - Count int - ApproxBytes int64 - OldestCreatedAt time.Time - UnreferencedCount int -} - -func validateCompilationReceipt(receipt CompilationReceipt) error { - if strings.TrimSpace(receipt.ID) == "" { - return ErrCorruptReceipt - } - // New-format receipts are validated as executable artifacts. A few pre-v2 - // fixtures used human-readable IDs; keep accepting those - // during the migration, but every content-addressed receipt is checked on - // every read and write. - if receipt.ReceiptFormatVersion != 0 || receipt.CompilerContractVersion != "" || receipt.CompilationKey != "" { - if err := receipt.Validate(); err != nil { - return err - } - } - if strings.HasPrefix(receipt.ID, "receipt_") && looksContentAddressedReceiptID(receipt.ID) { - if err := receipt.ValidateID(); err != nil { - return ErrCorruptReceipt - } - } - return nil -} - -func looksContentAddressedReceiptID(id string) bool { - const prefix = "receipt_" - return len(id) == len(prefix)+sha256.Size*2 && hexEncoded(id[len(prefix):]) -} - -func hexEncoded(value string) bool { - _, err := hex.DecodeString(value) - return err == nil -} - -func sameCompilationReceipt(a, b CompilationReceipt) bool { - left, leftErr := ReceiptID(a) - right, rightErr := ReceiptID(b) - return leftErr == nil && rightErr == nil && left == right -} - // Store deliberately exposes only lifecycle mutations for revisions. An // adapter must never replace definition, recipe, digests, source generation, // or frozen materialization mappings after InsertRevision succeeds. type Store interface { - ListConfigs(context.Context, string) ([]RepositoryConfig, error) - GetConfig(context.Context, string, string) (*RepositoryConfig, error) - SaveConfig(context.Context, RepositoryConfig) (*RepositoryConfig, error) GetRepositoryConfig(context.Context, string) (*RepositoryConfig, error) SaveRepositoryConfig(context.Context, RepositoryConfig) (*RepositoryConfig, error) List(context.Context, string) ([]Explorer, error) @@ -87,20 +33,11 @@ type Store interface { // caller's expected version. SaveDraft(context.Context, Explorer, int64, ...string) (*Explorer, error) InsertCompilationReceipt(context.Context, CompilationReceipt) (*CompilationReceipt, error) - GetCompilationReceipt(context.Context, string) (*CompilationReceipt, error) - // GetCompilationReceiptForExplorer is the tenant-scoped form. The legacy - // ID-only method remains temporarily for old publication callers. GetCompilationReceiptForExplorer(context.Context, string, string, string) (*CompilationReceipt, error) GetCompilationReceiptByCompilationKey(context.Context, string, string, string) (*CompilationReceipt, error) - CompilationReceiptStats(context.Context, string) (ReceiptStoreStats, error) PublishAuthoring(context.Context, CompilationReceipt, Revision) (*Revision, error) InsertRevision(context.Context, Revision) (*Revision, error) GetRevision(context.Context, string) (*Revision, error) TransitionRevision(context.Context, string, RevisionStatus, []Diagnostic) (*Revision, error) - ActivateInteractive(context.Context, string, string, string) error - ActivateRepository(context.Context, string, string) error ActivateRepositoryGeneration(context.Context, string, string, string) error - // PurgeDraftAuthoring irreversibly removes every legacy/draft authoring - // field and compilation receipt not referenced by an immutable revision. - PurgeDraftAuthoring(context.Context) error } diff --git a/internal/explorer/types.go b/internal/explorer/types.go index ccea0000..673baa8a 100644 --- a/internal/explorer/types.go +++ b/internal/explorer/types.go @@ -14,21 +14,25 @@ import ( // authoring aggregate: the repository packet carries the executable baseline; // live schema/readiness and publication metadata are stored alongside it. type RepositoryConfig struct { - Project string `json:"project"` - ExplorerID string `json:"explorerId"` - Management ManagementMode `json:"management"` - Config json.RawMessage `json:"config"` - ConfigDigest string `json:"configDigest,omitempty"` - SourceGeneration string `json:"sourceGeneration"` - SourceCommit string `json:"sourceCommit"` - ExecutionID string `json:"executionId"` - ActiveRevisionID string `json:"activeRevisionId,omitempty"` - DraftVersion int64 `json:"-"` - Materializations []Materialization `json:"materializations"` - Dataset DatasetMetadata `json:"dataset"` - Publication PublicationMetadata `json:"publication"` - Diagnostics []Diagnostic `json:"diagnostics,omitempty"` - UpdatedAt time.Time `json:"updatedAt"` + Project string `json:"project"` + ExplorerID string `json:"explorerId"` + Management ManagementMode `json:"management"` + Config json.RawMessage `json:"config"` + Workspace json.RawMessage `json:"workspace"` + ConfigDigest string `json:"configDigest,omitempty"` + IntentDigest string `json:"intentDigest,omitempty"` + CompilationReceiptID string `json:"compilationReceiptId,omitempty"` + PublicOutputContract json.RawMessage `json:"publicOutputContract,omitempty"` + SourceGeneration string `json:"sourceGeneration"` + SourceCommit string `json:"sourceCommit"` + ExecutionID string `json:"executionId"` + ActiveRevisionID string `json:"activeRevisionId,omitempty"` + DraftVersion int64 `json:"-"` + Materializations []Materialization `json:"materializations"` + Dataset DatasetMetadata `json:"dataset"` + Publication PublicationMetadata `json:"publication"` + Diagnostics []Diagnostic `json:"diagnostics,omitempty"` + UpdatedAt time.Time `json:"updatedAt"` } type ManagementMode string @@ -94,9 +98,9 @@ type Explorer struct { ManagementMode ManagementMode `json:"managementMode"` // DraftConfig is the lossless, canonical ExplorerConfigV2 packet used by // the Builder. - DraftConfig json.RawMessage `json:"-"` - DraftVersion int64 `json:"-"` - DraftDigest string `json:"-"` + DraftConfig json.RawMessage `json:"draftConfig,omitempty"` + DraftVersion int64 `json:"draftVersion"` + DraftDigest string `json:"draftDigest,omitempty"` ActiveRevisionID string `json:"activeRevisionId,omitempty"` ActiveConfig json.RawMessage `json:"activeConfig,omitempty"` RecipeDigest string `json:"recipeDigest,omitempty"` @@ -138,6 +142,7 @@ type Revision struct { AuthoringBundle json.RawMessage `json:"authoringBundle,omitempty"` IntentDigest string `json:"intentDigest,omitempty"` CompilationReceiptID string `json:"compilationReceiptId,omitempty"` + PublicOutputContract json.RawMessage `json:"publicOutputContract,omitempty"` Recipe recipe.Bundle `json:"canonicalRecipe"` RecipeDigest string `json:"recipeDigest"` ResolvedSchemaDigest string `json:"resolvedSchemaDigest"` diff --git a/internal/explorer/types_test.go b/internal/explorer/types_test.go new file mode 100644 index 00000000..bb1fdb59 --- /dev/null +++ b/internal/explorer/types_test.go @@ -0,0 +1,21 @@ +package explorer + +import ( + "encoding/json" + "testing" +) + +func TestExplorerPersistsDurableV2DraftState(t *testing.T) { + want := Explorer{Project: "program-project", ExplorerID: "default", DraftConfig: json.RawMessage(`{"apiVersion":"loom.calypr.org/explorer-authoring/v2"}`), DraftVersion: 3, DraftDigest: "sha256:intent"} + raw, err := json.Marshal(want) + if err != nil { + t.Fatal(err) + } + var got Explorer + if err := json.Unmarshal(raw, &got); err != nil { + t.Fatal(err) + } + if got.DraftVersion != want.DraftVersion || got.DraftDigest != want.DraftDigest || string(got.DraftConfig) != string(want.DraftConfig) { + t.Fatalf("draft state did not round trip: %#v", got) + } +} diff --git a/internal/explorer/v2_lifecycle_test.go b/internal/explorer/v2_lifecycle_test.go deleted file mode 100644 index 51573835..00000000 --- a/internal/explorer/v2_lifecycle_test.go +++ /dev/null @@ -1,69 +0,0 @@ -package explorer - -import ( - "context" - "testing" -) - -func TestV2DraftRoundTripLastWriteWins(t *testing.T) { - service, err := NewService(NewMemoryStore()) - if err != nil { - t.Fatal(err) - } - raw := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"my-explorer","title":"My Explorer","description":"presentation survives","management":"interactive"},"recipe":{"recipeSchemaVersion":1,"name":"explorer-my-explorer","translationVersion":"interactive","outputs":[{"name":"DocumentReference","rootResourceType":"DocumentReference","rowGrain":"document_reference","fields":[{"name":"id","fieldRef":"DocumentReference.id","expr":{"select":"root.id"}}]}]},"views":[{"id":"main","title":"Main","output":"DocumentReference","rowLabel":"id","table":{"columns":[{"column":"id","label":"Identifier","visible":true}]},"filters":[{"column":"id","label":"Identifier"}],"charts":[{"column":"id","type":"TABLE","title":"Identifiers"}],"fixedFilters":{"status":["active"]},"actions":[{"type":"download","title":"Download","fileName":"records.csv"}]}],"sharedFilters":{"main":[{"output":"DocumentReference","column":"id"}]},"fileActions":{"extensions":{"csv":["id"]},"actions":{"download":"csv"}}}`) - created, err := service.CreateInteractiveV2(context.Background(), "project-a", "my-explorer", raw, "author") - if err != nil { - t.Fatal(err) - } - if string(created.DraftConfig) == string(raw) { - t.Log("input was already canonical") - } - if created.DraftDigest == "" || created.DraftVersion != 1 { - t.Fatalf("draft metadata = %#v", created) - } - loaded, err := service.Get(context.Background(), "project-a", "my-explorer") - if err != nil { - t.Fatal(err) - } - if string(loaded.DraftConfig) != string(created.DraftConfig) { - t.Fatalf("draft packet changed on round trip: %s != %s", loaded.DraftConfig, created.DraftConfig) - } - updatedRaw := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"my-explorer","title":"Updated","description":"presentation survives","management":"interactive"},"recipe":{"recipeSchemaVersion":1,"name":"explorer-my-explorer","translationVersion":"interactive","outputs":[{"name":"DocumentReference","rootResourceType":"DocumentReference","rowGrain":"document_reference","fields":[{"name":"id","fieldRef":"DocumentReference.id","expr":{"select":"root.id"}}]}]},"views":[{"id":"main","title":"Main","output":"DocumentReference","rowLabel":"id","table":{"columns":[{"column":"id","label":"Identifier","visible":true}]}}],"sharedFilters":{"main":[{"output":"DocumentReference","column":"id"}]}}`) - _, _, _, nextDigest, err := CanonicalConfigV2(updatedRaw, "project-a", "my-explorer", "interactive") - if err != nil { - t.Fatal(err) - } - updated, err := service.SaveDraftV2(context.Background(), "project-a", "my-explorer", updatedRaw, 1, created.DraftDigest, "author") - if err != nil { - t.Fatal(err) - } - if updated.DraftVersion != 2 || updated.DraftDigest != nextDigest { - t.Fatalf("updated metadata = %#v", updated) - } - stale, err := service.SaveDraftV2(context.Background(), "project-a", "my-explorer", raw, 1, created.DraftDigest, "stale") - if err != nil { - t.Fatal(err) - } - if stale.DraftVersion != 3 || stale.DraftDigest == updated.DraftDigest || string(stale.DraftConfig) == string(updated.DraftConfig) { - t.Fatalf("last-write-wins draft = %#v", stale) - } -} - -func TestRepositoryConfigDoesNotFallBackToInteractiveDefault(t *testing.T) { - store := NewMemoryStore() - interactive := RepositoryConfig{Project: "project-a", ExplorerID: "default", Management: ManagementInteractive, SourceGeneration: "interactive-generation"} - repository := RepositoryConfig{Project: "project-a", ExplorerID: "default", Management: ManagementRepository, SourceGeneration: "repository-generation"} - if _, err := store.SaveConfig(context.Background(), interactive); err != nil { - t.Fatal(err) - } - if _, err := store.SaveRepositoryConfig(context.Background(), repository); err != nil { - t.Fatal(err) - } - got, err := store.GetRepositoryConfig(context.Background(), "project-a") - if err != nil { - t.Fatal(err) - } - if got.SourceGeneration != repository.SourceGeneration || got.Management != ManagementRepository { - t.Fatalf("repository config = %#v", got) - } -} diff --git a/internal/explorer/viewer_projection.go b/internal/explorer/viewer_projection.go new file mode 100644 index 00000000..4cb9e719 --- /dev/null +++ b/internal/explorer/viewer_projection.go @@ -0,0 +1,406 @@ +package explorer + +import ( + "encoding/json" + "sort" + "strings" + + "github.com/calypr/loom/internal/dataframe/publication" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataset" +) + +// buildViewerProjection is the single translation from immutable Explorer +// publication state to the renderer-facing contract. It intentionally does +// not require an authored ConfigView: a valid recipe is enough to produce a +// default table that a client can extend with presentation choices. +func buildViewerProjection(revision *Revision) *ExplorerRuntimeV1 { + if revision == nil { + return nil + } + + config, hasConfig := decodeProjectionConfig(revision.Config) + bundle := revision.Recipe + if len(bundle.Outputs) == 0 && hasConfig { + if parsed, err := recipe.Parse(config.Recipe); err == nil { + bundle = parsed + } + } + if len(bundle.Outputs) == 0 { + // A revision without a recipe is not an executable query. The caller + // still returns a valid ExplorerState response with runtime: null. + return nil + } + + datasetOutputs := make(map[string]DatasetOutput, len(revision.Dataset.Outputs)) + physicalColumns := make(map[string]map[string]publication.PhysicalColumn, len(revision.Dataset.Outputs)) + for _, output := range revision.Dataset.Outputs { + datasetOutputs[output.Name] = output + physicalColumns[output.Name] = make(map[string]publication.PhysicalColumn, len(output.Columns)) + for _, column := range output.Columns { + physicalColumns[output.Name][column.Name] = column + } + } + + materializations := make(map[string]Materialization, len(revision.Materializations)) + for _, materialization := range revision.Materializations { + outputID := firstNonEmptyString(materialization.OutputID, materialization.Output) + if outputID == "" { + continue + } + materializations[outputID] = materialization + if physicalColumns[outputID] == nil { + physicalColumns[outputID] = map[string]publication.PhysicalColumn{} + } + for _, column := range materialization.Columns { + physicalColumns[outputID][column.Name] = column + } + } + authoritativeColumns := make(map[string]bool, len(physicalColumns)) + for outputID, columns := range physicalColumns { + authoritativeColumns[outputID] = len(columns) > 0 + } + + emitted := make(map[string]map[string]EmittedColumn) + for _, column := range revision.EmittedColumns { + if column.OutputID == "" || column.PublicColumn == "" { + continue + } + if emitted[column.OutputID] == nil { + emitted[column.OutputID] = map[string]EmittedColumn{} + } + emitted[column.OutputID][column.PublicColumn] = column + // Emissions are a compatibility fallback for outputs whose publication + // metadata has no columns at all. Once DatasetMetadata or Materialization + // metadata supplies any column for an output, it is authoritative and + // historical emissions must not manufacture additional runtime columns. + if !authoritativeColumns[column.OutputID] { + if physicalColumns[column.OutputID] == nil { + physicalColumns[column.OutputID] = map[string]publication.PhysicalColumn{} + } + if _, exists := physicalColumns[column.OutputID][column.PublicColumn]; !exists { + physicalColumns[column.OutputID][column.PublicColumn] = publication.PhysicalColumn{ + Name: column.PublicColumn, + LogicalType: column.LogicalType, + ClickHouse: column.LogicalType, + } + } + } + } + // Labels are frozen by the public output contract. They are indexed by the + // authored physical column, never reconstructed from compiler identities. + contractLabels := map[string]map[string]string{} + if contracts, err := DecodePublicOutputContracts(revision.PublicOutputContract); err == nil { + for _, output := range contracts.Outputs { + contractLabels[output.OutputID] = map[string]string{} + for _, column := range output.Columns { + contractLabels[output.OutputID][column.Column] = column.Label + } + } + } + + status := firstNonEmptyString(revision.Publication.State, string(revision.Status), ExplorerRuntimeV1NotPublished) + publicationState := revision.Publication + publicationState.State = firstNonEmptyString(publicationState.State, status) + runtime := &ExplorerRuntimeV1{ + Status: status, + Generation: firstNonEmptyString(revision.Dataset.Generation, revision.SourceGeneration, revision.Publication.Generation), + Publication: publicationState, + Schema: ExplorerRuntimeSchemaV1{Digest: firstNonEmptyString(revision.Dataset.SchemaDigest, revision.ResolvedSchemaDigest), Version: ConfigV2APIVersion}, + Outputs: []ExplorerRuntimeOutputV1{}, + SharedFilters: map[string][]ExplorerRuntimeBindingV1{}, + FileActions: config.FileActions, + Diagnostics: append([]Diagnostic(nil), revision.Diagnostics...), + } + + views := config.Views + if !hasConfig || len(views) == 0 { + views = defaultProjectionViews(bundle) + } + for _, view := range views { + if view.Output == "" { + continue + } + selector, ok := projectionSelector(view.Output, datasetOutputs, materializations, bundle) + if !ok { + continue + } + + columnsByName := map[string]ExplorerRuntimeColumnV1{} + ensureColumn := func(name string) (ExplorerRuntimeColumnV1, bool) { + if existing, ok := columnsByName[name]; ok { + return existing, true + } + published, ok := physicalColumns[view.Output][name] + if !ok { + return ExplorerRuntimeColumnV1{}, false + } + emission := emitted[view.Output][name] + // Runtime is an intersection of compiler emissions and authoritative + // materialized columns. Physical schema metadata is never promoted into + // a user-visible column by itself. + if emission.PublicColumn == "" || strings.TrimSpace(emission.EmissionID) == "" { + return ExplorerRuntimeColumnV1{}, false + } + filterable, chartable := emission.Filterable, emission.Chartable + label := contractLabels[view.Output][name] + if strings.TrimSpace(label) == "" { + return ExplorerRuntimeColumnV1{}, false + } + column := ExplorerRuntimeColumnV1{ + Column: name, + EmissionID: name, + Name: name, + Label: label, + LogicalType: firstNonEmptyString(emission.LogicalType, published.LogicalType, published.ClickHouse, "string"), + Repeated: published.Repeated, + Filterable: filterable, + Sortable: !published.Repeated, + Chartable: chartable, + Aggregatable: filterable, + } + columnsByName[name] = column + return column, true + } + + ordered := []string{} + seen := map[string]bool{} + appendColumn := func(name string) { + if seen[name] { + return + } + if _, ok := ensureColumn(name); !ok { + return + } + seen[name] = true + ordered = append(ordered, name) + } + for _, binding := range view.Table.Columns { + appendColumn(binding.Column) + } + remaining := make([]string, 0, len(physicalColumns[view.Output])) + for name := range physicalColumns[view.Output] { + if !seen[name] { + remaining = append(remaining, name) + } + } + sort.Strings(remaining) + for _, name := range remaining { + appendColumn(name) + } + + table := ExplorerRuntimeTableV1{Columns: []ExplorerRuntimeTableColumnV1{}} + for index, binding := range view.Table.Columns { + column, ok := ensureColumn(binding.Column) + if !ok { + continue + } + column.Label = firstNonEmptyString(binding.Label, column.Label) + column.Visible, column.Order = binding.Visible, index + columnsByName[binding.Column] = column + table.Columns = append(table.Columns, ExplorerRuntimeTableColumnV1{Column: column.Column, EmissionID: column.Column, Visible: binding.Visible, Pinned: binding.Pinned, CellRenderer: binding.CellRenderer}) + } + columns := make([]ExplorerRuntimeColumnV1, 0, len(ordered)) + for index, name := range ordered { + column := columnsByName[name] + if len(view.Table.Columns) == 0 && !runtimeColumnIsInternal(name) { + column.Visible, column.Order = true, index + table.Columns = append(table.Columns, ExplorerRuntimeTableColumnV1{Column: column.Column, EmissionID: column.Column, Visible: true}) + } + columns = append(columns, column) + } + + bindings := func(values []ConfigFilter) []ExplorerRuntimeBindingV1 { + result := []ExplorerRuntimeBindingV1{} + for _, binding := range values { + if column, ok := ensureColumn(binding.Column); ok { + result = append(result, ExplorerRuntimeBindingV1{Column: column.Column, EmissionID: column.Column, OutputID: view.Output, Label: firstNonEmptyString(binding.Label, column.Label)}) + } + } + return result + } + charts := []ExplorerRuntimeBindingV1{} + for _, chart := range view.Charts { + if column, ok := ensureColumn(chart.Column); ok { + charts = append(charts, ExplorerRuntimeBindingV1{Column: column.Column, EmissionID: column.Column, OutputID: view.Output, Type: chart.Type, Title: chart.Title}) + } + } + fixed := map[string][]string{} + for name, values := range view.FixedFilters { + if column, ok := ensureColumn(name); ok { + fixed[column.Column] = append([]string(nil), values...) + } + } + output := ExplorerRuntimeOutputV1{ + OutputID: view.Output, + Name: firstNonEmptyString(view.ID, view.Output), + Title: firstNonEmptyString(view.Title, view.Output), + RowLabel: firstNonEmptyString(view.RowLabel, view.Title, view.Output), + Selector: selector, + Columns: columns, + Table: table, + Filters: bindings(view.Filters), + Charts: charts, + FixedFilters: fixed, + Actions: append([]ConfigAction(nil), view.Actions...), + } + if materialization, ok := materializations[view.Output]; ok { + copy := materialization + output.Materialization = © + } + runtime.Outputs = append(runtime.Outputs, output) + } + + for name, filters := range config.SharedFilters { + for _, filter := range filters { + if _, ok := emitted[filter.Output][filter.Column]; ok { + if _, published := physicalColumns[filter.Output][filter.Column]; published { + runtime.SharedFilters[name] = append(runtime.SharedFilters[name], ExplorerRuntimeBindingV1{Column: filter.Column, EmissionID: filter.Column, OutputID: filter.Output}) + } + } + } + } + + return runtime +} + +func decodeProjectionConfig(raw json.RawMessage) (ConfigV2, bool) { + if len(raw) == 0 { + return ConfigV2{}, false + } + var config ConfigV2 + if json.Unmarshal(raw, &config) != nil { + return ConfigV2{}, false + } + return config, true +} + +func defaultProjectionViews(bundle recipe.Bundle) []ConfigView { + views := make([]ConfigView, 0, len(bundle.Outputs)) + for _, output := range bundle.Outputs { + views = append(views, ConfigView{ID: output.Name, Title: output.Name, Output: output.Name}) + } + return views +} + +func projectionSelector(output string, datasetOutputs map[string]DatasetOutput, materializations map[string]Materialization, bundle recipe.Bundle) (dataset.DataframeSelector, bool) { + if value := datasetOutputs[output].Selector; value != nil && value.Validate() == nil { + return *value, true + } + if value := materializations[output].Selector; value != nil && value.Validate() == nil { + return *value, true + } + selector := dataset.DataframeSelector{Recipe: bundle.Name, TranslationVersion: bundle.TranslationVersion, Output: output} + return selector, selector.Validate() == nil +} + +func projectionAliases(emitted map[string]map[string]EmittedColumn, physicalColumns map[string]map[string]publication.PhysicalColumn) map[string]map[string]string { + aliases := map[string]map[string]string{} + for outputID, columns := range emitted { + for publicName := range columns { + matches := []string{} + for physicalName := range physicalColumns[outputID] { + if physicalName == publicName || strings.HasSuffix(physicalName, "_"+publicName) { + matches = append(matches, physicalName) + } + } + if len(matches) == 1 { + if aliases[outputID] == nil { + aliases[outputID] = map[string]string{} + } + aliases[outputID][publicName] = matches[0] + } + } + } + return aliases +} + +func emissionForPhysicalColumn(outputID, physical string, emitted map[string]map[string]EmittedColumn, aliases map[string]map[string]string) EmittedColumn { + publicNames := make([]string, 0, len(aliases[outputID])) + for publicName, physicalName := range aliases[outputID] { + if physicalName == physical { + publicNames = append(publicNames, publicName) + } + } + sort.Strings(publicNames) + for _, publicName := range publicNames { + if emission := emitted[outputID][publicName]; emission.PublicColumn != "" { + return emission + } + } + return EmittedColumn{} +} + +func recipeColumnLabels(bundle recipe.Bundle) map[string]map[string]string { + labels := map[string]map[string]string{} + var collect func(string, []recipe.Field, []recipe.Traversal) + collect = func(output string, fields []recipe.Field, traversals []recipe.Traversal) { + if labels[output] == nil { + labels[output] = map[string]string{} + } + for _, field := range fields { + if field.Name == "" { + continue + } + fieldRef := strings.TrimSpace(field.FieldRef) + if fieldRef == "" { + fieldRef = firstExpressionSelector(field.Expr) + } + if fieldRef != "" { + labels[output][field.Name] = humanizeFieldRef(fieldRef) + } + } + for _, traversal := range traversals { + collect(output, traversal.Fields, traversal.Traversals) + } + } + for _, output := range bundle.Outputs { + collect(output.Name, output.Fields, output.Traversals) + } + return labels +} + +func firstExpressionSelector(expr recipe.Expression) string { + if strings.TrimSpace(expr.Select) != "" { + return strings.TrimSpace(expr.Select) + } + for _, argument := range expr.Args { + if selector := firstExpressionSelector(argument); selector != "" { + return selector + } + } + return "" +} + +func humanizeFieldRef(fieldRef string) string { + value := strings.TrimSpace(fieldRef) + if index := strings.IndexByte(value, '.'); index >= 0 { + value = value[index+1:] + } + parts := strings.FieldsFunc(value, func(r rune) bool { return r == '.' || r == '_' || r == '-' || r == '[' || r == ']' }) + for index, part := range parts { + lower := strings.ToLower(part) + if lower == "id" || lower == "url" || lower == "uri" || lower == "uuid" { + parts[index] = strings.ToUpper(lower) + } else if part != "" { + parts[index] = strings.ToUpper(part[:1]) + part[1:] + } + } + if len(parts) == 0 { + return fieldRef + } + return strings.Join(parts, " ") +} + +func runtimeColumnIsInternal(name string) bool { + return name == "auth_resource_path" || strings.HasPrefix(name, "__loom_") +} + +func firstNonEmptyString(values ...string) string { + for _, value := range values { + if strings.TrimSpace(value) != "" { + return value + } + } + return "" +} diff --git a/internal/ingest/bench_test.go b/internal/ingest/bench_test.go index 3bc71cfa..494c32b5 100644 --- a/internal/ingest/bench_test.go +++ b/internal/ingest/bench_test.go @@ -215,8 +215,8 @@ func BenchmarkFieldCatalogProfiling(b *testing.B) { } b.Run("WithShapeCache", func(b *testing.B) { - cache := catalog.NewShapePlanCache() - profiler := catalog.NewProfilerForGeneration("BENCHMARK", "", "pathA", "Observation", cache) + cache := catalog.NewShapePlanCacheWithLimit(catalog.DefaultProfileLimits().MaxShapePlans) + profiler := catalog.NewProfilerForGenerationWithLimits("BENCHMARK", "", "pathA", "Observation", cache, catalog.DefaultProfileLimits()) timings := map[string]float64{} b.ResetTimer() for i := 0; i < b.N; i++ { @@ -232,8 +232,8 @@ func BenchmarkFieldCatalogProfiling(b *testing.B) { timings := map[string]float64{} b.ResetTimer() for i := 0; i < b.N; i++ { - cache := catalog.NewShapePlanCache() - profiler := catalog.NewProfilerForGeneration("BENCHMARK", "", "pathA", "Observation", cache) + cache := catalog.NewShapePlanCacheWithLimit(catalog.DefaultProfileLimits().MaxShapePlans) + profiler := catalog.NewProfilerForGenerationWithLimits("BENCHMARK", "", "pathA", "Observation", cache, catalog.DefaultProfileLimits()) var payload map[string]any if err := sonic.ConfigFastest.Unmarshal(lines[i%len(lines)], &payload); err != nil { b.Fatalf("decode payload: %v", err) diff --git a/internal/ingest/generation_load_test.go b/internal/ingest/generation_load_test.go index 2646c80e..d3905506 100644 --- a/internal/ingest/generation_load_test.go +++ b/internal/ingest/generation_load_test.go @@ -167,10 +167,10 @@ func TestGenerationLoadEmptyDirectoryDoesNotOpenBackend(t *testing.T) { } func TestSortedGenerationCatalogKeysKeepFullIdentityDistinct(t *testing.T) { - cache := catalog.NewShapePlanCache() + cache := catalog.NewShapePlanCacheWithLimit(catalog.DefaultProfileLimits().MaxShapePlans) keys := map[generationCatalogKey]*catalog.Profiler{ - {project: "project-a", datasetGeneration: "generation-b", authResourcePath: "scope-b", resourceType: "Patient"}: catalog.NewProfilerForGeneration("project-a", "generation-b", "scope-b", "Patient", cache), - {project: "project-a", datasetGeneration: "generation-a", authResourcePath: "scope-a", resourceType: "Patient"}: catalog.NewProfilerForGeneration("project-a", "generation-a", "scope-a", "Patient", cache), + {project: "project-a", datasetGeneration: "generation-b", authResourcePath: "scope-b", resourceType: "Patient"}: catalog.NewProfilerForGenerationWithLimits("project-a", "generation-b", "scope-b", "Patient", cache, catalog.DefaultProfileLimits()), + {project: "project-a", datasetGeneration: "generation-a", authResourcePath: "scope-a", resourceType: "Patient"}: catalog.NewProfilerForGenerationWithLimits("project-a", "generation-a", "scope-a", "Patient", cache, catalog.DefaultProfileLimits()), } sorted := sortedGenerationCatalogKeys(keys) if len(sorted) != 2 || sorted[0].datasetGeneration != "generation-a" || sorted[1].datasetGeneration != "generation-b" { diff --git a/internal/ingest/load_options_test.go b/internal/ingest/load_options_test.go index 53e77d20..c24c6a1e 100644 --- a/internal/ingest/load_options_test.go +++ b/internal/ingest/load_options_test.go @@ -21,17 +21,17 @@ func TestNormalizeLoadOptionsUsesBoundedConcurrencyDefaults(t *testing.T) { func TestNormalizeLoadOptionsPreservesExplicitConcurrencyAndCatalogLimits(t *testing.T) { got := normalizeLoadOptions(LoadOptions{ - WriterCount: 1, - WorkerCount: 1, - LineQueueSize: 32, + WriterCount: 1, + WorkerCount: 1, + LineQueueSize: 32, WriteQueueSize: 4, CatalogLimits: catalog.ProfileLimits{ - MaxFields: 4, - MaxDistinctValuesPerField: 2, - MaxDistinctValueBytes: 8, - MaxPivotColumnsPerField: 2, + MaxFields: 4, + MaxDistinctValuesPerField: 2, + MaxDistinctValueBytes: 8, + MaxPivotColumnsPerField: 2, MaxExtensionValuesPerField: 2, - MaxShapePlans: 1, + MaxShapePlans: 1, }, }) if got.WorkerCount != 1 || got.LineQueueSize != 32 || got.WriteQueueSize != 4 { diff --git a/internal/projectid/projectid.go b/internal/projectid/projectid.go index 207ae586..7a4df378 100644 --- a/internal/projectid/projectid.go +++ b/internal/projectid/projectid.go @@ -5,7 +5,6 @@ package projectid import ( - "fmt" "net/url" "strings" ) @@ -50,27 +49,3 @@ func Legacy(raw string) string { } return canonical } - -// Aliases returns canonical first, then legacy, without duplicates. It is -// useful for compatibility reads against records written before slash IDs. -func Aliases(raw string) []string { - canonical := Canonical(raw) - legacy := Legacy(canonical) - if canonical == "" { - return nil - } - if canonical == legacy { - return []string{canonical} - } - return []string{canonical, legacy} -} - -// RequireCanonical validates a project identity at a public API boundary. -func RequireCanonical(raw string) (string, error) { - canonical := Canonical(raw) - parts := strings.SplitN(canonical, "/", 2) - if len(parts) != 2 || parts[0] == "" || parts[1] == "" { - return "", fmt.Errorf("project must use program/project format") - } - return canonical, nil -} diff --git a/internal/projectid/projectid_test.go b/internal/projectid/projectid_test.go index 51f51807..3fa76556 100644 --- a/internal/projectid/projectid_test.go +++ b/internal/projectid/projectid_test.go @@ -16,20 +16,3 @@ func TestCanonicalAcceptsSlashAndLegacyIDs(t *testing.T) { } } } - -func TestAliasesPreserveLegacyStorageIdentity(t *testing.T) { - want := []string{"HTAN_INT/BForePC", "HTAN_INT-BForePC"} - got := Aliases("HTAN_INT/BForePC") - if len(got) != len(want) || got[0] != want[0] || got[1] != want[1] { - t.Fatalf("Aliases() = %#v, want %#v", got, want) - } -} - -func TestRequireCanonical(t *testing.T) { - if got, err := RequireCanonical("HTAN_INT-BForePC"); err != nil || got != "HTAN_INT/BForePC" { - t.Fatalf("RequireCanonical legacy = %q, %v", got, err) - } - if _, err := RequireCanonical("BForePC"); err == nil { - t.Fatal("RequireCanonical accepted project without program") - } -} diff --git a/internal/server/explorer_authoring_http.go b/internal/server/explorer_authoring_http.go new file mode 100644 index 00000000..3bb6fca0 --- /dev/null +++ b/internal/server/explorer_authoring_http.go @@ -0,0 +1,168 @@ +package server + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "log/slog" + "strings" + + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/explorer" + "github.com/gofiber/fiber/v3" +) + +func decodeAuthoringStrict(raw []byte, value any) error { + decoder := json.NewDecoder(bytes.NewReader(raw)) + decoder.DisallowUnknownFields() + if err := decoder.Decode(value); err != nil { + return err + } + var trailing any + if err := decoder.Decode(&trailing); err != io.EOF { + if err == nil { + return fmt.Errorf("multiple JSON values") + } + return err + } + return nil +} + +func authoringRead(c fiber.Ctx, authorizeRead explorerConfigReadAuthorizer) error { + if err := authorizeRead(c.Context(), principalFromFiber(c), explorerProjectParam(c)); err != nil { + return authoringHTTPError(c, &explorer.AuthoringError{Status: 403, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "authorization", Code: "FORBIDDEN", Message: "forbidden"}, Cause: err}) + } + return nil +} + +func authoringWrite(c fiber.Ctx, authorizer authscope.Authorizer) error { + project := explorerProjectParam(c) + path := authscope.NormalizeAuthResourcePath(strings.TrimSpace(c.Query("auth_resource_path"))) + if err := authorizer.AuthorizeWrite(c.Context(), principalFromFiber(c), project, path); err != nil { + return authoringHTTPError(c, &explorer.AuthoringError{Status: 403, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "authorization", Code: "FORBIDDEN", Message: "forbidden"}, Cause: err}) + } + return nil +} + +func requestIDFromFiber(c fiber.Ctx) string { + value, _ := c.Locals("request_id").(string) + return value +} + +func malformedRouteError(stage string, err error) error { + return &explorer.AuthoringError{Status: 400, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: "MALFORMED_AUTHORING_REQUEST", JSONPath: "$", Message: err.Error()}, Cause: err} +} + +func authoringSemanticRoute(stage, path, code, message string, details map[string]any) error { + return &explorer.AuthoringError{Status: 422, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: code, JSONPath: path, Message: message, Details: details}} +} + +func explorerConflict(stage, code, message string, details map[string]any) error { + return &explorer.AuthoringError{Status: 409, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: code, Message: message, Details: details}} +} + +func explorerUnavailable(stage, code, message string) error { + return &explorer.AuthoringError{Status: 503, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: code, Message: message}} +} + +func receiptHasOutput(bundle recipe.Bundle, id string) bool { + for _, output := range bundle.Outputs { + if output.Name == id { + return true + } + } + return false +} + +func authoringHTTPError(c fiber.Ctx, err error) error { + requestID := requestIDFromFiber(c) + var value *explorer.AuthoringError + if errors.As(err, &value) { + value.Diagnostic.RequestID = requestID + cause := value.Cause + if cause == nil { + cause = err + } + logAuthoringRequestFailure(c, requestID, value.Status, value.Diagnostic.Stage, value.Diagnostic.Code, value.Diagnostic.JSONPath, value.Diagnostic.Message, value.Diagnostic.Details, cause) + details := value.Diagnostic.Details + if details == nil { + details = map[string]any{} + } + diagnostic := fiber.Map{"severity": strings.ToLower(value.Diagnostic.Severity), "stage": value.Diagnostic.Stage, "code": value.Diagnostic.Code, "path": value.Diagnostic.JSONPath, "message": value.Diagnostic.Message, "requestId": requestID} + return c.Status(value.Status).JSON(fiber.Map{"code": value.Diagnostic.Code, "message": value.Diagnostic.Message, "diagnostics": []fiber.Map{diagnostic}, "requestId": requestID, "details": details}) + } + if errors.Is(err, explorer.ErrNotFound) { + return c.Status(404).JSON(fiber.Map{"code": "NOT_FOUND", "message": "Explorer resource not found", "diagnostics": []any{}, "requestId": requestID, "details": fiber.Map{}}) + } + logAuthoringRequestFailure(c, requestID, 500, "internal", "INTERNAL_ERROR", "", "internal server error", nil, err) + return c.Status(500).JSON(fiber.Map{"code": "INTERNAL_ERROR", "message": "internal server error", "diagnostics": []any{}, "requestId": requestID, "details": fiber.Map{}}) +} + +func logAuthoringRequestFailure(c fiber.Ctx, requestID string, status int, stage, code, jsonPath, message string, details map[string]any, cause error) { + attrs := []any{ + "request_id", requestID, + "method", c.Method(), + "path", c.Path(), + "status", status, + "project", explorerProjectParam(c), + "explorer_id", strings.TrimSpace(c.Params("explorerId")), + "stage", stage, + "code", code, + "json_path", jsonPath, + "message", message, + "details", details, + } + if cause != nil { + attrs = append(attrs, "cause", cause, "cause_type", fmt.Sprintf("%T", cause)) + } + slog.Error("Explorer authoring request failed", attrs...) +} + +func decodeStrict(raw []byte, value any) error { + decoder := json.NewDecoder(bytes.NewReader(raw)) + decoder.DisallowUnknownFields() + if err := decoder.Decode(value); err != nil { + return err + } + var trailing any + if err := decoder.Decode(&trailing); err == nil { + return fmt.Errorf("multiple JSON values") + } + return nil +} + +func principalFromFiber(c fiber.Ctx) *authscope.Principal { + principal, _ := c.Locals("principal").(*authscope.Principal) + return principal +} + +func subjectFromFiber(c fiber.Ctx) string { + if principal := principalFromFiber(c); principal != nil { + return principal.Subject + } + return "" +} + +func authorizeExplorerWrite(c fiber.Ctx, authorizer authscope.Authorizer, project string) error { + path := authscope.NormalizeAuthResourcePath(strings.TrimSpace(c.Query("auth_resource_path"))) + if err := authorizer.AuthorizeWrite(c.Context(), principalFromFiber(c), project, path); err != nil { + return explorerV2Error(c, 403, "FORBIDDEN", "forbidden") + } + return nil +} + +func explorerV2Error(c fiber.Ctx, status int, code, message string) error { + return c.Status(status).JSON(fiber.Map{"error": fiber.Map{"code": code, "message": message}}) +} + +func firstNonEmpty(values ...string) string { + for _, value := range values { + if strings.TrimSpace(value) != "" { + return value + } + } + return "Explorer" +} diff --git a/internal/server/explorer_authoring_migration.go b/internal/server/explorer_authoring_migration.go deleted file mode 100644 index e27bfa1b..00000000 --- a/internal/server/explorer_authoring_migration.go +++ /dev/null @@ -1,727 +0,0 @@ -package server - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "encoding/json" - "errors" - "fmt" - "sort" - "strings" - "time" - - "github.com/calypr/loom/internal/dataframe/recipe" - "github.com/calypr/loom/internal/explorer" - "github.com/calypr/loom/internal/explorer/bootstrap" - "github.com/calypr/loom/internal/projectid" -) - -// ExplorerAuthoringMigrationOptions describes the one-shot, server-side -// legacy cutover. It is intentionally not exposed as an HTTP operation. -type ExplorerAuthoringMigrationOptions struct { - Project string - ExplorerID string - Actor string - RequestID string - AuditOnly bool - // LegacyConfig and LegacyMapping are optional external migration inputs. - // When present they are used even if Loom has no existing Explorer record; - // the raw bytes are retained on the resulting immutable revision. - LegacyConfig []byte - LegacyMapping []byte -} - -type ExplorerAuthoringMigrationReport struct { - Mode string `json:"mode"` - Project string `json:"project"` - ExplorerID string `json:"explorerId"` - LegacyRevisionID string `json:"legacyRevisionId,omitempty"` - SourceGeneration string `json:"sourceGeneration"` - Source string `json:"source"` - IntentDigest string `json:"intentDigest"` - ReceiptID string `json:"receiptId"` - DraftVersion int64 `json:"draftVersion"` - PublicationID string `json:"publicationId"` - DocumentCount int `json:"documentCount"` - TabCount int `json:"tabCount"` - OutputCount int `json:"outputCount"` - MaterializationID string `json:"materializationId,omitempty"` - PersistedDocument bool `json:"persistedDocument"` - PublicationPolicy string `json:"publicationPolicy"` - DraftPersisted bool `json:"draftPersisted"` - Materialized bool `json:"materialized"` - DatasetActivated bool `json:"datasetActivated"` - ExplorerActivated bool `json:"explorerActivated"` - Diagnostics []string `json:"diagnostics,omitempty"` -} - -// MigrateLegacyExplorerAuthoring converts the active legacy default, compiles -// it with the current server resolver and, unless AuditOnly is set, -// materializes it and atomically stores and activates its immutable revision. -// Any conversion/resolution failure aborts the cutover. Migration never runs a -// global draft purge; unrelated Explorer authoring state is outside its scope. -func MigrateLegacyExplorerAuthoring(ctx context.Context, service *explorer.Service, capabilities ExplorerV2LifecycleConfig, options ExplorerAuthoringMigrationOptions) (ExplorerAuthoringMigrationReport, error) { - options.Project = projectid.Canonical(options.Project) - options.ExplorerID = strings.TrimSpace(options.ExplorerID) - if options.ExplorerID == "" { - options.ExplorerID = "default" - } - if options.Actor == "" { - options.Actor = "loom-authoring-migration" - } - if options.RequestID == "" { - options.RequestID = "loom-authoring-migration-" + options.Project + "-" + options.ExplorerID - } - if service == nil || capabilities.Catalog == nil || capabilities.ValidateReleaseGeneration == nil || capabilities.ActivateRelease == nil { - return ExplorerAuthoringMigrationReport{}, errors.New("Explorer authoring migration requires catalog, generation validator, and release activation") - } - if options.AuditOnly { - if capabilities.AuthoringCompile == nil { - return ExplorerAuthoringMigrationReport{}, errors.New("Explorer authoring migration audit requires the legacy intent compiler") - } - } else if capabilities.Capability == nil || capabilities.CompileReceipt == nil || capabilities.MaterializeReceipt == nil { - return ExplorerAuthoringMigrationReport{}, errors.New("Explorer authoring migration requires the native V2 capability compiler and receipt materializer") - } - - mode := "apply" - if options.AuditOnly { - mode = "audit" - } - report := ExplorerAuthoringMigrationReport{Mode: mode, Project: options.Project, ExplorerID: options.ExplorerID, PublicationPolicy: "LAST_WRITE_WINS", PersistedDocument: !options.AuditOnly} - owner, legacyConfig, err := migrationSource(ctx, service, options) - if err != nil { - return report, err - } - report.LegacyRevisionID = owner.ActiveRevisionID - - snapshot, err := capabilities.Catalog(ctx, options.Project, options.ExplorerID, "") - if err != nil { - return report, fmt.Errorf("load current authoring catalog: %w", err) - } - if !snapshot.Complete { - return report, fmt.Errorf("current authoring catalog is incomplete: %v", snapshot.Diagnostics) - } - report.SourceGeneration = snapshot.Generation - - var activeBundle json.RawMessage - var activeRevision *explorer.Revision - if owner.ActiveRevisionID != "" { - if storedRevision, revisionErr := service.Revision(ctx, owner.ActiveRevisionID); revisionErr == nil { - activeRevision = storedRevision - activeBundle = storedRevision.AuthoringBundle - } - } - var migrationDiagnostics []string - bundle, source, err := migrationBundleWithDiagnostics(legacyConfig, options.LegacyMapping, activeBundle, snapshot.Catalog, options.Project, options.ExplorerID, &migrationDiagnostics) - if err != nil { - return report, err - } - report.Source = source - report.Diagnostics = append(report.Diagnostics, migrationDiagnostics...) - report.DocumentCount = len(bundle.AuthoringDocuments()) - report.TabCount = len(bundle.AuthoringTabs()) - report.OutputCount = len(bundle.AuthoringDocuments()) - - var receipt explorer.CompilationReceipt - if options.AuditOnly { - compiled, compileErr := capabilities.AuthoringCompile(ctx, ExplorerAuthoringV1CompileRequest{Bundle: bundle, SnapshotToken: snapshot.Token, RequestID: options.RequestID}) - if compileErr != nil { - return report, fmt.Errorf("audit migrated Explorer authoring intent: %w", compileErr) - } - receipt = compiled.Receipt - } else { - capabilitySnapshot, capabilityErr := capabilities.Capability(ctx, options.Project, options.ExplorerID, snapshot.Generation) - if capabilityErr != nil { - return report, fmt.Errorf("load native V2 capability snapshot: %w", capabilityErr) - } - if !capabilitySnapshot.Usable() || capabilitySnapshot.Identity.Generation != snapshot.Generation { - return report, fmt.Errorf("native V2 capability snapshot does not match migration generation %q", snapshot.Generation) - } - wire := authoringV2Catalog(capabilitySnapshot, options.ExplorerID) - emitted := []explorer.EmittedColumn(nil) - if activeRevision != nil { - emitted = activeRevision.EmittedColumns - } - workspace, migrateErr := migrateV1WorkspaceToCapability(bundle, capabilitySnapshot, wire, emitted) - if migrateErr != nil { - return report, fmt.Errorf("convert stored V1 workspace to V2: %w", migrateErr) - } - compiled, compileErr := capabilities.CompileReceipt(ctx, ExplorerV2ReceiptCompileRequest{ - Project: options.Project, ExplorerID: options.ExplorerID, Workspace: workspace, - SnapshotToken: capabilitySnapshot.Token, RequestID: options.RequestID, - }) - if compileErr != nil { - return report, fmt.Errorf("compile migrated V2 workspace: %w", compileErr) - } - if compiled == nil { - return report, errors.New("compile migrated V2 workspace: compiler returned no receipt") - } - receipt = *compiled - } - report.IntentDigest, report.ReceiptID = receipt.IntentDigest, receipt.ID - if options.AuditOnly { - return report, nil - } - - report.DraftVersion, report.DraftPersisted = 0, false - - revisionID := "authoring_" + strings.TrimPrefix(receipt.ID, "receipt_") - if len(options.LegacyConfig) > 0 || len(options.LegacyMapping) > 0 { - // Keep an externally seeded migration distinct from a previously - // published authoring revision with the same executable receipt. This - // preserves the old revision for rollback while making a rerun with the - // same source inputs idempotent. - revisionID = migrationRevisionID(receipt.ID, options.LegacyConfig, options.LegacyMapping) - } - if active, activeErr := service.ActiveRevision(ctx, options.Project, options.ExplorerID); activeErr == nil && active.ID == revisionID { - report.PublicationID = revisionID - report.DatasetActivated, report.ExplorerActivated, report.Materialized = true, true, true - return report, nil - } - // Dataset lifecycle storage still uses the historical project alias. The - // authoring bundle/API stays canonical, but release validation, runtime - // bindings, and activation must use the storage identity or a valid active - // generation will be reported as missing. - storageProject := projectid.Legacy(receipt.Project) - if err := capabilities.ValidateReleaseGeneration(ctx, storageProject, receipt.SourceGeneration); err != nil { - return report, fmt.Errorf("validate migrated Explorer generation: %w", err) - } - execution, err := capabilities.MaterializeReceipt(ctx, &receipt, recipe.RuntimeBindings{Project: storageProject, DatasetGeneration: receipt.SourceGeneration}) - if err != nil { - return report, fmt.Errorf("materialize migrated Explorer receipt: %w", err) - } - if err := verifyQueryableOutputs(receipt.Bundle, execution); err != nil { - return report, fmt.Errorf("validate migrated Explorer materialization: %w", err) - } - report.MaterializationID, report.Materialized = execution.ID, true - materializations := explorerMaterializations(receipt.Bundle, execution) - datasetMetadata := datasetMetadataFromExecution(receipt.Bundle, receipt.SourceGeneration, execution.ResolvedSchemaDigest, execution) - publication := explorer.PublicationMetadata{State: string(explorer.RevisionReady), Generation: receipt.SourceGeneration, ExecutionID: execution.ID, UpdatedAt: time.Now().UTC()} - now := time.Now().UTC() - revision := explorer.Revision{ - ID: revisionID, Project: receipt.Project, ExplorerID: receipt.ExplorerID, - Config: receipt.CompiledConfig, ConfigDigest: receipt.IntentDigest, - AuthoringBundle: receipt.NormalizedBundle, IntentDigest: receipt.IntentDigest, - CompilationReceiptID: receipt.ID, Recipe: receipt.Bundle, RecipeDigest: receipt.RecipeDigest, - ResolvedSchemaDigest: receipt.ResolvedSchemaDigest, SourceGeneration: receipt.SourceGeneration, - Materializations: materializations, EmittedColumns: receipt.EmittedColumns, - Dataset: datasetMetadata, Publication: publication, Status: explorer.RevisionReady, - CreatedBy: options.Actor, CreatedAt: now, ReadyAt: &now, - Migration: migrationMetadata(options, legacyConfig, source), - } - if err := capabilities.ActivateRelease(ctx, storageProject, receipt.SourceGeneration, selectorsForBundle(receipt.Bundle)); err != nil { - return report, fmt.Errorf("activate migrated dataset release: %w", err) - } - report.DatasetActivated = true - published, err := service.PublishAuthoring(ctx, receipt, revision) - if err != nil { - return report, fmt.Errorf("atomically persist and activate migrated Explorer revision: %w", err) - } - report.PublicationID = published.ID - report.ExplorerActivated = true - return report, nil -} - -func migrationSource(ctx context.Context, service *explorer.Service, options ExplorerAuthoringMigrationOptions) (*explorer.Explorer, []byte, error) { - project := projectid.Canonical(options.Project) - owner, err := service.Get(ctx, project, options.ExplorerID) - if errors.Is(err, explorer.ErrNotFound) && (len(options.LegacyConfig) > 0 || len(options.LegacyMapping) > 0) { - title := migrationTitle(options.LegacyConfig, options.LegacyMapping) - owner, err = service.EnsureRepositoryExplorer(ctx, project, options.ExplorerID, title, options.Actor) - } - if err != nil { - return nil, nil, fmt.Errorf("load legacy Explorer state: %w", err) - } - legacyConfig := append([]byte(nil), options.LegacyConfig...) - if len(legacyConfig) == 0 { - legacyConfig = owner.ActiveConfig - } - if owner.ActiveRevisionID != "" { - if revision, revisionErr := service.Revision(ctx, owner.ActiveRevisionID); revisionErr == nil && len(revision.Config) > 0 { - if len(options.LegacyConfig) == 0 { - legacyConfig = revision.Config - } - } - } - if len(legacyConfig) == 0 && len(options.LegacyMapping) == 0 { - return nil, nil, errors.New("legacy Explorer has no active document") - } - return owner, legacyConfig, nil -} - -func migrationBundle(rawConfig, rawMapping, existingBundle json.RawMessage, catalog explorer.Catalog, project, explorerID string) (explorer.ExplorerAuthoringBundleV1, string, error) { - return migrationBundleWithDiagnostics(rawConfig, rawMapping, existingBundle, catalog, project, explorerID, nil) -} - -func migrationBundleWithDiagnostics(rawConfig, rawMapping, existingBundle json.RawMessage, catalog explorer.Catalog, project, explorerID string, diagnostics *[]string) (explorer.ExplorerAuthoringBundleV1, string, error) { - // Explicit migration inputs always win over whatever happens to be active - // in Loom. When both inputs are supplied, the legacy config is the source - // of field intent and the mapping is only a starting point: old mapping - // exports can contain an output with an empty candidate list even though - // the current catalog contains exact matches for its recipe fields. - if len(rawConfig) > 0 { - bundle, conversionReport, err := bootstrap.ConvertDefault(rawConfig, catalog, project) - if err == nil { - if bundle.ExplorerID != explorerID { - return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", fmt.Errorf("converted bundle explorerId %q does not match %q", bundle.ExplorerID, explorerID) - } - return bundle, "legacy-config", nil - } - if len(rawMapping) > 0 { - mapped, mappingErr := mappingAuthoringBundle(rawMapping, project, explorerID) - if mappingErr == nil { - repaired, repairDiagnostics, repairErr := repairMappedBundle(rawConfig, mapped, catalog, project, explorerID) - if repairErr == nil { - // Preserve explicit information about legacy fields that the - // current catalog does not expose. They are not guessed into a - // different field, but the migrated outputs must still contain - // every candidate that can be resolved and compiled. - if diagnostics != nil { - *diagnostics = append(*diagnostics, repairDiagnostics...) - } - return repaired, "frontend-mapping-repaired", nil - } - if conversionReportJSON, marshalErr := conversionReport.CanonicalJSON(); marshalErr == nil { - return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", fmt.Errorf("typed legacy Explorer conversion failed: %s: %w; mapping repair also failed: %v", conversionReportJSON, err, repairErr) - } - return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", fmt.Errorf("typed legacy Explorer conversion failed: %w; mapping repair also failed: %v", err, repairErr) - } - if conversionReportJSON, marshalErr := conversionReport.CanonicalJSON(); marshalErr == nil { - return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", fmt.Errorf("typed legacy Explorer conversion failed: %s: %w; decode frontend authoring mapping: %v", conversionReportJSON, err, mappingErr) - } - return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", fmt.Errorf("typed legacy Explorer conversion failed: %w; decode frontend authoring mapping: %v", err, mappingErr) - } - if conversionReportJSON, marshalErr := conversionReport.CanonicalJSON(); marshalErr == nil { - return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", fmt.Errorf("typed legacy Explorer conversion failed: %s: %w", conversionReportJSON, err) - } - return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", err - } - if len(rawMapping) > 0 { - bundle, err := mappingAuthoringBundle(rawMapping, project, explorerID) - if err != nil { - return explorer.ExplorerAuthoringBundleV1{}, "frontend-mapping", fmt.Errorf("decode frontend authoring mapping: %w", err) - } - return bundle, "frontend-mapping", nil - } - if len(existingBundle) > 0 { - bundle, err := explorer.DecodeAuthoringBundleV1ForMigration(existingBundle) - if err == nil && bundle.Project == project && bundle.ExplorerID == explorerID { - return bundle, "active-v1-bundle", nil - } - } - bundle, conversionReport, err := bootstrap.ConvertDefault(rawConfig, catalog, project) - if err != nil { - if conversionReportJSON, marshalErr := conversionReport.CanonicalJSON(); marshalErr == nil { - return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", fmt.Errorf("typed legacy Explorer conversion failed: %s: %w", conversionReportJSON, err) - } - return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", err - } - if bundle.ExplorerID != explorerID { - return explorer.ExplorerAuthoringBundleV1{}, "legacy-config", fmt.Errorf("converted bundle explorerId %q does not match %q", bundle.ExplorerID, explorerID) - } - return bundle, "legacy-config", nil -} - -func mappingAuthoringBundle(raw []byte, project, explorerID string) (explorer.ExplorerAuthoringBundleV1, error) { - var envelope struct { - Bundle json.RawMessage `json:"bundle"` - } - if err := json.Unmarshal(raw, &envelope); err != nil { - return explorer.ExplorerAuthoringBundleV1{}, err - } - if len(envelope.Bundle) == 0 { - return explorer.ExplorerAuthoringBundleV1{}, errors.New("mapping does not contain a bundle") - } - bundle, err := explorer.DecodeAuthoringBundleV1ForMigration(envelope.Bundle) - if err != nil { - return explorer.ExplorerAuthoringBundleV1{}, err - } - if projectid.Canonical(bundle.Project) != projectid.Canonical(project) || bundle.ExplorerID != explorerID { - return explorer.ExplorerAuthoringBundleV1{}, fmt.Errorf("mapping identity %q/%q does not match %q/%q", bundle.Project, bundle.ExplorerID, project, explorerID) - } - bundle.Project = projectid.Canonical(project) - bundle.IntentDigest = "" - digest, err := bundle.DocumentDigest() - if err != nil { - return explorer.ExplorerAuthoringBundleV1{}, err - } - bundle.IntentDigest = digest - return bundle, nil -} - -// repairMappedBundle fills gaps in a frontend mapping export from the legacy -// recipe and the current Loom catalog. Mapping exports are useful migration -// hints, but they are not authoritative: older exports were able to persist a -// graph and an output while dropping all candidate IDs for that output. The -// authoring compiler cannot invent those IDs, so an empty list would compile -// into an empty column set forever. -// -// The repair deliberately resolves only explicit legacy selections. A legacy -// call such as first(root.identifier[].value) still names an exact catalog -// field and is therefore repaired from its nested select. Calls with multiple -// selections contribute each exact catalog candidate; no opaque field is -// guessed or silently replaced. -func repairMappedBundle(rawConfig []byte, bundle explorer.ExplorerAuthoringBundleV1, catalog explorer.Catalog, project, explorerID string) (explorer.ExplorerAuthoringBundleV1, []string, error) { - if len(rawConfig) == 0 { - return bundle, nil, nil - } - cfg, legacy, err := explorer.DecodeDefaultConfigV2(rawConfig, project) - if err != nil { - return explorer.ExplorerAuthoringBundleV1{}, nil, fmt.Errorf("decode legacy config for mapping repair: %w", err) - } - documents := bundle.AuthoringDocuments() - if len(documents) == 0 { - return explorer.ExplorerAuthoringBundleV1{}, nil, errors.New("mapping bundle contains no authoring documents") - } - nodeByResource := make(map[string]string, len(catalog.Nodes)) - for _, node := range catalog.Nodes { - if prior, exists := nodeByResource[node.ResourceType]; exists && prior != node.ID { - return explorer.ExplorerAuthoringBundleV1{}, nil, fmt.Errorf("catalog has multiple node IDs for resource type %q", node.ResourceType) - } - nodeByResource[node.ResourceType] = node.ID - } - selectionByID := catalog.Selections - unmapped := make([]string, 0) - for outputIndex, output := range legacy.Outputs { - documentIndex := mappedDocumentIndex(documents, output.Name) - if documentIndex < 0 { - return explorer.ExplorerAuthoringBundleV1{}, nil, fmt.Errorf("mapping bundle has no document for legacy output %q", output.Name) - } - document := &documents[documentIndex] - if strings.TrimSpace(document.BaseNodeID) == "" { - document.BaseNodeID = nodeByResource[output.RootResourceType] - } - if document.BaseNodeID == "" { - return explorer.ExplorerAuthoringBundleV1{}, nil, fmt.Errorf("legacy output %q has no catalog node for resource type %q", output.Name, output.RootResourceType) - } - if strings.TrimSpace(document.RowNodeID) == "" { - document.RowNodeID = document.BaseNodeID - } - // Preserve existing valid IDs, but remove stale IDs before adding IDs - // resolved from the current catalog. This makes reruns safe across - // catalog generations and prevents a stale mapping from poisoning the - // one-shot compile with STALE_CANDIDATE. - valid := make([]string, 0, len(document.CandidateIDs)) - seen := make(map[string]bool, len(document.CandidateIDs)) - fieldCandidates := make(map[string][]string, len(output.Fields)) - for _, candidateID := range document.CandidateIDs { - selection, ok := selectionByID[candidateID] - if !ok || selection.NodeID != document.BaseNodeID || seen[candidateID] { - continue - } - seen[candidateID] = true - valid = append(valid, candidateID) - } - for _, reference := range document.CandidateOccurrences { - if reference.OccurrenceID != "base" || seen[reference.CandidateID] { - continue - } - selection, ok := selectionByID[reference.CandidateID] - if ok && selection.NodeID == document.BaseNodeID { - seen[reference.CandidateID] = true - valid = append(valid, reference.CandidateID) - } - } - for fieldIndex, field := range output.Fields { - paths := legacySelectionPaths(field.Expr) - if len(paths) == 0 { - unmapped = append(unmapped, fmt.Sprintf("outputs[%d].fields[%d].expr", outputIndex, fieldIndex)) - continue - } - matched := false - for _, path := range paths { - candidateID, ok := catalogCandidateForPath(catalog, document.BaseNodeID, path) - if !ok { - continue - } - matched = true - if !containsString(fieldCandidates[field.Name], candidateID) { - fieldCandidates[field.Name] = append(fieldCandidates[field.Name], candidateID) - } - if !seen[candidateID] { - seen[candidateID] = true - valid = append(valid, candidateID) - } - } - if !matched { - unmapped = append(unmapped, fmt.Sprintf("outputs[%d].fields[%d].%s", outputIndex, fieldIndex, field.Name)) - } - } - if len(valid) == 0 { - return explorer.ExplorerAuthoringBundleV1{}, nil, fmt.Errorf("legacy output %q has no fields that resolve against the current catalog", output.Name) - } - sort.Strings(valid) - document.CandidateIDs = valid - // Presentation keys are emission identities and therefore change when a - // legacy candidate/node identity is rebound. Retain only bindings that - // already name a current base emission; the legacy view below restores - // labels, order, visibility, filters, and charts under canonical IDs. - canonicalPresentation := make(map[string]explorer.ExplorerPresentationBindingV1, len(valid)) - for _, candidateID := range valid { - emissionID := explorer.OpaqueID("em_", document.Output.ID+"\x00base\x00"+candidateID) - if binding, ok := document.Presentation[emissionID]; ok { - canonicalPresentation[emissionID] = binding - } - } - document.Presentation = canonicalPresentation - // The canonical authoring contract always records the exact occurrence - // for every selected candidate, including the zero-hop base occurrence. - // Legacy inference is confined to this migration and never runs while the - // Builder is reading or reconciling an already-migrated bundle. - occurrences := make([]explorer.ExplorerCandidateOccurrenceV1, 0, len(valid)) - for _, candidateID := range valid { - occurrences = append(occurrences, explorer.ExplorerCandidateOccurrenceV1{CandidateID: candidateID, OccurrenceID: "base"}) - } - document.CandidateOccurrences = occurrences - repairDocumentPresentation(cfg.Views, output, document, fieldCandidates, &unmapped) - } - bundle.Document = explorer.ExplorerBuilderDocumentV1{} - bundle.Documents = documents - bundle.Project = projectid.Canonical(project) - bundle.ExplorerID = explorerID - bundle.IntentDigest = "" - digest, err := bundle.DocumentDigest() - if err != nil { - return explorer.ExplorerAuthoringBundleV1{}, nil, fmt.Errorf("digest repaired authoring bundle: %w", err) - } - bundle.IntentDigest = digest - return bundle, unmapped, nil -} - -func repairDocumentPresentation(views []explorer.ConfigView, output recipe.Output, document *explorer.ExplorerBuilderDocumentV1, fieldCandidates map[string][]string, diagnostics *[]string) { - if document.Presentation == nil { - document.Presentation = map[string]explorer.ExplorerPresentationBindingV1{} - } - aliases := make(map[string][]string) - for fieldName, candidateIDs := range fieldCandidates { - if len(candidateIDs) != 1 { - continue - } - emissionID := explorer.OpaqueID("em_", document.Output.ID+"\x00base\x00"+candidateIDs[0]) - for _, alias := range []string{ - fieldName, - output.Name + fieldName, - output.RootResourceType + fieldName, - document.Output.Title + fieldName, - } { - key := normalizeLegacyColumnAlias(alias) - if key != "" && !containsString(aliases[key], emissionID) { - aliases[key] = append(aliases[key], emissionID) - } - } - } - resolve := func(column string) (string, bool) { - matches := aliases[normalizeLegacyColumnAlias(column)] - return firstUniqueString(matches) - } - for viewIndex, view := range views { - if !strings.EqualFold(strings.TrimSpace(view.Output), strings.TrimSpace(output.Name)) { - continue - } - for columnIndex, column := range view.Table.Columns { - emissionID, ok := resolve(column.Column) - if !ok { - if hasPresentationTableOrder(document.Presentation, columnIndex) { - continue - } - *diagnostics = append(*diagnostics, fmt.Sprintf("views[%d].table.columns[%d].%s", viewIndex, columnIndex, column.Column)) - continue - } - binding := document.Presentation[emissionID] - if strings.TrimSpace(binding.Label) == "" { - binding.Label = firstNonEmpty(column.Label, column.Column) - } - if binding.Visible == nil { - visible := column.Visible - binding.Visible = &visible - } - if binding.Order == nil { - order := columnIndex - binding.Order = &order - } - if binding.Table == nil { - binding.Table = &explorer.ExplorerTableBindingV1{} - } - document.Presentation[emissionID] = binding - } - for filterIndex, filter := range view.Filters { - emissionID, ok := resolve(filter.Column) - if !ok { - if presentationBindingCount(document.Presentation, "filter") > filterIndex { - continue - } - *diagnostics = append(*diagnostics, fmt.Sprintf("views[%d].filters[%d].%s", viewIndex, filterIndex, filter.Column)) - continue - } - binding := document.Presentation[emissionID] - if binding.Filter == nil { - binding.Filter = &explorer.ExplorerFilterBindingV1{Label: filter.Label} - } - document.Presentation[emissionID] = binding - } - for chartIndex, chart := range view.Charts { - emissionID, ok := resolve(chart.Column) - if !ok { - if presentationBindingCount(document.Presentation, "chart") > chartIndex { - continue - } - *diagnostics = append(*diagnostics, fmt.Sprintf("views[%d].charts[%d].%s", viewIndex, chartIndex, chart.Column)) - continue - } - binding := document.Presentation[emissionID] - if binding.Chart == nil { - binding.Chart = &explorer.ExplorerChartBindingV1{Type: chart.Type, Title: chart.Title} - } - document.Presentation[emissionID] = binding - } - } -} - -func hasPresentationTableOrder(presentation map[string]explorer.ExplorerPresentationBindingV1, order int) bool { - for _, binding := range presentation { - if binding.Table != nil && binding.Order != nil && *binding.Order == order { - return true - } - } - return false -} - -func presentationBindingCount(presentation map[string]explorer.ExplorerPresentationBindingV1, kind string) int { - count := 0 - for _, binding := range presentation { - if kind == "filter" && binding.Filter != nil || kind == "chart" && binding.Chart != nil { - count++ - } - } - return count -} - -func normalizeLegacyColumnAlias(value string) string { - var normalized strings.Builder - for _, character := range strings.ToLower(strings.TrimSpace(value)) { - if character >= 'a' && character <= 'z' || character >= '0' && character <= '9' { - normalized.WriteRune(character) - } - } - return normalized.String() -} - -func firstUniqueString(values []string) (string, bool) { - if len(values) != 1 { - return "", false - } - return values[0], true -} - -func mappedDocumentIndex(documents []explorer.ExplorerBuilderDocumentV1, output string) int { - stable := explorer.StableExplorerID(output) - for index, document := range documents { - if document.Output.ID == stable || strings.EqualFold(document.Output.ID, output) || strings.EqualFold(document.Output.Title, output) { - return index - } - } - return -1 -} - -func legacySelectionPaths(expression recipe.Expression) []string { - paths := make([]string, 0, 1) - var walk func(recipe.Expression) - walk = func(current recipe.Expression) { - if strings.TrimSpace(current.Select) != "" { - path := strings.TrimSpace(current.Select) - if !containsString(paths, path) { - paths = append(paths, path) - } - } - for _, argument := range current.Args { - walk(argument) - } - } - walk(expression) - return paths -} - -func catalogCandidateForPath(catalog explorer.Catalog, nodeID, path string) (string, bool) { - want := normalizeCatalogSelectionPath(path) - for candidateID, selection := range catalog.Selections { - if selection.NodeID != nodeID || normalizeCatalogSelectionPath(selection.Select) != want { - continue - } - return candidateID, true - } - return "", false -} - -func normalizeCatalogSelectionPath(path string) string { - path = strings.TrimSpace(path) - if strings.HasPrefix(path, "root.") { - path = strings.TrimPrefix(path, "root.") - } - return strings.ToLower(strings.ReplaceAll(path, "[]", "")) -} - -func containsString(values []string, value string) bool { - for _, candidate := range values { - if candidate == value { - return true - } - } - return false -} - -func migrationTitle(config, mapping []byte) string { - var mappingEnvelope struct { - Title string `json:"title"` - Bundle struct { - Title string `json:"title"` - } `json:"bundle"` - } - if len(mapping) > 0 && json.Unmarshal(mapping, &mappingEnvelope) == nil { - if strings.TrimSpace(mappingEnvelope.Title) != "" { - return mappingEnvelope.Title - } - if strings.TrimSpace(mappingEnvelope.Bundle.Title) != "" { - return mappingEnvelope.Bundle.Title - } - } - var envelope struct { - Explorer struct { - Title string `json:"title"` - } `json:"explorer"` - } - if len(config) > 0 && json.Unmarshal(config, &envelope) == nil && strings.TrimSpace(envelope.Explorer.Title) != "" { - return envelope.Explorer.Title - } - return "Explorer" -} - -func migrationMetadata(options ExplorerAuthoringMigrationOptions, originalConfig []byte, source string) *explorer.MigrationMetadata { - metadata := &explorer.MigrationMetadata{ - Kind: "ExplorerAuthoringMigration", - Source: source, - SourceProject: projectid.Canonical(options.Project), - SourceExplorerID: options.ExplorerID, - OriginalConfig: append([]byte(nil), originalConfig...), - OriginalMapping: append([]byte(nil), options.LegacyMapping...), - Actor: options.Actor, - RequestID: options.RequestID, - MigratedAt: time.Now().UTC(), - } - metadata.OriginalConfigDigest = rawDigest(originalConfig) - metadata.OriginalMappingDigest = rawDigest(options.LegacyMapping) - return metadata -} - -func rawDigest(raw []byte) string { - if len(raw) == 0 { - return "" - } - sum := sha256.Sum256(raw) - return "sha256:" + hex.EncodeToString(sum[:]) -} - -func migrationRevisionID(receiptID string, config, mapping []byte) string { - sum := sha256.Sum256([]byte(receiptID + "\x00" + rawDigest(config) + "\x00" + rawDigest(mapping))) - return "authoring_migration_" + hex.EncodeToString(sum[:]) -} diff --git a/internal/server/explorer_authoring_migration_test.go b/internal/server/explorer_authoring_migration_test.go deleted file mode 100644 index 296bf3de..00000000 --- a/internal/server/explorer_authoring_migration_test.go +++ /dev/null @@ -1,296 +0,0 @@ -package server - -import ( - "context" - "encoding/json" - "testing" - - graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" - "github.com/calypr/loom/internal/dataframe/recipe" - "github.com/calypr/loom/internal/dataset" - "github.com/calypr/loom/internal/explorer" - "github.com/calypr/loom/internal/explorer/authoringv2" - "github.com/calypr/loom/internal/explorer/capability" -) - -func TestMappingAuthoringBundleCanonicalizesIdentityAndDigest(t *testing.T) { - input := map[string]any{ - "title": "BForePC", - "bundle": map[string]any{ - "apiVersion": explorer.ExplorerAuthoringV1APIVersion, - "kind": explorer.ExplorerAuthoringV1Kind, - "project": "HTAN_INT%2FBForePC", - "explorerId": "default", - "title": "BForePC", - "documents": []any{map[string]any{ - "kind": "ExplorerBuilderDocument", - "output": map[string]any{"id": "groupmember", "title": "GroupMember"}, - "baseNodeId": "n_group", - "rowNodeId": "n_group", - }}, - }, - } - raw, err := json.Marshal(input) - if err != nil { - t.Fatal(err) - } - bundle, err := mappingAuthoringBundle(raw, "HTAN_INT/BForePC", "default") - if err != nil { - t.Fatal(err) - } - if bundle.Project != "HTAN_INT/BForePC" || bundle.ExplorerID != "default" || bundle.IntentDigest == "" { - t.Fatalf("unexpected canonical bundle: %#v", bundle) - } - if err := bundle.Validate(); err != nil { - t.Fatalf("canonical bundle does not validate: %v", err) - } -} - -func TestMigrationSourceCreatesMissingRepositoryIdentityAndPreservesExternalConfig(t *testing.T) { - store := explorer.NewMemoryStore() - service, err := explorer.NewService(store) - if err != nil { - t.Fatal(err) - } - rawConfig := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"HTAN_INT-BForePC","explorer":{"id":"default","title":"BForePC","management":"repository"},"unknownFrontendField":{"preserve":true}}`) - owner, config, err := migrationSource(context.Background(), service, ExplorerAuthoringMigrationOptions{ - Project: "HTAN_INT%252FBForePC", ExplorerID: "default", Actor: "test", LegacyConfig: rawConfig, - }) - if err != nil { - t.Fatal(err) - } - if owner.Project != "HTAN_INT-BForePC" || owner.ExplorerID != "default" || owner.Title != "BForePC" { - t.Fatalf("unexpected seeded owner: %#v", owner) - } - if string(config) != string(rawConfig) { - t.Fatalf("migration did not preserve original config bytes") - } - if _, err := service.Get(context.Background(), "HTAN_INT/BForePC", "default"); err != nil { - t.Fatalf("seeded repository identity is not discoverable: %v", err) - } -} - -func TestMigrationSourceCanSeedFromMappingWithoutLegacyConfig(t *testing.T) { - store := explorer.NewMemoryStore() - service, err := explorer.NewService(store) - if err != nil { - t.Fatal(err) - } - rawMapping := []byte(`{"title":"BForePC","bundle":{"apiVersion":"loom.calypr.org/explorer-authoring/v1","kind":"ExplorerAuthoringBundle","project":"HTAN_INT/BForePC","explorerId":"default","title":"BForePC","documents":[]}}`) - owner, config, err := migrationSource(context.Background(), service, ExplorerAuthoringMigrationOptions{ - Project: "HTAN_INT/BForePC", ExplorerID: "default", Actor: "test", LegacyMapping: rawMapping, - }) - if err != nil { - t.Fatal(err) - } - if owner.Project != "HTAN_INT-BForePC" || owner.Title != "BForePC" { - t.Fatalf("unexpected seeded owner: %#v", owner) - } - if len(config) != 0 { - t.Fatalf("mapping-only migration unexpectedly returned a legacy config: %q", config) - } -} - -func TestMigrationBundlePrefersExplicitLegacyConfigOverActiveBundle(t *testing.T) { - rawConfig := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Default","management":"repository"},"recipe":{"recipeSchemaVersion":1,"name":"legacy","translationVersion":"v1","outputs":[{"name":"patient","rootResourceType":"Patient","rowGrain":"patient","fields":[{"name":"id","fieldRef":"Patient.id","expr":{"select":"root.id"}}]}]},"views":[]}`) - catalog := explorer.Catalog{Nodes: []explorer.CatalogNode{{ID: "n_patient", ResourceType: "Patient"}}, Selections: map[string]explorer.CatalogSelection{ - "s_patient_id": {ID: "s_patient_id", NodeID: "n_patient", FieldRef: "Patient.id", Select: "id"}, - }} - active := explorer.ExplorerAuthoringBundleV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, Project: "project-a", ExplorerID: "default", Documents: []explorer.ExplorerBuilderDocumentV1{{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "old"}, BaseNodeID: "n_patient", RowNodeID: "n_patient"}}} - bundle, source, err := migrationBundle(rawConfig, nil, mustAuthoringJSON(t, active), catalog, "project-a", "default") - if err != nil { - t.Fatal(err) - } - if source != "legacy-config" || len(bundle.AuthoringDocuments()) != 1 || bundle.AuthoringDocuments()[0].Output.ID != "patient" { - t.Fatalf("explicit config was not selected: source=%q bundle=%#v", source, bundle) - } -} - -func TestMigrationBundleRepairsEmptyMappingCandidatesFromLegacyConfig(t *testing.T) { - rawConfig := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Default","management":"repository"},"recipe":{"recipeSchemaVersion":1,"name":"legacy","translationVersion":"v1","outputs":[{"name":"DocumentReference","rootResourceType":"DocumentReference","rowGrain":"file","fields":[{"name":"id","expr":{"select":"root.id"}},{"name":"url","expr":{"call":"first","args":[{"select":"root.content[].attachment.url"}]}}]}]},"views":[{"id":"file","title":"Files","output":"DocumentReference","table":{"columns":[{"column":"document_reference_id","label":"Identifier","visible":true},{"column":"document_reference_url","label":"URL","visible":false},{"column":"project_id","label":"Project","visible":true}]}}]}`) - mappingBundle := explorer.ExplorerAuthoringBundleV1{ - APIVersion: explorer.ExplorerAuthoringV1APIVersion, - Kind: explorer.ExplorerAuthoringV1Kind, - Project: "project-a", - ExplorerID: "default", - Title: "Default", - Documents: []explorer.ExplorerBuilderDocumentV1{{ - Kind: explorer.ExplorerBuilderV1Kind, - Output: explorer.ExplorerOutputIdentityV1{ID: "file", Title: "DocumentReference"}, - BaseNodeID: "n_document", - RowNodeID: "n_document", - }}, - } - rawMapping, err := json.Marshal(map[string]any{"bundle": mappingBundle}) - if err != nil { - t.Fatal(err) - } - catalog := explorer.Catalog{ - Nodes: []explorer.CatalogNode{{ID: "n_document", ResourceType: "DocumentReference"}}, - Selections: map[string]explorer.CatalogSelection{ - "s_document_id": {ID: "s_document_id", NodeID: "n_document", FieldRef: "DocumentReference.id", Select: "id", LogicalType: "scalar", Filterable: true}, - "s_document_url": {ID: "s_document_url", NodeID: "n_document", FieldRef: "DocumentReference.content_attachment_url", Select: "content[].attachment.url", LogicalType: "scalar", Filterable: true}, - }, - } - var diagnostics []string - bundle, source, err := migrationBundleWithDiagnostics(rawConfig, rawMapping, nil, catalog, "project-a", "default", &diagnostics) - if err != nil { - t.Fatal(err) - } - if source != "frontend-mapping-repaired" { - t.Fatalf("source=%q, want frontend-mapping-repaired", source) - } - documents := bundle.AuthoringDocuments() - if len(documents) != 1 || len(documents[0].CandidateIDs) != 2 { - t.Fatalf("repaired documents=%#v", documents) - } - if documents[0].CandidateIDs[0] != "s_document_id" || documents[0].CandidateIDs[1] != "s_document_url" { - t.Fatalf("candidate IDs=%v", documents[0].CandidateIDs) - } - idEmission := explorer.OpaqueID("em_", "file\x00base\x00s_document_id") - urlEmission := explorer.OpaqueID("em_", "file\x00base\x00s_document_url") - idPresentation, ok := documents[0].Presentation[idEmission] - if !ok || idPresentation.Label != "Identifier" || idPresentation.Table == nil || idPresentation.Visible == nil || !*idPresentation.Visible || idPresentation.Order == nil || *idPresentation.Order != 0 { - t.Fatalf("identifier presentation=%#v", idPresentation) - } - urlPresentation, ok := documents[0].Presentation[urlEmission] - if !ok || urlPresentation.Label != "URL" || urlPresentation.Table == nil || urlPresentation.Visible == nil || *urlPresentation.Visible || urlPresentation.Order == nil || *urlPresentation.Order != 1 { - t.Fatalf("URL presentation=%#v", urlPresentation) - } - if len(diagnostics) != 1 || diagnostics[0] != "views[0].table.columns[2].project_id" { - t.Fatalf("repair diagnostics=%v", diagnostics) - } - snapshot, err := explorer.NewCatalogSnapshot("project-a", "generation-a", "scope-a", catalog, true, false, nil) - if err != nil { - t.Fatal(err) - } - compiled, err := ResolveAuthoringBundle(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: bundle, SnapshotToken: snapshot.Token}) - if err != nil { - t.Fatal(err) - } - if len(compiled.ResolvedBindings) != 1 || len(compiled.ResolvedBindings[0].CandidateEmissions) != 2 { - t.Fatalf("resolved bindings=%#v", compiled.ResolvedBindings) - } -} - -func TestResolvedAuthoringBindingSerializesEmptyCandidateEmissionsAsArray(t *testing.T) { - catalog := explorer.Catalog{Nodes: []explorer.CatalogNode{{ID: "n_patient", ResourceType: "Patient"}}} - binding := resolvedAuthoringBinding(explorer.ExplorerBuilderDocumentV1{ - Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_patient", RowNodeID: "n_patient", - }, catalog, nil, nil, nil) - raw, err := json.Marshal(binding) - if err != nil { - t.Fatal(err) - } - var payload map[string]any - if err := json.Unmarshal(raw, &payload); err != nil { - t.Fatal(err) - } - emissions, ok := payload["candidateEmissions"].([]any) - if !ok || len(emissions) != 0 { - t.Fatalf("candidateEmissions serialized as %s", raw) - } -} - -func TestMigrationPublishesNativeV2WorkspaceRevision(t *testing.T) { - ctx := context.Background() - store := explorer.NewMemoryStore() - service, err := explorer.NewService(store) - if err != nil { - t.Fatal(err) - } - owner, err := service.EnsureRepositoryExplorer(ctx, "project-a", "default", "Default", "test") - if err != nil { - t.Fatal(err) - } - legacyCandidateID := explorer.OpaqueID("s_", "Patient\x00id") - visible := true - order := 0 - legacyBundle := explorer.ExplorerAuthoringBundleV1{ - APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, - Project: "project-a", ExplorerID: "default", Title: "Default", - Documents: []explorer.ExplorerBuilderDocumentV1{{ - Kind: explorer.ExplorerBuilderV1Kind, - Output: explorer.ExplorerOutputIdentityV1{ID: "patients", Title: "Patients"}, - BaseNodeID: explorer.OpaqueID("n_", "Patient"), RowNodeID: explorer.OpaqueID("n_", "Patient"), - CandidateIDs: []string{legacyCandidateID}, - CandidateOccurrences: []explorer.ExplorerCandidateOccurrenceV1{{CandidateID: legacyCandidateID, OccurrenceID: "base", ProjectionMode: "SCALAR"}}, - Presentation: map[string]explorer.ExplorerPresentationBindingV1{legacyCandidateID + "\x00base": {Label: "Identifier", Visible: &visible, Order: &order}}, - }}, - Tabs: []explorer.ExplorerTabV1{{ID: "patients-tab", Title: "Patients", OutputID: "patients", Order: 0, Visible: &visible}}, - } - legacyRaw := mustAuthoringJSON(t, legacyBundle) - if _, err := service.PublishAuthoring(ctx, - explorer.CompilationReceipt{ID: "legacy-receipt", Project: "project-a", ExplorerID: "default", NormalizedBundle: legacyRaw}, - explorer.Revision{ID: "legacy-revision", Project: owner.Project, ExplorerID: "default", CompilationReceiptID: "legacy-receipt", IntentDigest: "legacy-intent", AuthoringBundle: legacyRaw, Status: explorer.RevisionReady}, - ); err != nil { - t.Fatal(err) - } - rawMapping, err := json.Marshal(map[string]any{"bundle": legacyBundle}) - if err != nil { - t.Fatal(err) - } - legacyCatalog := explorer.Catalog{ - Nodes: []explorer.CatalogNode{{ID: explorer.OpaqueID("n_", "Patient"), ResourceType: "Patient"}}, - Selections: map[string]explorer.CatalogSelection{legacyCandidateID: {ID: legacyCandidateID, NodeID: explorer.OpaqueID("n_", "Patient"), FieldRef: "Patient.id", Select: "id", ProjectionModes: []string{"SCALAR"}, DefaultProjectionMode: "SCALAR"}}, - } - legacySnapshot := explorer.CatalogSnapshot{Project: "project-a", Generation: "generation-a", AuthorizationScopeDigest: "scope-a", Catalog: legacyCatalog, Complete: true, Token: "legacy-snapshot"} - nativeSnapshot := capability.Snapshot{ - Identity: capability.SnapshotIdentity{Project: "project-a", Generation: "generation-a", AuthorizationScopeDigest: "scope-a"}, - Policy: capability.Policy{Route: capability.RoutePolicy{AllowsRepeatedEdges: true, AllowsSelfLoops: true}}, - Status: capability.StatusReady, Complete: true, Token: "native-snapshot", - Nodes: []capability.Node{{ID: "patient-node", ResourceType: "Patient", RowRootEligible: true, RowGrain: "patient", Populated: true, DocumentCount: 1}}, - Candidates: []capability.Candidate{{ID: "patient-id", NodeID: "patient-node", ResourceType: "Patient", FieldPath: "id", Label: "Identifier", LogicalType: "string", Cardinality: "scalar", ProjectionModes: []capability.ProjectionMode{capability.ProjectionScalar}, Populated: true}}, - } - compiledWorkspace := authoringv2.Workspace{} - config := ExplorerV2LifecycleConfig{ - Catalog: func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { - return legacySnapshot, nil - }, - Capability: func(context.Context, string, string, string) (capability.Snapshot, error) { return nativeSnapshot, nil }, - CompileReceipt: func(_ context.Context, request ExplorerV2ReceiptCompileRequest) (*explorer.CompilationReceipt, error) { - compiledWorkspace = request.Workspace - normalized, marshalErr := request.Workspace.CanonicalJSON() - if marshalErr != nil { - return nil, marshalErr - } - return &explorer.CompilationReceipt{ - ID: "native-v2-receipt", Project: "project-a", ExplorerID: "default", IntentDigest: "v2-intent", - SnapshotToken: nativeSnapshot.Token, SourceGeneration: "generation-a", NormalizedBundle: normalized, - Bundle: recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "migrated", Outputs: []recipe.Output{{Name: "patients", RootResourceType: "Patient", RowGrain: "patient"}}}, - }, nil - }, - MaterializeReceipt: func(context.Context, *explorer.CompilationReceipt, recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { - return graphresolver.RecipeExecution{ID: "migration-execution", SourceGeneration: "generation-a", State: "PUBLISHED", Outputs: []graphresolver.RecipeExecutionOutput{{Name: "patients", State: "PUBLISHED"}}}, nil - }, - ValidateReleaseGeneration: func(context.Context, string, string) error { return nil }, - ActivateRelease: func(context.Context, string, string, []dataset.DataframeSelector) error { return nil }, - } - report, err := MigrateLegacyExplorerAuthoring(ctx, service, config, ExplorerAuthoringMigrationOptions{Project: "project-a", ExplorerID: "default", LegacyMapping: rawMapping}) - if err != nil { - t.Fatal(err) - } - if report.ExplorerActivated == false || len(compiledWorkspace.Documents) != 1 { - t.Fatalf("report=%#v workspace=%#v", report, compiledWorkspace) - } - active, err := service.ActiveRevision(ctx, "project-a", "default") - if err != nil { - t.Fatal(err) - } - storedWorkspace, err := authoringv2.DecodeWorkspace(active.AuthoringBundle) - if err != nil { - t.Fatalf("active authoring bundle is not V2: %v\n%s", err, active.AuthoringBundle) - } - if len(storedWorkspace.Documents) != 1 || storedWorkspace.Documents[0].Selections[0].CandidateID != "patient-id" { - t.Fatalf("stored workspace=%#v", storedWorkspace) - } -} - -func mustAuthoringJSON(t *testing.T, bundle explorer.ExplorerAuthoringBundleV1) []byte { - t.Helper() - raw, err := bundle.CanonicalJSON() - if err != nil { - t.Fatal(err) - } - return raw -} diff --git a/internal/server/explorer_authoring_normalization_test.go b/internal/server/explorer_authoring_normalization_test.go deleted file mode 100644 index 06292477..00000000 --- a/internal/server/explorer_authoring_normalization_test.go +++ /dev/null @@ -1,223 +0,0 @@ -package server - -import ( - "context" - "errors" - "strings" - "testing" - - "github.com/calypr/loom/internal/explorer" -) - -func TestNormalizeDocumentMapsZeroHopCandidateToBase(t *testing.T) { - snapshot := authoringTestSnapshot(t) - document := explorer.ExplorerBuilderDocumentV1{ - Kind: explorer.ExplorerBuilderV1Kind, - Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, - BaseNodeID: "n_base", - RowNodeID: "n_base", - CandidateIDs: []string{ - "s_base", - }, - } - result, err := ResolveAuthoringBundle(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { - return snapshot, nil - }, ExplorerAuthoringV1CompileRequest{ - Bundle: authoringTestBundleWithoutCandidateOccurrences(document), - SnapshotToken: snapshot.Token, - }) - if err != nil { - t.Fatal(err) - } - got := result.Bundle.AuthoringDocuments()[0].CandidateOccurrences - if len(got) != 1 || got[0].CandidateID != "s_base" || got[0].OccurrenceID != "base" { - t.Fatalf("candidate occurrences=%#v", got) - } -} - -func TestNormalizeDocumentMapsOneHopCandidateToOnlyMatchingOccurrence(t *testing.T) { - snapshot := authoringTestSnapshot(t) - document := explorer.ExplorerBuilderDocumentV1{ - Kind: explorer.ExplorerBuilderV1Kind, - Output: explorer.ExplorerOutputIdentityV1{ID: "observations"}, - BaseNodeID: "n_base", - RowNodeID: "n_child", - RouteEdgeIDs: []string{"e_forward"}, - CandidateIDs: []string{"s_child"}, - } - result, err := ResolveAuthoringBundle(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { - return snapshot, nil - }, ExplorerAuthoringV1CompileRequest{ - Bundle: authoringTestBundleWithoutCandidateOccurrences(document), - SnapshotToken: snapshot.Token, - }) - if err != nil { - t.Fatal(err) - } - got := result.Bundle.AuthoringDocuments()[0] - if len(got.CandidateOccurrences) != 1 || got.CandidateOccurrences[0].CandidateID != "s_child" || got.CandidateOccurrences[0].OccurrenceID == "base" { - t.Fatalf("normalized one-hop document=%#v", got) - } - if got.CandidateOccurrences[0].OccurrenceID != got.RouteOccurrences[1].ID { - t.Fatalf("candidate occurrence=%#v route occurrences=%#v", got.CandidateOccurrences, got.RouteOccurrences) - } -} - -func TestNormalizeDocumentRequiresOccurrenceForRepeatedResource(t *testing.T) { - catalog := explorer.Catalog{ - Nodes: []explorer.CatalogNode{ - {ID: "n_base", ResourceType: "Patient"}, - {ID: "n_child", ResourceType: "Observation"}, - }, - Edges: []explorer.CatalogEdge{ - {ID: "e_forward", FromNodeID: "n_base", ToNodeID: "n_child"}, - {ID: "e_back", FromNodeID: "n_child", ToNodeID: "n_base"}, - }, - Selections: map[string]explorer.CatalogSelection{ - "s_base": {ID: "s_base", NodeID: "n_base", Select: "id"}, - }, - } - document := explorer.ExplorerBuilderDocumentV1{ - Kind: explorer.ExplorerBuilderV1Kind, - Output: explorer.ExplorerOutputIdentityV1{ID: "patients"}, - BaseNodeID: "n_base", - RowNodeID: "n_base", - RouteEdgeIDs: []string{"e_forward", "e_back"}, - CandidateIDs: []string{"s_base"}, - } - snapshot, err := explorer.NewCatalogSnapshot("project-a", "generation-a", "scope-a", catalog, true, false, nil) - if err != nil { - t.Fatal(err) - } - _, err = ResolveAuthoringBundle(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { - return snapshot, nil - }, ExplorerAuthoringV1CompileRequest{ - Bundle: authoringTestBundleWithoutCandidateOccurrences(document), - SnapshotToken: snapshot.Token, - }) - if err == nil || !strings.Contains(err.Error(), "CANDIDATE_OCCURRENCE_REQUIRED") { - t.Fatalf("ambiguous candidate error=%v", err) - } - var authoringErr *explorer.AuthoringError - if !errors.As(err, &authoringErr) || len(authoringErr.Diagnostic.Details["validOccurrences"].([]string)) != 2 { - t.Fatalf("ambiguous candidate details=%#v", err) - } -} - -func TestNormalizeDocumentRejectsStaleAndMismatchedCandidates(t *testing.T) { - snapshot := authoringTestSnapshot(t) - baseBinding := explorer.ExplorerResolvedBindingV1{ - BaseNodeID: "n_base", - RouteOccurrences: []explorer.ExplorerResolvedOccurrenceV1{ - {OccurrenceID: "base", Index: 0, NodeID: "n_base"}, - }, - } - unknown := explorer.ExplorerBuilderDocumentV1{CandidateIDs: []string{"unknown"}} - if _, err := normalizeDocument(unknown, snapshot.Catalog, baseBinding); err == nil || !strings.Contains(err.Error(), "STALE_CANDIDATE_ID") { - t.Fatalf("unknown candidate error=%v", err) - } - mismatch := explorer.ExplorerBuilderDocumentV1{CandidateIDs: []string{"s_child"}, BaseNodeID: "n_base"} - if _, err := normalizeDocument(mismatch, snapshot.Catalog, baseBinding); err == nil || !strings.Contains(err.Error(), "SELECTION_NODE_MISMATCH") { - t.Fatalf("mismatched candidate error=%v", err) - } -} - -func TestNormalizeDocumentDropsDownstreamSelectionsAfterRouteTruncation(t *testing.T) { - catalog := explorer.Catalog{ - Nodes: []explorer.CatalogNode{ - {ID: "n_base", ResourceType: "Patient"}, - {ID: "n_child", ResourceType: "Observation"}, - {ID: "n_grandchild", ResourceType: "Task"}, - }, - Edges: []explorer.CatalogEdge{{ID: "e_forward", FromNodeID: "n_base", ToNodeID: "n_child"}}, - Selections: map[string]explorer.CatalogSelection{ - "s_child": {ID: "s_child", NodeID: "n_child", Select: "status"}, - "s_grandchild": {ID: "s_grandchild", NodeID: "n_grandchild", Select: "status"}, - }, - } - document := explorer.ExplorerBuilderDocumentV1{ - Kind: explorer.ExplorerBuilderV1Kind, - Output: explorer.ExplorerOutputIdentityV1{ID: "observations"}, - BaseNodeID: "n_base", - RowNodeID: "n_child", - RouteEdgeIDs: []string{"e_forward"}, - RouteOccurrences: []explorer.ExplorerRouteOccurrenceV1{ - {ID: "base", Index: 0, NodeID: "n_base"}, - {ID: "child", Index: 1, NodeID: "n_child"}, - {ID: "grandchild", Index: 2, NodeID: "n_grandchild"}, - }, - CandidateIDs: []string{"s_child", "s_grandchild"}, - CandidateOccurrences: []explorer.ExplorerCandidateOccurrenceV1{ - {CandidateID: "s_child", OccurrenceID: "child"}, - {CandidateID: "s_grandchild", OccurrenceID: "grandchild"}, - }, - } - structural, err := normalizeStructuralAuthoringRoutes([]explorer.ExplorerBuilderDocumentV1{document}, catalog) - if err != nil { - t.Fatal(err) - } - normalized, err := normalizeAuthoringDocuments(structural, catalog) - if err != nil { - t.Fatal(err) - } - got := normalized[0] - if len(got.CandidateIDs) != 1 || got.CandidateIDs[0] != "s_child" || len(got.CandidateOccurrences) != 1 || got.CandidateOccurrences[0].OccurrenceID != "child" { - t.Fatalf("truncated route retained downstream selection: %#v", got) - } -} - -func TestNormalizeDocumentIsIdempotent(t *testing.T) { - snapshot := authoringTestSnapshot(t) - document := explorer.ExplorerBuilderDocumentV1{ - Kind: explorer.ExplorerBuilderV1Kind, - Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, - BaseNodeID: "n_base", - RowNodeID: "n_base", - CandidateIDs: []string{ - "s_base", - }, - } - firstStructural, err := normalizeStructuralAuthoringRoutes([]explorer.ExplorerBuilderDocumentV1{document}, snapshot.Catalog) - if err != nil { - t.Fatal(err) - } - first, err := normalizeAuthoringDocuments(firstStructural, snapshot.Catalog) - if err != nil { - t.Fatal(err) - } - secondStructural, err := normalizeStructuralAuthoringRoutes(first, snapshot.Catalog) - if err != nil { - t.Fatal(err) - } - second, err := normalizeAuthoringDocuments(secondStructural, snapshot.Catalog) - if err != nil { - t.Fatal(err) - } - firstBundle := authoringTestBundleWithoutCandidateOccurrences(first[0]) - firstBundle.Documents = first - firstBundle.Document = explorer.ExplorerBuilderDocumentV1{} - secondBundle := authoringTestBundleWithoutCandidateOccurrences(second[0]) - secondBundle.Documents = second - secondBundle.Document = explorer.ExplorerBuilderDocumentV1{} - firstDigest, err := firstBundle.DocumentDigest() - if err != nil { - t.Fatal(err) - } - secondDigest, err := secondBundle.DocumentDigest() - if err != nil { - t.Fatal(err) - } - if firstDigest != secondDigest { - t.Fatalf("normalization is not idempotent: first=%s second=%s", firstDigest, secondDigest) - } -} - -func authoringTestBundleWithoutCandidateOccurrences(document explorer.ExplorerBuilderDocumentV1) explorer.ExplorerAuthoringBundleV1 { - return explorer.ExplorerAuthoringBundleV1{ - APIVersion: explorer.ExplorerAuthoringV1APIVersion, - Kind: explorer.ExplorerAuthoringV1Kind, - Project: "project-a", - ExplorerID: "custom", - Documents: []explorer.ExplorerBuilderDocumentV1{document}, - } -} diff --git a/internal/server/explorer_authoring_v1.go b/internal/server/explorer_authoring_v1.go deleted file mode 100644 index a91f2430..00000000 --- a/internal/server/explorer_authoring_v1.go +++ /dev/null @@ -1,878 +0,0 @@ -package server - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "encoding/json" - "errors" - "fmt" - "regexp" - "sort" - "strconv" - "strings" - "time" - - "github.com/calypr/loom/internal/dataframe/recipe" - "github.com/calypr/loom/internal/dataframe/recipe/engine" - "github.com/calypr/loom/internal/dataframe/spec" - "github.com/calypr/loom/internal/explorer" - fhirschema "github.com/calypr/loom/internal/fhir/schema" - "github.com/calypr/loom/internal/projectid" -) - -var authoringIDPattern = regexp.MustCompile(`^[a-z][a-z0-9-]{0,63}$`) - -type ExplorerAuthoringV1CompileRequest struct { - Bundle explorer.ExplorerAuthoringBundleV1 - SnapshotToken string - RequestID string -} - -type ExplorerAuthoringV1CompileResult struct { - Bundle explorer.ExplorerAuthoringBundleV1 - CanonicalBundle []byte - Receipt explorer.CompilationReceipt - RecipeDigest string - ResolvedSchemaDigest string - SourceGeneration string - EmittedColumns []explorer.EmittedColumn - ResolvedBindings []explorer.ExplorerResolvedBindingV1 - // Snapshot is the exact catalog snapshot used for route/candidate - // resolution. Builder responses reuse it so bindings and catalog metadata - // cannot drift across two catalog reads. - Snapshot explorer.CatalogSnapshot - Diagnostics []explorer.AuthoringDiagnostic -} - -// ResolveAuthoringBundle is the single authoritative authoring phase used by -// Builder reads, preview, publication, and compilation. It resolves opaque -// intent against exactly one catalog snapshot, validates route occurrences and -// candidates, lowers the native recipe, compiles it, and returns the resolved -// Builder bindings alongside the executable receipt. -func ResolveAuthoringBundle(ctx context.Context, recipeEngine *engine.Engine, catalogReader explorerV2CatalogReader, request ExplorerAuthoringV1CompileRequest) (ExplorerAuthoringV1CompileResult, error) { - bundle := request.Bundle - // Intent digests describe the pre-resolution document. Legacy documents - // may have been persisted before candidateOccurrences became canonical, so - // validate the strict shape first and verify the digest only after the - // catalog-aware normalizer has produced the canonical document. - shape := bundle - shape.IntentDigest = "" - if err := shape.Validate(); err != nil { - return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(err, request.RequestID) - } - bundle.Project = projectid.Canonical(bundle.Project) - documents := bundle.AuthoringDocuments() - if len(documents) == 0 { - return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(authoringSemantic("intent", "$.bundle.documents", "EMPTY_AUTHORING_BUNDLE", "preview and publish require at least one output", nil), request.RequestID) - } - // Normalize compatibility single-document input before it is stored in a - // receipt or returned to the Builder. One Explorer may contain multiple - // output documents; the canonical wire form is always documents[]. - bundle.Document = explorer.ExplorerBuilderDocumentV1{} - bundle.Documents = documents - if request.SnapshotToken == "" { - return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(explorerConflict("snapshot", "SNAPSHOT_REQUIRED", "a catalog snapshot token is required", nil), request.RequestID) - } - if catalogReader == nil { - return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(explorerUnavailable("catalog", "CATALOG_UNAVAILABLE", "Explorer authoring catalog is not configured"), request.RequestID) - } - snapshot, err := catalogReader(ctx, bundle.Project, bundle.ExplorerID, "") - if err != nil { - if snapshot.Token != "" && !snapshot.Complete { - return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(explorerUnavailable("catalog", "CATALOG_INCOMPLETE", "Explorer authoring catalog is incomplete"), request.RequestID) - } - return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(explorerConflict("catalog", "CATALOG_SNAPSHOT_FAILED", err.Error(), nil), request.RequestID) - } - if err := snapshot.ValidateToken(request.SnapshotToken); err != nil { - code := "STALE_CATALOG_SNAPSHOT" - if errors.Is(err, explorer.ErrIncompleteCatalog) { - code = "CATALOG_INCOMPLETE" - } - return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(explorerConflict("catalog", code, err.Error(), map[string]any{"snapshotToken": request.SnapshotToken}), request.RequestID) - } - documents, err = normalizeStructuralAuthoringRoutes(documents, snapshot.Catalog) - if err != nil { - return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(err, request.RequestID) - } - documents, err = normalizeAuthoringDocuments(documents, snapshot.Catalog) - if err != nil { - return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(err, request.RequestID) - } - bundle.Documents = documents - digest, err := bundle.DocumentDigest() - if err != nil { - return ExplorerAuthoringV1CompileResult{}, err - } - // The compatibility normalization above changes canonical authoring intent. - // Return the matching digest with the normalized bundle so a subsequent - // preview or publish can round-trip the Builder response without a 409. - bundle.IntentDigest = digest - - var native recipe.Bundle - var emitted []explorer.EmittedColumn - var mappings []explorer.IdentityMapping - var bindings []explorer.ExplorerResolvedBindingV1 - for _, document := range documents { - path, routeErr := resolveAuthoringRoute(document, snapshot.Catalog) - if routeErr != nil { - return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(routeErr, request.RequestID) - } - assignments, candidateErr := resolveAuthoringCandidates(document, snapshot.Catalog, path) - if candidateErr != nil { - return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(candidateErr, request.RequestID) - } - documentEmitted, documentMappings := authoringEmissions(document, snapshot.Catalog, assignments) - if presentationErr := validateAuthoringPresentation(document, documentEmitted); presentationErr != nil { - return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(presentationErr, request.RequestID) - } - part, lowerErr := lowerAuthoringDocument(bundle.Project, bundle.ExplorerID, document, snapshot.Catalog, path, assignments) - if lowerErr != nil { - return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(lowerErr, request.RequestID) - } - if len(part.Outputs) != 1 { - return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(authoringSemantic("lower", "$.documents", "AUTHORING_OUTPUT_LOWERING_FAILED", "each authoring document must lower to exactly one recipe output", nil), request.RequestID) - } - if len(native.Outputs) == 0 { - native = part - } else { - native.Outputs = append(native.Outputs, part.Outputs...) - } - emitted = append(emitted, documentEmitted...) - mappings = append(mappings, documentMappings...) - bindings = append(bindings, resolvedAuthoringBinding(document, snapshot.Catalog, path, assignments, documentEmitted)) - } - if err := native.Validate(); err != nil { - return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(authoringSemanticFromRecipe(err), request.RequestID) - } - - recipeDigest, resolvedSchemaDigest := "", snapshot.ResolvedSchemaDigest - if recipeEngine != nil { - resolved, resolveErr := recipeEngine.ResolveBundle(ctx, native, recipe.RuntimeBindings{Project: projectid.Legacy(bundle.Project), DatasetGeneration: snapshot.Generation}) - if resolveErr != nil { - return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(authoringSemanticFromCompile(resolveErr), request.RequestID) - } - recipeDigest = resolved.StoredRecipeDigest - resolvedSchemaDigest = resolved.ResolvedSchemaDigest - // The lowerer is authoritative for physical public columns. Keep the - // intent-to-emission IDs stable, while using the compiler schema only to - // fill logical type metadata. - kindByColumn := map[string]string{} - for _, output := range resolved.Compiled.Outputs { - for _, column := range output.OutputSchema { - if !column.Internal { - kindByColumn[column.Name] = column.Kind - } - } - } - for i := range emitted { - if kind := kindByColumn[generatedFieldName(emitted[i].CandidateID, emitted[i].OccurrenceID)]; kind != "" { - emitted[i].LogicalType = kind - } - } - } else { - recipeDigest, _ = native.Digest() - } - if recipeDigest == "" { - recipeDigest, _ = native.Digest() - } - canonical, err := bundle.CanonicalJSON() - if err != nil { - return ExplorerAuthoringV1CompileResult{}, withRequestAuthoringError(err, request.RequestID) - } - compiledConfig, err := authoringCompiledConfig(bundle, native, emitted) - if err != nil { - return ExplorerAuthoringV1CompileResult{}, err - } - receipt := explorer.CompilationReceipt{ - Project: bundle.Project, ExplorerID: bundle.ExplorerID, IntentDigest: digest, - SnapshotToken: request.SnapshotToken, SourceGeneration: snapshot.Generation, - RecipeDigest: recipeDigest, ResolvedSchemaDigest: resolvedSchemaDigest, - NormalizedBundle: append([]byte(nil), canonical...), Bundle: native, - CompiledConfig: compiledConfig, IdentityMappings: mappings, EmittedColumns: emitted, - CreatedAt: time.Now().UTC(), RequestID: request.RequestID, - } - receipt.OutputFingerprints = map[string]string{} - for _, output := range native.Outputs { - receipt.OutputFingerprints[output.Name] = outputFingerprint(native, bundle.Project, snapshot.Generation) - } - receipt.ID, err = explorer.ReceiptID(receipt) - if err != nil { - return ExplorerAuthoringV1CompileResult{}, err - } - return ExplorerAuthoringV1CompileResult{Bundle: bundle, CanonicalBundle: canonical, Receipt: receipt, RecipeDigest: recipeDigest, ResolvedSchemaDigest: resolvedSchemaDigest, SourceGeneration: snapshot.Generation, EmittedColumns: emitted, ResolvedBindings: bindings, Snapshot: snapshot, Diagnostics: []explorer.AuthoringDiagnostic{}}, nil -} - -// normalizeStructuralAuthoringRoutes lets a client append exact catalog edge -// IDs without inventing occurrence identities. Existing route prefixes retain -// their IDs; Loom deterministically owns only the newly appended occurrences. -func normalizeStructuralAuthoringRoutes(documents []explorer.ExplorerBuilderDocumentV1, catalog explorer.Catalog) ([]explorer.ExplorerBuilderDocumentV1, error) { - edges := make(map[string]explorer.CatalogEdge, len(catalog.Edges)) - for _, edge := range catalog.Edges { - edges[edge.ID] = edge - } - normalized := append([]explorer.ExplorerBuilderDocumentV1(nil), documents...) - for documentIndex := range normalized { - document := &normalized[documentIndex] - path := fmt.Sprintf("$.documents[%d]", documentIndex) - current := document.BaseNodeID - targets := make([]string, 0, len(document.RouteEdgeIDs)) - for edgeIndex, edgeID := range document.RouteEdgeIDs { - edge, ok := edges[edgeID] - if !ok { - return nil, authoringSemantic("route", fmt.Sprintf("%s.routeEdgeIds[%d]", path, edgeIndex), "STALE_ROUTE_EDGE", "route edge is not present in the catalog snapshot", map[string]any{"edgeId": edgeID}) - } - if edge.FromNodeID != current { - return nil, authoringSemantic("route", fmt.Sprintf("%s.routeEdgeIds[%d]", path, edgeIndex), "INVALID_ROUTE_CONTINUITY", "ordered route edges do not form a continuous path", map[string]any{"edgeId": edgeID, "currentNodeId": current}) - } - current = edge.ToNodeID - targets = append(targets, current) - } - provided := append([]explorer.ExplorerRouteOccurrenceV1(nil), document.RouteOccurrences...) - providedOccurrenceIDs := make(map[string]bool, len(provided)) - for _, occurrence := range provided { - providedOccurrenceIDs[occurrence.ID] = true - } - if len(provided) > 0 && (provided[0].ID == "base" || provided[0].NodeID == document.BaseNodeID && len(provided) == len(document.RouteEdgeIDs)+1) { - provided = provided[1:] - } - // A Builder can retain route/candidate state from a longer route while - // the user shortens the route. Keep the surviving prefix and let the - // candidate normalizer remove selections tied only to occurrences that - // no longer exist. - if len(provided) > len(targets) { - provided = provided[:len(targets)] - } - occurrences := []explorer.ExplorerRouteOccurrenceV1{{ID: "base", Index: 0, NodeID: document.BaseNodeID}} - for index, nodeID := range targets { - edgeID := document.RouteEdgeIDs[index] - occurrence := explorer.ExplorerRouteOccurrenceV1{} - if index < len(provided) { - occurrence = provided[index] - if occurrence.NodeID != nodeID || occurrence.IncomingEdgeID != "" && occurrence.IncomingEdgeID != edgeID { - return nil, authoringSemantic("route", fmt.Sprintf("%s.routeOccurrences[%d]", path, index), "INVALID_ROUTE_OCCURRENCE_NODE", "route occurrence does not match its exact edge target", map[string]any{"expectedNodeId": nodeID, "receivedNodeId": occurrence.NodeID}) - } - } else { - occurrence.ID = explorer.OpaqueID("occ_", document.Output.ID+"\x00"+strconv.Itoa(index+1)+"\x00"+edgeID+"\x00"+nodeID) - } - occurrence.Index = index + 1 - occurrence.NodeID = nodeID - occurrence.IncomingEdgeID = edgeID - occurrences = append(occurrences, occurrence) - } - document.RouteOccurrences = occurrences - keptOccurrenceIDs := make(map[string]bool, len(occurrences)) - for _, occurrence := range occurrences { - keptOccurrenceIDs[occurrence.ID] = true - } - candidateOccurrences := make([]explorer.ExplorerCandidateOccurrenceV1, 0, len(document.CandidateOccurrences)) - removedCandidateIDs := map[string]bool{} - for _, reference := range document.CandidateOccurrences { - if reference.OccurrenceID != "base" && providedOccurrenceIDs[reference.OccurrenceID] && !keptOccurrenceIDs[reference.OccurrenceID] { - removedCandidateIDs[reference.CandidateID] = true - continue - } - candidateOccurrences = append(candidateOccurrences, reference) - } - document.CandidateOccurrences = candidateOccurrences - if len(removedCandidateIDs) > 0 { - candidateIDs := make([]string, 0, len(document.CandidateIDs)) - for _, candidateID := range document.CandidateIDs { - if removedCandidateIDs[candidateID] && !candidateOccurrenceHasID(candidateOccurrences, candidateID) { - continue - } - candidateIDs = append(candidateIDs, candidateID) - } - document.CandidateIDs = candidateIDs - } - } - return normalized, nil -} - -func candidateOccurrenceHasID(references []explorer.ExplorerCandidateOccurrenceV1, candidateID string) bool { - for _, reference := range references { - if reference.CandidateID == candidateID { - return true - } - } - return false -} - -// normalizeAuthoringDocuments resolves every legacy candidate selection -// against the exact route occurrences that structural normalization produced. -// It is deliberately separate from recipe lowering so GET, Builder POST, -// preview, publish, and the admin migration all share the same repair rules. -func normalizeAuthoringDocuments(documents []explorer.ExplorerBuilderDocumentV1, catalog explorer.Catalog) ([]explorer.ExplorerBuilderDocumentV1, error) { - normalized := append([]explorer.ExplorerBuilderDocumentV1(nil), documents...) - for index := range normalized { - document := normalized[index] - path := fmt.Sprintf("$.documents[%d]", index) - if _, err := resolveAuthoringRoute(document, catalog); err != nil { - return nil, err - } - binding := explorer.ExplorerResolvedBindingV1{OutputID: document.Output.ID, BaseNodeID: document.BaseNodeID, RouteOccurrences: make([]explorer.ExplorerResolvedOccurrenceV1, 0, len(document.RouteOccurrences))} - for _, occurrence := range document.RouteOccurrences { - binding.RouteOccurrences = append(binding.RouteOccurrences, explorer.ExplorerResolvedOccurrenceV1{OccurrenceID: occurrence.ID, Index: occurrence.Index, NodeID: occurrence.NodeID, IncomingEdgeID: occurrence.IncomingEdgeID}) - } - var err error - normalized[index], err = normalizeDocument(document, catalog, binding) - if err != nil { - return nil, withDocumentPath(err, path) - } - } - return normalized, nil -} - -// normalizeDocument upgrades the legacy candidateIds-only representation to -// the canonical candidateIds + candidateOccurrences representation. Existing -// valid pairs are retained verbatim. A missing pair is inferred only when the -// catalog identifies exactly one route occurrence; repeated resource nodes -// remain an explicit user choice. -func normalizeDocument(document explorer.ExplorerBuilderDocumentV1, catalog explorer.Catalog, resolvedBinding explorer.ExplorerResolvedBindingV1) (explorer.ExplorerBuilderDocumentV1, error) { - selectionByID := catalog.Selections - routeOccurrences := append([]explorer.ExplorerResolvedOccurrenceV1(nil), resolvedBinding.RouteOccurrences...) - occurrenceNodes := make(map[string]string, len(routeOccurrences)+1) - for _, occurrence := range resolvedBinding.RouteOccurrences { - if strings.TrimSpace(occurrence.OccurrenceID) == "" { - continue - } - occurrenceNodes[occurrence.OccurrenceID] = occurrence.NodeID - } - baseNodeID := resolvedBinding.BaseNodeID - if baseNodeID == "" { - baseNodeID = document.BaseNodeID - } - if _, ok := occurrenceNodes["base"]; !ok { - occurrenceNodes["base"] = baseNodeID - routeOccurrences = append([]explorer.ExplorerResolvedOccurrenceV1{{OccurrenceID: "base", Index: 0, NodeID: baseNodeID}}, routeOccurrences...) - } - - byCandidate := make(map[string][]string, len(document.CandidateOccurrences)) - seenPairs := make(map[string]bool, len(document.CandidateOccurrences)) - for index, reference := range document.CandidateOccurrences { - if _, ok := selectionByID[reference.CandidateID]; !ok { - return document, authoringSemantic("candidates", fmt.Sprintf("$.document.candidateOccurrences[%d].candidateId", index), "STALE_CANDIDATE_ID", "candidate is not present in the catalog snapshot", map[string]any{"candidateId": reference.CandidateID}) - } - occurrenceNode, ok := occurrenceNodes[reference.OccurrenceID] - if !ok { - return document, authoringSemantic("candidates", fmt.Sprintf("$.document.candidateOccurrences[%d].occurrenceId", index), "STALE_ROUTE_OCCURRENCE", "candidate occurrence references an unknown route occurrence", map[string]any{"occurrenceId": reference.OccurrenceID}) - } - key := reference.CandidateID + "\x00" + reference.OccurrenceID - if seenPairs[key] { - return document, authoringSemantic("candidates", "$.document.candidateOccurrences", "DUPLICATE_CANDIDATE_OCCURRENCE", "a candidate occurrence may be listed only once", nil) - } - seenPairs[key] = true - if selectionByID[reference.CandidateID].NodeID != occurrenceNode { - return document, authoringSemantic("candidates", "$.document.candidateOccurrences", "SELECTION_NODE_MISMATCH", "candidate is not valid at the referenced route occurrence", map[string]any{"candidateId": reference.CandidateID, "occurrenceId": reference.OccurrenceID, "selectionNodeId": selectionByID[reference.CandidateID].NodeID, "occurrenceNodeId": occurrenceNode}) - } - byCandidate[reference.CandidateID] = append(byCandidate[reference.CandidateID], reference.OccurrenceID) - } - - occurrences := append([]explorer.ExplorerCandidateOccurrenceV1(nil), document.CandidateOccurrences...) - for index, candidateID := range document.CandidateIDs { - selection, ok := selectionByID[candidateID] - if !ok { - return document, authoringSemantic("candidates", fmt.Sprintf("$.document.candidateIds[%d]", index), "STALE_CANDIDATE_ID", "candidate is not present in the catalog snapshot", map[string]any{"candidateId": candidateID}) - } - if len(byCandidate[candidateID]) > 0 { - continue - } - matches := make([]string, 0, len(occurrenceNodes)) - for _, occurrence := range routeOccurrences { - if occurrence.NodeID == selection.NodeID { - matches = append(matches, occurrence.OccurrenceID) - } - } - if len(matches) == 0 { - return document, authoringSemantic("candidates", fmt.Sprintf("$.document.candidateIds[%d]", index), "SELECTION_NODE_MISMATCH", "candidate does not belong to any route occurrence in this document", map[string]any{"candidateId": candidateID, "selectionNodeId": selection.NodeID, "routeOccurrences": matches}) - } - if len(matches) > 1 { - return document, authoringSemantic("candidates", "$.document.candidateOccurrences", "CANDIDATE_OCCURRENCE_REQUIRED", "every selected candidate must identify its exact route occurrence", map[string]any{"candidateId": candidateID, "validOccurrences": matches}) - } - occurrences = append(occurrences, explorer.ExplorerCandidateOccurrenceV1{CandidateID: candidateID, OccurrenceID: matches[0]}) - byCandidate[candidateID] = append(byCandidate[candidateID], matches[0]) - } - - represented := make(map[string]bool, len(occurrences)) - for _, reference := range occurrences { - represented[reference.CandidateID] = true - } - candidateIDs := make([]string, 0, len(represented)) - for _, candidateID := range document.CandidateIDs { - if represented[candidateID] { - candidateIDs = append(candidateIDs, candidateID) - } - } - document.CandidateIDs = candidateIDs - document.CandidateOccurrences = occurrences - return document, nil -} - -func withDocumentPath(err error, path string) error { - var authoringErr *explorer.AuthoringError - if !errors.As(err, &authoringErr) || authoringErr == nil { - return err - } - if authoringErr.Diagnostic.JSONPath == "" || strings.HasPrefix(authoringErr.Diagnostic.JSONPath, "$.documents[") { - return err - } - authoringErr.Diagnostic.JSONPath = path + authoringErr.Diagnostic.JSONPath[len("$.document"):] - return err -} - -// compileExplorerAuthoringV1 remains as the internal compiler capability seam; -// all behavior is owned by ResolveAuthoringBundle. -func compileExplorerAuthoringV1(ctx context.Context, recipeEngine *engine.Engine, catalogReader explorerV2CatalogReader, request ExplorerAuthoringV1CompileRequest) (ExplorerAuthoringV1CompileResult, error) { - return ResolveAuthoringBundle(ctx, recipeEngine, catalogReader, request) -} - -type authoringRouteStep struct { - Occurrence explorer.ExplorerRouteOccurrenceV1 - Edge explorer.CatalogEdge - NodeID string -} - -func resolveAuthoringRoute(document explorer.ExplorerBuilderDocumentV1, catalog explorer.Catalog) ([]authoringRouteStep, error) { - nodes := map[string]explorer.CatalogNode{} - for _, node := range catalog.Nodes { - nodes[node.ID] = node - } - if _, ok := nodes[document.BaseNodeID]; !ok { - return nil, authoringSemantic("route", "$.document.baseNodeId", "STALE_BASE_NODE", "base node is not present in the catalog snapshot", map[string]any{"nodeId": document.BaseNodeID}) - } - if _, ok := nodes[document.RowNodeID]; !ok { - return nil, authoringSemantic("route", "$.document.rowNodeId", "STALE_ROW_NODE", "row node is not present in the catalog snapshot", map[string]any{"nodeId": document.RowNodeID}) - } - edges := map[string]explorer.CatalogEdge{} - for _, edge := range catalog.Edges { - edges[edge.ID] = edge - } - if len(document.RouteEdgeIDs) == 0 { - if document.BaseNodeID != document.RowNodeID { - return nil, authoringSemantic("route", "$.document.rowNodeId", "INVALID_ZERO_HOP_ROUTE", "a zero-hop route must end at its base node", nil) - } - if len(document.RouteOccurrences) > 1 { - return nil, authoringSemantic("route", "$.document.routeOccurrences", "INVALID_ZERO_HOP_ROUTE", "a zero-hop route has no child occurrences", nil) - } - if len(document.RouteOccurrences) == 1 && (document.RouteOccurrences[0].Index != 0 || document.RouteOccurrences[0].NodeID != document.BaseNodeID) { - return nil, authoringSemantic("route", "$.document.routeOccurrences[0]", "INVALID_ZERO_HOP_ROUTE", "the optional zero-hop occurrence must reference the base node at index zero", nil) - } - return nil, nil - } - for index, occurrence := range document.RouteOccurrences { - if _, ok := nodes[occurrence.NodeID]; !ok { - return nil, authoringSemantic("route", fmt.Sprintf("$.document.routeOccurrences[%d].nodeId", index), "STALE_ROUTE_NODE", "route occurrence node is not present in the catalog snapshot", map[string]any{"nodeId": occurrence.NodeID}) - } - } - if len(document.RouteOccurrences) != len(document.RouteEdgeIDs) && len(document.RouteOccurrences) != len(document.RouteEdgeIDs)+1 { - return nil, authoringSemantic("route", "$.document.routeOccurrences", "ROUTE_OCCURRENCES_REQUIRED", "route occurrence references must contain one target per edge, or include the base occurrence", map[string]any{"edges": len(document.RouteEdgeIDs), "occurrences": len(document.RouteOccurrences)}) - } - if len(document.RouteOccurrences) == len(document.RouteEdgeIDs)+1 && document.RouteOccurrences[0].NodeID != document.BaseNodeID { - return nil, authoringSemantic("route", "$.document.routeOccurrences[0].nodeId", "INVALID_ROUTE_ORIGIN", "the first route occurrence must reference baseNodeId", nil) - } - current := document.BaseNodeID - steps := make([]authoringRouteStep, 0, len(document.RouteEdgeIDs)) - for index, edgeID := range document.RouteEdgeIDs { - edge, ok := edges[edgeID] - if !ok { - return nil, authoringSemantic("route", fmt.Sprintf("$.document.routeEdgeIds[%d]", index), "STALE_ROUTE_EDGE", "route edge is not present in the catalog snapshot", map[string]any{"edgeId": edgeID}) - } - if edge.FromNodeID != current { - return nil, authoringSemantic("route", fmt.Sprintf("$.document.routeEdgeIds[%d]", index), "INVALID_ROUTE_CONTINUITY", "ordered route edges do not form a continuous path", map[string]any{"edgeId": edgeID, "currentNodeId": current}) - } - next := edge.ToNodeID - occurrenceIndex := index - if len(document.RouteOccurrences) == len(document.RouteEdgeIDs)+1 { - occurrenceIndex++ - } - occurrence := document.RouteOccurrences[occurrenceIndex] - if occurrence.Index != occurrenceIndex { - return nil, authoringSemantic("route", fmt.Sprintf("$.document.routeOccurrences[%d].index", occurrenceIndex), "INVALID_ROUTE_OCCURRENCE_ORDER", "route occurrence index does not match ordered route edges", nil) - } - if occurrence.NodeID != next { - return nil, authoringSemantic("route", fmt.Sprintf("$.document.routeOccurrences[%d].nodeId", occurrenceIndex), "INVALID_ROUTE_OCCURRENCE_NODE", "route occurrence does not name the edge target", map[string]any{"expectedNodeId": next, "receivedNodeId": occurrence.NodeID}) - } - if occurrence.IncomingEdgeID != "" && occurrence.IncomingEdgeID != edgeID { - return nil, authoringSemantic("route", fmt.Sprintf("$.document.routeOccurrences[%d].incomingEdgeId", occurrenceIndex), "INVALID_ROUTE_OCCURRENCE_EDGE", "route occurrence does not reference its incoming edge", nil) - } - steps = append(steps, authoringRouteStep{Occurrence: occurrence, Edge: edge, NodeID: next}) - current = next - } - if current != document.RowNodeID { - return nil, authoringSemantic("route", "$.document.rowNodeId", "INVALID_ROUTE_TERMINAL_NODE", "route does not terminate at rowNodeId", map[string]any{"terminalNodeId": current, "rowNodeId": document.RowNodeID}) - } - return steps, nil -} - -type authoringAssignment struct { - CandidateID, OccurrenceID, ProjectionMode string - Selection explorer.CatalogSelection -} - -func resolveAuthoringCandidates(document explorer.ExplorerBuilderDocumentV1, catalog explorer.Catalog, route []authoringRouteStep) ([]authoringAssignment, error) { - selections := catalog.Selections - pathNodes := map[string][]string{"base": {document.BaseNodeID}} - for _, step := range route { - pathNodes[step.Occurrence.ID] = append(pathNodes[step.Occurrence.ID], step.NodeID) - } - byCandidateOccurrence := map[string][]string{} - projectionByPair := map[string]string{} - seenAssignment := map[string]bool{} - for _, reference := range document.CandidateOccurrences { - key := reference.CandidateID + "\x00" + reference.OccurrenceID - if seenAssignment[key] { - return nil, authoringSemantic("candidates", "$.document.candidateOccurrences", "DUPLICATE_CANDIDATE_OCCURRENCE", "a candidate occurrence may be listed only once", nil) - } - seenAssignment[key] = true - byCandidateOccurrence[reference.CandidateID] = append(byCandidateOccurrence[reference.CandidateID], reference.OccurrenceID) - projectionByPair[key] = strings.TrimSpace(reference.ProjectionMode) - } - assignments := make([]authoringAssignment, 0, len(document.CandidateIDs)) - for i, candidateID := range document.CandidateIDs { - selection, ok := selections[candidateID] - if !ok { - return nil, authoringSemantic("candidates", fmt.Sprintf("$.document.candidateIds[%d]", i), "STALE_CANDIDATE_ID", "candidate is not present in the catalog snapshot", map[string]any{"candidateId": candidateID}) - } - occurrenceIDs := byCandidateOccurrence[candidateID] - matches := make([]string, 0, 2) - for id, nodeIDs := range pathNodes { - for _, nodeID := range nodeIDs { - if nodeID == selection.NodeID { - matches = append(matches, id) - break - } - } - } - if len(matches) == 0 { - return nil, authoringSemantic("candidates", fmt.Sprintf("$.document.candidateIds[%d]", i), "SELECTION_NODE_MISMATCH", "candidate does not belong to the base node or any route occurrence in this document", map[string]any{"candidateId": candidateID, "selectionNodeId": selection.NodeID, "routeNodeIds": pathNodes}) - } - if len(occurrenceIDs) == 0 { - return nil, authoringSemantic("candidates", fmt.Sprintf("$.document.candidateOccurrences"), "CANDIDATE_OCCURRENCE_REQUIRED", "every selected candidate must identify its exact route occurrence", map[string]any{"candidateId": candidateID, "validOccurrences": matches}) - } - for _, occurrenceID := range occurrenceIDs { - if occurrenceID != "base" && !containsRouteOccurrence(route, occurrenceID) { - return nil, authoringSemantic("candidates", "$.document.candidateOccurrences", "STALE_ROUTE_OCCURRENCE", "candidate references a stale route occurrence", map[string]any{"occurrenceId": occurrenceID}) - } - var occurrenceNode string - if occurrenceID == "base" { - occurrenceNode = document.BaseNodeID - } else { - for _, step := range route { - if step.Occurrence.ID == occurrenceID { - occurrenceNode = step.NodeID - break - } - } - } - if occurrenceNode != selection.NodeID { - return nil, authoringSemantic("candidates", "$.document.candidateOccurrences", "SELECTION_NODE_MISMATCH", "candidate is not valid at the referenced route occurrence", map[string]any{"candidateId": candidateID, "occurrenceId": occurrenceID}) - } - projectionMode := projectionByPair[candidateID+"\x00"+occurrenceID] - if projectionMode == "" { - projectionMode = selection.DefaultProjectionMode - } - if projectionMode != "" && !containsString(selection.ProjectionModes, projectionMode) { - return nil, authoringSemantic("candidates", "$.document.candidateOccurrences", "UNSUPPORTED_PROJECTION_MODE", "candidate projection mode is not advertised by the catalog snapshot", map[string]any{"candidateId": candidateID, "projectionMode": projectionMode, "supported": selection.ProjectionModes}) - } - assignments = append(assignments, authoringAssignment{CandidateID: candidateID, OccurrenceID: occurrenceID, ProjectionMode: projectionMode, Selection: selection}) - } - } - return assignments, nil -} - -func containsRouteOccurrence(route []authoringRouteStep, id string) bool { - for _, step := range route { - if step.Occurrence.ID == id { - return true - } - } - return false -} - -func authoringEmissions(document explorer.ExplorerBuilderDocumentV1, _ explorer.Catalog, assignments []authoringAssignment) ([]explorer.EmittedColumn, []explorer.IdentityMapping) { - byCandidateOccurrence := map[string][]string{} - emitted := make([]explorer.EmittedColumn, 0, len(assignments)) - for _, assignment := range assignments { - emissionID := explorer.OpaqueID("em_", document.Output.ID+"\x00"+assignment.OccurrenceID+"\x00"+assignment.CandidateID) - // PublicColumn must be the logical field name emitted by the native - // recipe. Publication may add the root-resource prefix, but the runtime - // projection can resolve that qualification only when the unqualified - // suffix is identical. Deriving this name from EmissionID instead gives - // it a different hash and leaves previews/runtime tables with column - // metadata that cannot address any returned row value. - publicColumn := generatedFieldName(assignment.CandidateID, assignment.OccurrenceID) - column := explorer.EmittedColumn{EmissionID: emissionID, OutputID: document.Output.ID, NodeID: assignment.Selection.NodeID, SelectionID: assignment.CandidateID, CandidateID: assignment.CandidateID, OccurrenceID: assignment.OccurrenceID, PublicColumn: publicColumn, Filterable: assignment.Selection.Filterable, Chartable: assignment.Selection.Chartable} - emitted = append(emitted, column) - key := assignment.CandidateID + "\x00" + assignment.OccurrenceID - byCandidateOccurrence[key] = append(byCandidateOccurrence[key], emissionID) - } - mappings := make([]explorer.IdentityMapping, 0, len(byCandidateOccurrence)) - for _, assignment := range assignments { - key := assignment.CandidateID + "\x00" + assignment.OccurrenceID - if ids := byCandidateOccurrence[key]; len(ids) > 0 { - mappings = append(mappings, explorer.IdentityMapping{CandidateID: assignment.CandidateID, OccurrenceID: assignment.OccurrenceID, EmissionIDs: append([]string(nil), ids...)}) - delete(byCandidateOccurrence, key) - } - } - return emitted, mappings -} - -func resolvedAuthoringBinding(document explorer.ExplorerBuilderDocumentV1, catalog explorer.Catalog, route []authoringRouteStep, assignments []authoringAssignment, emitted []explorer.EmittedColumn) explorer.ExplorerResolvedBindingV1 { - base, _ := catalogNode(catalog, document.BaseNodeID) - row, _ := catalogNode(catalog, document.RowNodeID) - rowGrain, _ := spec.InferRowGrain(base.ResourceType) - kind := "ROUTE" - if len(route) == 0 { - kind = "ZERO_HOP" - } - result := explorer.ExplorerResolvedBindingV1{ - OutputID: document.Output.ID, OutputTitle: document.Output.Title, - BaseNodeID: document.BaseNodeID, BaseResourceType: base.ResourceType, - RowNodeID: document.RowNodeID, RowResourceType: row.ResourceType, - RowGrain: string(rowGrain), RouteKind: kind, - RouteOccurrences: []explorer.ExplorerResolvedOccurrenceV1{{OccurrenceID: "base", Index: 0, NodeID: document.BaseNodeID, ResourceType: base.ResourceType}}, - CandidateEmissions: []explorer.ExplorerCandidateEmissionV1{}, - } - for i, step := range route { - result.RouteOccurrences = append(result.RouteOccurrences, explorer.ExplorerResolvedOccurrenceV1{OccurrenceID: step.Occurrence.ID, Index: i + 1, NodeID: step.NodeID, ResourceType: nodeResourceType(catalog, step.NodeID), IncomingEdgeID: step.Edge.ID}) - } - emissionByKey := map[string]explorer.EmittedColumn{} - for _, column := range emitted { - emissionByKey[column.CandidateID+"\x00"+column.OccurrenceID] = column - } - for _, assignment := range assignments { - column := emissionByKey[assignment.CandidateID+"\x00"+assignment.OccurrenceID] - label := assignment.Selection.FieldRef - if presentation, ok := document.Presentation[column.EmissionID]; ok && strings.TrimSpace(presentation.Label) != "" { - label = presentation.Label - } - result.CandidateEmissions = append(result.CandidateEmissions, explorer.ExplorerCandidateEmissionV1{CandidateID: assignment.CandidateID, OccurrenceID: assignment.OccurrenceID, EmissionID: column.EmissionID, PublicColumn: column.PublicColumn, Label: label, LogicalType: firstNonEmpty(column.LogicalType, assignment.Selection.LogicalType), Filterable: column.Filterable, Chartable: column.Chartable}) - } - return result -} - -func validateAuthoringPresentation(document explorer.ExplorerBuilderDocumentV1, emitted []explorer.EmittedColumn) error { - known := map[string]explorer.EmittedColumn{} - for _, column := range emitted { - known[column.EmissionID] = column - } - for emissionID := range document.Presentation { - column, ok := known[emissionID] - if !ok { - return authoringSemantic("presentation", "$.document.presentation."+emissionID, "STALE_EMISSION", "presentation references an emission that is not in this compilation", map[string]any{"emissionId": emissionID}) - } - binding := document.Presentation[emissionID] - if binding.Filter != nil && !column.Filterable { - return authoringSemantic("presentation", "$.document.presentation."+emissionID+".filter", "UNSUPPORTED_FILTER_PRESENTATION", "the selected emission is not filterable", map[string]any{"emissionId": emissionID}) - } - if binding.Chart != nil && !column.Chartable { - return authoringSemantic("presentation", "$.document.presentation."+emissionID+".chart", "UNSUPPORTED_CHART_PRESENTATION", "the selected emission is not chartable", map[string]any{"emissionId": emissionID}) - } - } - return nil -} - -func lowerAuthoringDocument(project, explorerID string, document explorer.ExplorerBuilderDocumentV1, catalog explorer.Catalog, route []authoringRouteStep, assignments []authoringAssignment) (recipe.Bundle, error) { - base, ok := catalogNode(catalog, document.BaseNodeID) - if !ok { - return recipe.Bundle{}, authoringSemantic("route", "$.document.baseNodeId", "STALE_BASE_NODE", "base node is not present in the catalog snapshot", nil) - } - outputID := document.Output.ID - if !authoringIDPattern.MatchString(outputID) { - return recipe.Bundle{}, authoringSemantic("intent", "$.document.output.id", "INVALID_OUTPUT_ID", "output.id must be a stable lower-case identifier", nil) - } - rootResourceType, ok := fhirschema.CanonicalResourceType(base.ResourceType) - if !ok { - return recipe.Bundle{}, authoringSemantic("lower", "$.document.baseNodeId", "UNSUPPORTED_ROW_GRAIN", "the selected base resource has no supported row grain", map[string]any{"resourceType": base.ResourceType, "nodeId": base.ID}) - } - rowGrain, ok := spec.InferRowGrain(rootResourceType) - if !ok { - return recipe.Bundle{}, authoringSemantic("lower", "$.document.baseNodeId", "UNSUPPORTED_ROW_GRAIN", "the selected base resource has no supported row grain", map[string]any{"resourceType": base.ResourceType, "nodeId": base.ID}) - } - native := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "explorer_" + safeAuthoringName(project) + "_" + safeAuthoringName(explorerID), TranslationVersion: "authoring-v1", Outputs: []recipe.Output{{Name: outputID, RootResourceType: rootResourceType, RowGrain: string(rowGrain)}}} - byOccurrence := map[string][]authoringAssignment{} - for _, assignment := range assignments { - byOccurrence[assignment.OccurrenceID] = append(byOccurrence[assignment.OccurrenceID], assignment) - } - appendFields := func(fields *[]recipe.Field, occurrenceID, alias string) { - for _, assignment := range byOccurrence[occurrenceID] { - fieldName := generatedFieldName(assignment.CandidateID, occurrenceID) - selectPath := strings.TrimSpace(assignment.Selection.Select) - selectPath = strings.TrimPrefix(selectPath, "root.") - *fields = append(*fields, recipe.Field{Name: fieldName, FieldRef: assignment.Selection.FieldRef, Expr: recipe.Expression{Select: alias + "." + selectPath}, ValueMode: authoringValueMode(assignment.ProjectionMode)}) - } - } - appendFields(&native.Outputs[0].Fields, "base", "root") - var appendTraversals func(*[]recipe.Traversal, int, string) - appendTraversals = func(target *[]recipe.Traversal, index int, parentAlias string) { - if index >= len(route) { - return - } - step := route[index] - alias := "route_" + strconv.Itoa(index) - toResourceType, _ := fhirschema.CanonicalResourceType(nodeResourceType(catalog, step.NodeID)) - traversal := recipe.Traversal{Name: step.Edge.Label, Alias: alias, ToResourceType: toResourceType, MatchMode: recipe.MatchOptional} - appendFields(&traversal.Fields, step.Occurrence.ID, alias) - appendTraversals(&traversal.Traversals, index+1, alias) - *target = append(*target, traversal) - } - appendTraversals(&native.Outputs[0].Traversals, 0, "root") - return native, nil -} - -func authoringValueMode(projectionMode string) recipe.ValueMode { - switch strings.ToUpper(strings.TrimSpace(projectionMode)) { - case "FIRST": - return recipe.ValueModeFirst - case "ARRAY": - return recipe.ValueModeAll - case "DISTINCT_ARRAY": - return recipe.ValueModeDistinct - default: - return recipe.ValueModeAuto - } -} - -func catalogNode(catalog explorer.Catalog, id string) (explorer.CatalogNode, bool) { - for _, node := range catalog.Nodes { - if node.ID == id { - return node, true - } - } - return explorer.CatalogNode{}, false -} -func nodeResourceType(catalog explorer.Catalog, id string) string { - node, _ := catalogNode(catalog, id) - return node.ResourceType -} -func safeAuthoringName(value string) string { - value = strings.ToLower(value) - var b strings.Builder - for _, r := range value { - if r >= 'a' && r <= 'z' || r >= '0' && r <= '9' || r == '_' { - b.WriteRune(r) - } else { - b.WriteByte('_') - } - } - value = strings.Trim(b.String(), "_") - if value == "" { - return "x" - } - return value -} -func generatedFieldName(candidateID, occurrenceID string) string { - sum := sha256.Sum256([]byte(candidateID + "\x00" + occurrenceID)) - return "c_" + hex.EncodeToString(sum[:]) -} -func outputFingerprint(bundle recipe.Bundle, project, generation string) string { - raw, _ := json.Marshal(struct { - Bundle recipe.Bundle - Project, Generation string - }{bundle, project, generation}) - sum := sha256.Sum256(raw) - return hex.EncodeToString(sum[:]) -} - -func authoringCompiledConfig(bundle explorer.ExplorerAuthoringBundleV1, native recipe.Bundle, emitted []explorer.EmittedColumn) ([]byte, error) { - documents := bundle.AuthoringDocuments() - documentsByOutput := make(map[string]explorer.ExplorerBuilderDocumentV1, len(documents)) - emittedByOutput := make(map[string][]explorer.EmittedColumn, len(documents)) - for _, document := range documents { - documentsByOutput[document.Output.ID] = document - } - for _, column := range emitted { - emittedByOutput[column.OutputID] = append(emittedByOutput[column.OutputID], column) - } - tabs := bundle.AuthoringTabs() - sort.SliceStable(tabs, func(i, j int) bool { return tabs[i].Order < tabs[j].Order }) - views := make([]explorer.ConfigView, 0, len(tabs)) - for _, tab := range tabs { - if tab.Visible != nil && !*tab.Visible { - continue - } - document, ok := documentsByOutput[tab.OutputID] - if !ok { - return nil, authoringSemantic("presentation", "$.tabs", "TAB_OUTPUT_MISSING", "tab references an output that is not in the authoring bundle", map[string]any{"outputId": tab.OutputID}) - } - columns := make([]explorer.ConfigColumn, 0, len(emittedByOutput[tab.OutputID])) - filters := make([]explorer.ConfigFilter, 0) - charts := make([]explorer.ConfigChart, 0) - orderByColumn := map[string]int{} - for _, column := range emittedByOutput[tab.OutputID] { - binding := document.Presentation[column.EmissionID] - visible := true - if binding.Visible != nil { - visible = *binding.Visible - } - if binding.Order != nil { - orderByColumn[column.PublicColumn] = *binding.Order - } - label := firstNonEmpty(binding.Label, column.PublicColumn) - columns = append(columns, explorer.ConfigColumn{Column: column.PublicColumn, Label: label, Visible: visible}) - if binding.Filter != nil { - filters = append(filters, explorer.ConfigFilter{Column: column.PublicColumn, Label: binding.Filter.Label}) - } - if binding.Chart != nil { - charts = append(charts, explorer.ConfigChart{Column: column.PublicColumn, Type: binding.Chart.Type, Title: binding.Chart.Title}) - } - } - sort.SliceStable(columns, func(i, j int) bool { - left, leftOK := orderByColumn[columns[i].Column] - right, rightOK := orderByColumn[columns[j].Column] - if leftOK && rightOK && left != right { - return left < right - } - if leftOK != rightOK { - return leftOK - } - return columns[i].Column < columns[j].Column - }) - sort.Slice(filters, func(i, j int) bool { return filters[i].Column < filters[j].Column }) - sort.Slice(charts, func(i, j int) bool { return charts[i].Column < charts[j].Column }) - views = append(views, explorer.ConfigView{ID: tab.ID, Title: tab.Title, Output: tab.OutputID, Table: explorer.ConfigTable{Columns: columns}, Filters: filters, Charts: charts}) - } - config := explorer.ConfigV2{APIVersion: explorer.ConfigV2APIVersion, Kind: "ExplorerConfig", Project: bundle.Project, Explorer: explorer.ConfigExplorer{ID: bundle.ExplorerID, Title: firstNonEmpty(bundle.Title, documents[0].Output.Title, documents[0].Output.ID), Management: explorer.ConfigManagementForID(bundle.ExplorerID)}, Recipe: mustJSON(native), Views: views} - return json.Marshal(config) -} -func mustJSON(value any) json.RawMessage { raw, _ := json.Marshal(value); return raw } -func firstNonEmpty(values ...string) string { - for _, value := range values { - if strings.TrimSpace(value) != "" { - return value - } - } - return "Explorer" -} - -func authoringSemantic(stage, path, code, message string, details map[string]any) error { - return &explorer.AuthoringError{Status: 422, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: code, JSONPath: path, Message: message, Details: details}} -} -func explorerConflict(stage, code, message string, details map[string]any) error { - return &explorer.AuthoringError{Status: 409, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: code, Message: message, Details: details}} -} -func explorerUnavailable(stage, code, message string) error { - return &explorer.AuthoringError{Status: 503, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: code, Message: message}} -} -func withRequestAuthoringError(err error, requestID string) error { - var authoringErr *explorer.AuthoringError - if errors.As(err, &authoringErr) { - authoringErr.Diagnostic.RequestID = requestID - } - return err -} -func authoringSemanticFromRecipe(err error) error { - var validation *recipe.ValidationError - if errors.As(err, &validation) { - return authoringSemantic("recipe", validation.Path, "INVALID_COMPILED_RECIPE", validation.Message, map[string]any{"recipeCode": validation.Code}) - } - return authoringSemanticFromCompile(err) -} -func authoringSemanticFromCompile(err error) error { - message := err.Error() - code := "INVALID_AUTHORING_INTENT" - if strings.Contains(strings.ToLower(message), "traversal") { - code = "UNSUPPORTED_NESTED_TRAVERSAL" - } - return authoringSemantic("compile", "$", code, message, nil) -} diff --git a/internal/server/explorer_authoring_v1_routes.go b/internal/server/explorer_authoring_v1_routes.go deleted file mode 100644 index a1fc829a..00000000 --- a/internal/server/explorer_authoring_v1_routes.go +++ /dev/null @@ -1,533 +0,0 @@ -package server - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "io" - "log/slog" - "sort" - "strings" - "time" - - "github.com/calypr/loom/internal/authscope" - "github.com/calypr/loom/internal/dataframe/recipe" - "github.com/calypr/loom/internal/explorer" - "github.com/calypr/loom/internal/projectid" - "github.com/gofiber/fiber/v3" -) - -// RegisterExplorerAuthoringV1Routes exposes the publish-only Builder contract. -// GET /builder hydrates active state; POST /builder resolves local intent using -// the same response model without persisting a browser draft. -func RegisterExplorerAuthoringV1Routes(app *fiber.App, authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, explorers *explorer.Service, capabilities ExplorerV2LifecycleConfig) { - if app == nil || authorizer == nil || authorizeRead == nil || explorers == nil { - return - } - prefix := "/api/v1/projects/:project/explorers/:explorerId/authoring/v1" - - app.Get(prefix+"/capabilities", func(c fiber.Ctx) error { - if err := authoringRead(c, authorizeRead); err != nil { - return err - } - return c.JSON(fiber.Map{ - "apiVersion": explorer.ExplorerAuthoringV1APIVersion, - "kind": "ExplorerAuthoringCapabilities", - "operations": []string{"builder", "preview", "publish", "active-export", "table-identity", "create"}, - "publication": "last-writer-wins", - "features": fiber.Map{ - "emissionFilters": true, "emissionCharts": true, - "sharedFilters": false, "fixedFilters": false, - "fileActions": false, "deleteExplorer": false, - }, - }) - }) - - app.Post(prefix+"/table-identity", func(c fiber.Ctx) error { - if err := authoringWrite(c, authorizer); err != nil { - return err - } - var request struct { - Title string `json:"title"` - RequestID string `json:"requestId"` - OccupiedOutputIDs []string `json:"occupiedOutputIds,omitempty"` - OccupiedTabIDs []string `json:"occupiedTabIds,omitempty"` - } - if err := decodeAuthoringStrict(c.Body(), &request); err != nil || strings.TrimSpace(request.Title) == "" || strings.TrimSpace(request.RequestID) == "" { - if err == nil { - err = fmt.Errorf("title and requestId are required") - } - return authoringHTTPError(c, &explorer.AuthoringError{Status: 400, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "decode", Code: "MALFORMED_AUTHORING_REQUEST", JSONPath: "$", Message: err.Error()}}) - } - seed := explorerProjectParam(c) + "\x00" + strings.TrimSpace(c.Params("explorerId")) + "\x00" + strings.TrimSpace(request.RequestID) - outputID := explorer.OpaqueID("out_", seed) - tabID := explorer.OpaqueID("tab_", seed) - return c.JSON(fiber.Map{ - "apiVersion": explorer.ExplorerAuthoringV1APIVersion, - "kind": "ExplorerTableIdentity", - "output": explorer.ExplorerOutputIdentityV1{ID: outputID, Title: strings.TrimSpace(request.Title)}, - "tab": fiber.Map{"id": tabID, "title": strings.TrimSpace(request.Title), "outputId": outputID}, - }) - }) - - app.Get(prefix+"/builder", func(c fiber.Ctx) error { - if err := authoringRead(c, authorizeRead); err != nil { - return err - } - state, err := loadExplorerBuilderState(c.Context(), explorers, capabilities, explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")), requestIDFromFiber(c)) - if err != nil { - return authoringHTTPError(c, err) - } - emissionCount := 0 - for _, binding := range state.Bindings { - emissionCount += len(binding.CandidateEmissions) - } - slog.Info("Explorer Builder state resolved", - "request_id", requestIDFromFiber(c), - "project", state.Project, - "explorer_id", state.ExplorerID, - "catalog_nodes", len(state.Catalog.Nodes), - "catalog_candidates", len(state.Catalog.Candidates), - "documents", len(state.Bundle.AuthoringDocuments()), - "bindings", len(state.Bindings), - "candidate_emissions", emissionCount, - ) - return c.JSON(state) - }) - - app.Post(prefix+"/builder", func(c fiber.Ctx) error { - if err := authoringWrite(c, authorizer); err != nil { - return err - } - var request struct { - Bundle explorer.ExplorerAuthoringBundleV1 `json:"bundle"` - SnapshotToken string `json:"snapshotToken"` - } - if err := decodeAuthoringStrict(c.Body(), &request); err != nil { - return authoringHTTPError(c, malformedRouteError("builder", err)) - } - logAuthoringCompatibilityRequest(c, "builder", request.Bundle) - if err := validateAuthoringRouteIdentity(c, request.Bundle); err != nil { - return authoringHTTPError(c, err) - } - if capabilities.AuthoringCompile == nil || capabilities.Catalog == nil { - return authoringHTTPError(c, explorerUnavailable("builder", "AUTHORING_COMPILER_UNAVAILABLE", "Explorer authoring resolver is not configured")) - } - project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) - if len(request.Bundle.AuthoringDocuments()) == 0 { - owner, err := explorers.Get(c.Context(), project, id) - if err != nil { - return authoringHTTPError(c, err) - } - snapshot, err := capabilities.Catalog(c.Context(), project, id, "") - if err != nil || !snapshot.Complete || snapshot.Truncated { - return authoringHTTPError(c, explorerUnavailable("catalog", "CATALOG_UNAVAILABLE", "Explorer authoring catalog is unavailable or incomplete")) - } - if err := snapshot.ValidateToken(request.SnapshotToken); err != nil { - return authoringHTTPError(c, explorerConflict("catalog", "STALE_CATALOG_SNAPSHOT", err.Error(), map[string]any{"snapshotToken": request.SnapshotToken})) - } - active, activeErr := explorers.ActiveRevision(c.Context(), project, id) - if errors.Is(activeErr, explorer.ErrNotFound) { - active = nil - } else if activeErr != nil { - return authoringHTTPError(c, activeErr) - } - state := newBuilderState(owner, request.Bundle, snapshot, nil, active) - return c.JSON(state) - } - resolved, err := capabilities.AuthoringCompile(c.Context(), ExplorerAuthoringV1CompileRequest{Bundle: request.Bundle, SnapshotToken: request.SnapshotToken, RequestID: requestIDFromFiber(c)}) - if err != nil { - return authoringHTTPError(c, err) - } - active, activeErr := explorers.ActiveRevision(c.Context(), project, id) - if errors.Is(activeErr, explorer.ErrNotFound) { - active = nil - } else if activeErr != nil { - return authoringHTTPError(c, activeErr) - } - state, err := builderStateFromResolved(c.Context(), explorers, capabilities, project, id, resolved, active) - if err != nil { - return authoringHTTPError(c, err) - } - return c.JSON(state) - }) - - app.Post(prefix+"/preview", func(c fiber.Ctx) error { - if err := authoringRead(c, authorizeRead); err != nil { - return err - } - var request struct { - Bundle explorer.ExplorerAuthoringBundleV1 `json:"bundle"` - SnapshotToken string `json:"snapshotToken"` - OutputID string `json:"outputId"` - Limit int `json:"limit"` - } - if err := decodeAuthoringStrict(c.Body(), &request); err != nil { - return authoringHTTPError(c, malformedRouteError("preview", err)) - } - logAuthoringCompatibilityRequest(c, "preview", request.Bundle) - if request.Limit == 0 { - request.Limit = 25 - } - if request.Limit < 1 || request.Limit > 1000 { - return authoringHTTPError(c, authoringSemanticRoute("preview", "$.limit", "INVALID_PREVIEW_LIMIT", "limit must be between 1 and 1000", nil)) - } - if err := validateAuthoringRouteIdentity(c, request.Bundle); err != nil { - return authoringHTTPError(c, err) - } - if capabilities.AuthoringCompile == nil || capabilities.Preview == nil { - return authoringHTTPError(c, explorerUnavailable("preview", "PREVIEW_UNAVAILABLE", "Explorer preview is not configured")) - } - resolved, err := capabilities.AuthoringCompile(c.Context(), ExplorerAuthoringV1CompileRequest{Bundle: request.Bundle, SnapshotToken: request.SnapshotToken, RequestID: requestIDFromFiber(c)}) - if err != nil { - return authoringHTTPError(c, err) - } - if !receiptHasOutput(resolved.Receipt.Bundle, request.OutputID) { - return authoringHTTPError(c, authoringSemanticRoute("preview", "$.outputId", "UNKNOWN_AUTHORING_OUTPUT", "outputId is not in the authoring bundle", nil)) - } - rows, err := capabilities.Preview(c.Context(), resolved.Receipt.Bundle, recipe.RuntimeBindings{Project: projectid.Legacy(explorerProjectParam(c)), DatasetGeneration: resolved.SourceGeneration, PreviewLimit: request.Limit, OutputNames: []string{request.OutputID}}) - if err != nil { - return authoringHTTPError(c, &explorer.AuthoringError{Status: 422, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "preview", Code: "AUTHORING_PREVIEW_FAILED", Message: "authoring bundle could not be previewed"}, Cause: err}) - } - return c.JSON(fiber.Map{"outputId": request.OutputID, "columns": previewColumnsForOutput(resolved.ResolvedBindings, request.OutputID), "rows": rows[request.OutputID], "rowCount": len(rows[request.OutputID]), "snapshotToken": request.SnapshotToken, "generation": resolved.SourceGeneration, "diagnostics": resolved.Diagnostics}) - }) - - app.Post(prefix+"/publish", func(c fiber.Ctx) error { - if err := authoringWrite(c, authorizer); err != nil { - return err - } - var request struct { - Bundle explorer.ExplorerAuthoringBundleV1 `json:"bundle"` - SnapshotToken string `json:"snapshotToken"` - } - if err := decodeAuthoringStrict(c.Body(), &request); err != nil { - return authoringHTTPError(c, malformedRouteError("publish", err)) - } - logAuthoringCompatibilityRequest(c, "publish", request.Bundle) - if err := validateAuthoringRouteIdentity(c, request.Bundle); err != nil { - return authoringHTTPError(c, err) - } - if capabilities.AuthoringCompile == nil || capabilities.Materialize == nil || capabilities.ActivateRelease == nil || capabilities.ValidateReleaseGeneration == nil { - return authoringHTTPError(c, explorerUnavailable("publish", "PUBLICATION_UNAVAILABLE", "Explorer publication is not configured")) - } - resolved, err := capabilities.AuthoringCompile(c.Context(), ExplorerAuthoringV1CompileRequest{Bundle: request.Bundle, SnapshotToken: request.SnapshotToken, RequestID: requestIDFromFiber(c)}) - if err != nil { - return authoringHTTPError(c, err) - } - receipt := resolved.Receipt - revisionID := "authoring_" + strings.TrimPrefix(receipt.ID, "receipt_") - if active, activeErr := explorers.ActiveRevision(c.Context(), receipt.Project, receipt.ExplorerID); activeErr == nil && active.ID == revisionID { - state, stateErr := builderStateFromResolved(c.Context(), explorers, capabilities, receipt.Project, receipt.ExplorerID, resolved, active) - if stateErr != nil { - return authoringHTTPError(c, stateErr) - } - return c.JSON(state) - } - if err := capabilities.ValidateReleaseGeneration(c.Context(), projectid.Legacy(receipt.Project), receipt.SourceGeneration); err != nil { - return authoringHTTPError(c, &explorer.AuthoringError{Status: 409, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "snapshot", Code: "SNAPSHOT_CONFLICT", Message: "the catalog generation is no longer active", Details: map[string]any{"generation": receipt.SourceGeneration}}, Cause: err}) - } - execution, err := capabilities.Materialize(c.Context(), receipt.Bundle, recipe.RuntimeBindings{Project: projectid.Legacy(receipt.Project), DatasetGeneration: receipt.SourceGeneration}) - if err != nil { - return authoringHTTPError(c, &explorer.AuthoringError{Status: 503, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "materialize", Code: "MATERIALIZATION_FAILED", Message: "Explorer materialization failed; the active revision was retained"}, Cause: err}) - } - if err := verifyQueryableOutputs(receipt.Bundle, execution); err != nil { - return authoringHTTPError(c, &explorer.AuthoringError{Status: 503, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "materialize", Code: "MATERIALIZATION_FAILED", Message: "materialization did not produce queryable outputs"}, Cause: err}) - } - if err := capabilities.ActivateRelease(c.Context(), projectid.Legacy(receipt.Project), receipt.SourceGeneration, selectorsForBundle(receipt.Bundle)); err != nil { - return authoringHTTPError(c, &explorer.AuthoringError{Status: 503, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "activation", Code: "MATERIALIZATION_ACTIVATION_FAILED", Message: "dataset release activation failed; the active revision was retained"}, Cause: err}) - } - now := time.Now().UTC() - _, err = explorers.PublishAuthoring(c.Context(), receipt, explorer.Revision{ID: revisionID, Project: receipt.Project, ExplorerID: receipt.ExplorerID, Config: receipt.CompiledConfig, ConfigDigest: receipt.IntentDigest, AuthoringBundle: receipt.NormalizedBundle, IntentDigest: receipt.IntentDigest, CompilationReceiptID: receipt.ID, Recipe: receipt.Bundle, RecipeDigest: receipt.RecipeDigest, ResolvedSchemaDigest: receipt.ResolvedSchemaDigest, SourceGeneration: receipt.SourceGeneration, Materializations: explorerMaterializations(receipt.Bundle, execution), EmittedColumns: receipt.EmittedColumns, Dataset: datasetMetadataFromExecution(receipt.Bundle, receipt.SourceGeneration, receipt.ResolvedSchemaDigest, execution), Publication: explorer.PublicationMetadata{State: string(explorer.RevisionReady), Generation: receipt.SourceGeneration, ExecutionID: execution.ID, UpdatedAt: now}, Status: explorer.RevisionReady, CreatedBy: subjectFromFiber(c), CreatedAt: now, ReadyAt: &now}) - if err != nil { - return authoringHTTPError(c, &explorer.AuthoringError{Status: 500, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "persist", Code: "REVISION_STORE_FAILED", Message: "could not store the immutable Explorer revision"}, Cause: err}) - } - active, err := explorers.ActiveRevision(c.Context(), receipt.Project, receipt.ExplorerID) - if err != nil { - return authoringHTTPError(c, err) - } - state, err := builderStateFromResolved(c.Context(), explorers, capabilities, receipt.Project, receipt.ExplorerID, resolved, active) - if err != nil { - return authoringHTTPError(c, err) - } - return c.JSON(state) - }) - - app.Get(prefix+"/bundle/active", func(c fiber.Ctx) error { - if err := authoringRead(c, authorizeRead); err != nil { - return err - } - revision, err := explorers.ActiveRevision(c.Context(), explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId"))) - if err != nil { - return authoringHTTPError(c, err) - } - if len(revision.AuthoringBundle) == 0 { - return authoringHTTPError(c, authoringSemanticRoute("export", "$", "ACTIVE_AUTHORING_BUNDLE_MISSING", "active Explorer has no authoring bundle", nil)) - } - bundle, err := explorer.DecodeAuthoringBundleV1ForMigration(revision.AuthoringBundle) - if err != nil { - return authoringHTTPError(c, err) - } - canonical, err := bundle.CanonicalJSON() - if err != nil { - return authoringHTTPError(c, err) - } - c.Set("Content-Type", "application/json") - return c.Send(canonical) - }) -} - -func validateAuthoringRouteIdentity(c fiber.Ctx, bundle explorer.ExplorerAuthoringBundleV1) error { - if projectid.Canonical(bundle.Project) != explorerProjectParam(c) || bundle.ExplorerID != strings.TrimSpace(c.Params("explorerId")) { - return explorerConflict("scope", "AUTHORING_IDENTITY_CONFLICT", "the authoring bundle identity does not match the route scope", nil) - } - return nil -} - -func loadExplorerBuilderState(ctx context.Context, service *explorer.Service, capabilities ExplorerV2LifecycleConfig, project, id, requestID string) (*explorer.ExplorerBuilderStateV1, error) { - owner, err := service.Get(ctx, project, id) - if err != nil { - return nil, err - } - if capabilities.Catalog == nil { - return nil, explorerUnavailable("catalog", "CATALOG_UNAVAILABLE", "Explorer authoring catalog is not configured") - } - snapshot, err := capabilities.Catalog(ctx, project, id, "") - if err != nil || !snapshot.Complete || snapshot.Truncated { - return nil, explorerUnavailable("catalog", "CATALOG_UNAVAILABLE", "Explorer authoring catalog is unavailable or incomplete") - } - active, err := service.ActiveRevision(ctx, project, id) - if errors.Is(err, explorer.ErrNotFound) { - bundle := explorer.ExplorerAuthoringBundleV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, Project: projectid.Canonical(project), ExplorerID: id, Title: owner.Title, Documents: []explorer.ExplorerBuilderDocumentV1{}} - state := newBuilderState(owner, bundle, snapshot, nil, nil) - return &state, nil - } - if err != nil { - return nil, err - } - if len(active.AuthoringBundle) == 0 { - return nil, &explorer.AuthoringError{Status: 422, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "builder", Code: "ACTIVE_AUTHORING_BUNDLE_MISSING", Message: "active Explorer cannot be edited because its authoring bundle is missing", RequestID: requestID}} - } - bundle, err := explorer.DecodeAuthoringBundleV1ForMigration(active.AuthoringBundle) - if err != nil { - return nil, &explorer.AuthoringError{Status: 422, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "builder", Code: "ACTIVE_AUTHORING_BUNDLE_INVALID", Message: "active Explorer authoring state is invalid", RequestID: requestID}, Cause: err} - } - if capabilities.AuthoringCompile == nil { - return nil, explorerUnavailable("builder", "AUTHORING_COMPILER_UNAVAILABLE", "Explorer authoring resolver is not configured") - } - resolved, err := capabilities.AuthoringCompile(ctx, ExplorerAuthoringV1CompileRequest{Bundle: bundle, SnapshotToken: snapshot.Token, RequestID: requestID}) - if err != nil { - return nil, err - } - return builderStateFromResolved(ctx, service, capabilities, project, id, resolved, active) -} - -func builderStateFromResolved(ctx context.Context, service *explorer.Service, capabilities ExplorerV2LifecycleConfig, project, id string, resolved ExplorerAuthoringV1CompileResult, active *explorer.Revision) (*explorer.ExplorerBuilderStateV1, error) { - owner, err := service.Get(ctx, project, id) - if err != nil { - return nil, err - } - // ResolveAuthoringBundle already validated and resolved this exact - // snapshot. Reuse it for the Builder response so catalog metadata and - // bindings are guaranteed to describe the same generation/token. - snapshot := resolved.Snapshot - if snapshot.Token == "" { - var snapshotErr error - snapshot, snapshotErr = capabilities.Catalog(ctx, project, id, resolved.SourceGeneration) - if snapshotErr != nil { - return nil, explorerUnavailable("catalog", "CATALOG_UNAVAILABLE", snapshotErr.Error()) - } - } - state := newBuilderState(owner, resolved.Bundle, snapshot, resolved.ResolvedBindings, active) - state.Diagnostics = append(state.Diagnostics, resolved.Diagnostics...) - return &state, nil -} - -func newBuilderState(owner *explorer.Explorer, bundle explorer.ExplorerAuthoringBundleV1, snapshot explorer.CatalogSnapshot, bindings []explorer.ExplorerResolvedBindingV1, active *explorer.Revision) explorer.ExplorerBuilderStateV1 { - state := explorer.ExplorerBuilderStateV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerBuilderStateV1Kind, Project: projectid.Canonical(owner.Project), ExplorerID: owner.ExplorerID, Title: owner.Title, Bundle: bundle, Catalog: builderCatalog(snapshot), Bindings: bindings, Diagnostics: []explorer.AuthoringDiagnostic{}} - if state.Bindings == nil { - state.Bindings = []explorer.ExplorerResolvedBindingV1{} - } - if active != nil { - state.Active = explorer.ExplorerBuilderPublicationV1{RevisionID: active.ID, State: string(active.Status), Generation: active.SourceGeneration, IntentDigest: active.IntentDigest} - if active.ActivatedAt != nil { - state.Active.PublishedAt = *active.ActivatedAt - } - if active.Migration != nil { - state.Active.Migration = &explorer.ExplorerMigrationSummaryV1{ - Kind: active.Migration.Kind, - Source: active.Migration.Source, - SourceProject: active.Migration.SourceProject, - SourceExplorerID: active.Migration.SourceExplorerID, - OriginalConfigDigest: active.Migration.OriginalConfigDigest, - OriginalMappingDigest: active.Migration.OriginalMappingDigest, - MigratedAt: active.Migration.MigratedAt, - } - } - } - return state -} - -func builderCatalog(snapshot explorer.CatalogSnapshot) explorer.ExplorerBuilderCatalogV1 { - result := explorer.ExplorerBuilderCatalogV1{SnapshotToken: snapshot.Token, Generation: snapshot.Generation, ResolvedSchemaDigest: snapshot.ResolvedSchemaDigest, AuthorizationScopeDigest: snapshot.AuthorizationScopeDigest, Nodes: []explorer.ExplorerCatalogNodeV1{}, Edges: []explorer.ExplorerCatalogEdgeV1{}, Candidates: []explorer.ExplorerCandidateV1{}} - for _, node := range snapshot.Catalog.Nodes { - result.Nodes = append(result.Nodes, explorer.ExplorerCatalogNodeV1{NodeID: node.ID, ResourceType: node.ResourceType}) - } - for _, edge := range snapshot.Catalog.Edges { - result.Edges = append(result.Edges, explorer.ExplorerCatalogEdgeV1{EdgeID: edge.ID, FromNodeID: edge.FromNodeID, ToNodeID: edge.ToNodeID, Label: edge.Label}) - } - ids := make([]string, 0, len(snapshot.Catalog.Selections)) - for id := range snapshot.Catalog.Selections { - ids = append(ids, id) - } - sort.Strings(ids) - for _, id := range ids { - candidate := snapshot.Catalog.Selections[id] - result.Candidates = append(result.Candidates, explorer.ExplorerCandidateV1{CandidateID: candidate.ID, NodeID: candidate.NodeID, Label: candidate.FieldRef, LogicalType: candidate.LogicalType, Filterable: candidate.Filterable, Chartable: candidate.Chartable}) - } - return result -} - -// Retained for migration and contract tests; no standalone catalog route uses it. -func authoringCatalogResponse(snapshot explorer.CatalogSnapshot) fiber.Map { - catalog := builderCatalog(snapshot) - candidates := make([]fiber.Map, 0, len(catalog.Candidates)) - for _, candidate := range catalog.Candidates { - candidates = append(candidates, fiber.Map{"candidateId": candidate.CandidateID, "nodeId": candidate.NodeID, "label": candidate.Label, "path": candidate.Label, "fieldRef": candidate.Label, "logicalType": candidate.LogicalType, "filterable": candidate.Filterable, "chartable": candidate.Chartable}) - } - return fiber.Map{"apiVersion": explorer.ExplorerAuthoringV1APIVersion, "kind": "ExplorerAuthoringCatalog", "snapshotToken": snapshot.Token, "project": snapshot.Project, "sourceGeneration": snapshot.Generation, "authorizationScopeDigest": snapshot.AuthorizationScopeDigest, "resolvedSchemaDigest": snapshot.ResolvedSchemaDigest, "nodes": catalog.Nodes, "routeEdges": catalog.Edges, "candidates": candidates, "diagnostics": snapshot.Diagnostics} -} - -func decodeAuthoringStrict(raw []byte, value any) error { - if err := explorer.RejectDuplicateJSONKeys(raw); err != nil { - return err - } - decoder := json.NewDecoder(bytes.NewReader(raw)) - decoder.DisallowUnknownFields() - if err := decoder.Decode(value); err != nil { - return err - } - var trailing any - if err := decoder.Decode(&trailing); err != io.EOF { - if err == nil { - return fmt.Errorf("multiple JSON values") - } - return err - } - return nil -} - -func authoringRead(c fiber.Ctx, authorizeRead explorerConfigReadAuthorizer) error { - if err := authorizeRead(c.Context(), principalFromFiber(c), explorerProjectParam(c)); err != nil { - return authoringHTTPError(c, &explorer.AuthoringError{Status: 403, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "authorization", Code: "FORBIDDEN", Message: "forbidden"}, Cause: err}) - } - return nil -} -func authoringWrite(c fiber.Ctx, authorizer authscope.Authorizer) error { - project := explorerProjectParam(c) - path := authscope.NormalizeAuthResourcePath(strings.TrimSpace(c.Query("auth_resource_path"))) - if err := authorizer.AuthorizeWrite(c.Context(), principalFromFiber(c), project, path); err != nil { - return authoringHTTPError(c, &explorer.AuthoringError{Status: 403, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "authorization", Code: "FORBIDDEN", Message: "forbidden"}, Cause: err}) - } - return nil -} -func requestIDFromFiber(c fiber.Ctx) string { - value, _ := c.Locals("request_id").(string) - return value -} - -// logAuthoringCompatibilityRequest is intentionally scoped to the incident -// request so normal Builder traffic never writes full authoring documents to -// logs. It records the raw envelope plus the three fields needed to determine -// whether the frontend or Loom dropped candidate occurrence mappings. -func logAuthoringCompatibilityRequest(c fiber.Ctx, operation string, bundle explorer.ExplorerAuthoringBundleV1) { - if requestIDFromFiber(c) != "f9131e28d8e058da07145008a1e93970" { - return - } - for index, document := range bundle.AuthoringDocuments() { - slog.Info("Explorer authoring compatibility request", - "request_id", requestIDFromFiber(c), - "operation", operation, - "document_index", index, - "document_candidate_ids", document.CandidateIDs, - "document_candidate_occurrences", document.CandidateOccurrences, - "document_route_occurrences", document.RouteOccurrences, - "raw_body", string(c.Body()), - ) - } -} - -func malformedRouteError(stage string, err error) error { - return &explorer.AuthoringError{Status: 400, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: "MALFORMED_AUTHORING_REQUEST", JSONPath: "$", Message: err.Error()}, Cause: err} -} -func authoringSemanticRoute(stage, path, code, message string, details map[string]any) error { - return &explorer.AuthoringError{Status: 422, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: stage, Code: code, JSONPath: path, Message: message, Details: details}} -} -func receiptHasOutput(bundle recipe.Bundle, id string) bool { - for _, output := range bundle.Outputs { - if output.Name == id { - return true - } - } - return false -} -func previewColumnsForOutput(bindings []explorer.ExplorerResolvedBindingV1, output string) []explorer.ExplorerPreviewColumnV1 { - columns := []explorer.ExplorerPreviewColumnV1{} - for _, binding := range bindings { - if binding.OutputID != output { - continue - } - for _, emission := range binding.CandidateEmissions { - columns = append(columns, explorer.ExplorerPreviewColumnV1{ - OutputID: output, CandidateID: emission.CandidateID, OccurrenceID: emission.OccurrenceID, - EmissionID: emission.EmissionID, PublicColumn: emission.PublicColumn, Label: emission.Label, - LogicalType: emission.LogicalType, Filterable: emission.Filterable, Chartable: emission.Chartable, - }) - } - } - return columns -} -func authoringHTTPError(c fiber.Ctx, err error) error { - requestID := requestIDFromFiber(c) - var value *explorer.AuthoringError - if errors.As(err, &value) { - value.Diagnostic.RequestID = requestID - cause := value.Cause - if cause == nil { - cause = err - } - logAuthoringRequestFailure(c, requestID, value.Status, value.Diagnostic.Stage, value.Diagnostic.Code, value.Diagnostic.JSONPath, value.Diagnostic.Message, value.Diagnostic.Details, cause) - details := value.Diagnostic.Details - if details == nil { - details = map[string]any{} - } - diagnostic := fiber.Map{"severity": strings.ToLower(value.Diagnostic.Severity), "stage": value.Diagnostic.Stage, "code": value.Diagnostic.Code, "path": value.Diagnostic.JSONPath, "message": value.Diagnostic.Message, "requestId": requestID} - return c.Status(value.Status).JSON(fiber.Map{"code": value.Diagnostic.Code, "message": value.Diagnostic.Message, "diagnostics": []fiber.Map{diagnostic}, "requestId": requestID, "details": details}) - } - if errors.Is(err, explorer.ErrNotFound) { - return c.Status(404).JSON(fiber.Map{"code": "NOT_FOUND", "message": "Explorer resource not found", "diagnostics": []any{}, "requestId": requestID, "details": fiber.Map{}}) - } - logAuthoringRequestFailure(c, requestID, 500, "internal", "INTERNAL_ERROR", "", "internal server error", nil, err) - return c.Status(500).JSON(fiber.Map{"code": "INTERNAL_ERROR", "message": "internal server error", "diagnostics": []any{}, "requestId": requestID, "details": fiber.Map{}}) -} - -func logAuthoringRequestFailure(c fiber.Ctx, requestID string, status int, stage, code, jsonPath, message string, details map[string]any, cause error) { - attrs := []any{ - "request_id", requestID, - "method", c.Method(), - "path", c.Path(), - "status", status, - "project", explorerProjectParam(c), - "explorer_id", strings.TrimSpace(c.Params("explorerId")), - "stage", stage, - "code", code, - "json_path", jsonPath, - "message", message, - "details", details, - } - if cause != nil { - attrs = append(attrs, "cause", cause, "cause_type", fmt.Sprintf("%T", cause)) - } - slog.Error("Explorer authoring request failed", attrs...) -} diff --git a/internal/server/explorer_authoring_v1_test.go b/internal/server/explorer_authoring_v1_test.go deleted file mode 100644 index 2258875a..00000000 --- a/internal/server/explorer_authoring_v1_test.go +++ /dev/null @@ -1,440 +0,0 @@ -package server - -import ( - "context" - "encoding/json" - "errors" - "net/http" - "strings" - "testing" - - graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" - "github.com/calypr/loom/internal/authscope" - "github.com/calypr/loom/internal/dataframe/recipe" - "github.com/calypr/loom/internal/dataset" - "github.com/calypr/loom/internal/explorer" - "github.com/gofiber/fiber/v3" -) - -func authoringTestSnapshot(t *testing.T) explorer.CatalogSnapshot { - t.Helper() - catalog := explorer.Catalog{ - Nodes: []explorer.CatalogNode{{ID: "n_base", ResourceType: "Patient"}, {ID: "n_child", ResourceType: "Observation"}}, - Edges: []explorer.CatalogEdge{{ID: "e_forward", FromNodeID: "n_base", ToNodeID: "n_child", Label: "observation"}}, - Selections: map[string]explorer.CatalogSelection{ - "s_base": {ID: "s_base", NodeID: "n_base", FieldRef: "Patient.id", Select: "id", LogicalType: "string", Filterable: true, Chartable: true}, - "s_child": {ID: "s_child", NodeID: "n_child", FieldRef: "Observation.status", Select: "status", LogicalType: "string", Filterable: true, Chartable: true}, - }, - } - snapshot, err := explorer.NewCatalogSnapshot("project-a", "generation-a", "scope-a", catalog, true, false, nil) - if err != nil { - t.Fatal(err) - } - return snapshot -} - -func authoringTestBundle(document explorer.ExplorerBuilderDocumentV1) explorer.ExplorerAuthoringBundleV1 { - if len(document.CandidateOccurrences) == 0 { - for _, candidateID := range document.CandidateIDs { - document.CandidateOccurrences = append(document.CandidateOccurrences, explorer.ExplorerCandidateOccurrenceV1{CandidateID: candidateID, OccurrenceID: "base"}) - } - } - return explorer.ExplorerAuthoringBundleV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, Project: "project-a", ExplorerID: "custom", Document: document} -} - -func TestAuthoringCatalogResponseIncludesCandidatePath(t *testing.T) { - response := authoringCatalogResponse(authoringTestSnapshot(t)) - candidates, ok := response["candidates"].([]fiber.Map) - if !ok || len(candidates) != 2 { - t.Fatalf("candidates=%#v", response["candidates"]) - } - for _, candidate := range candidates { - if candidate["path"] == "" || candidate["path"] != candidate["fieldRef"] { - t.Fatalf("candidate path compatibility alias is missing: %#v", candidate) - } - } -} - -func TestCompileAuthoringV1ZeroHopAndPresentationByEmission(t *testing.T) { - snapshot := authoringTestSnapshot(t) - visible := false - document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"s_base"}} - emission := explorer.OpaqueID("em_", "patient\x00base\x00s_base") - document.Presentation = map[string]explorer.ExplorerPresentationBindingV1{emission: {Label: "Patient ID", Visible: &visible, Filter: &explorer.ExplorerFilterBindingV1{Label: "Filter ID"}, Chart: &explorer.ExplorerChartBindingV1{Type: "bar", Title: "ID chart"}}} - result, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) - if err != nil { - t.Fatal(err) - } - if len(result.Receipt.EmittedColumns) != 1 || result.Receipt.EmittedColumns[0].EmissionID != emission { - t.Fatalf("emissions=%#v", result.Receipt.EmittedColumns) - } - publicColumn := result.Receipt.EmittedColumns[0].PublicColumn - if want := generatedFieldName("s_base", "base"); publicColumn != want { - t.Fatalf("public column=%q, want lowered recipe field %q", publicColumn, want) - } - if got := result.Receipt.Bundle.Outputs[0].Fields[0].Name; got != publicColumn { - t.Fatalf("lowered recipe field=%q, want emitted public column %q", got, publicColumn) - } - repeated, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) - if err != nil || repeated.Receipt.ID != result.Receipt.ID { - t.Fatalf("compilation is not deterministic: first=%q second=%q err=%v", result.Receipt.ID, repeated.Receipt.ID, err) - } - if strings.Contains(string(result.Receipt.NormalizedBundle), "select") || strings.Contains(string(result.Receipt.NormalizedBundle), "expr") || strings.Contains(string(result.Receipt.NormalizedBundle), "children") { - t.Fatalf("intent leaked recipe syntax: %s", result.Receipt.NormalizedBundle) - } - var config explorer.ConfigV2 - if err := json.Unmarshal(result.Receipt.CompiledConfig, &config); err != nil { - t.Fatal(err) - } - if len(config.Views) != 1 || len(config.Views[0].Table.Columns) != 1 || config.Views[0].Table.Columns[0].Column != publicColumn || config.Views[0].Table.Columns[0].Label != "Patient ID" || config.Views[0].Table.Columns[0].Visible || len(config.Views[0].Filters) != 1 || config.Views[0].Filters[0].Column != publicColumn || len(config.Views[0].Charts) != 1 || config.Views[0].Charts[0].Column != publicColumn { - t.Fatalf("presentation was not lowered by emission ID: %#v", config.Views) - } -} - -func TestCompileAuthoringV1UsesCatalogRowGrain(t *testing.T) { - snapshot := authoringTestSnapshot(t) - snapshot.Catalog.Nodes = append(snapshot.Catalog.Nodes, explorer.CatalogNode{ID: "n_file", ResourceType: "DocumentReference"}) - snapshot.Catalog.Selections["s_file"] = explorer.CatalogSelection{ID: "s_file", NodeID: "n_file", FieldRef: "DocumentReference.id", Select: "id"} - document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "files"}, BaseNodeID: "n_file", RowNodeID: "n_file", CandidateIDs: []string{"s_file"}} - result, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) - if err != nil { - t.Fatal(err) - } - if got := result.Receipt.Bundle.Outputs[0].RowGrain; got != "file" { - t.Fatalf("row grain=%q, want file", got) - } -} - -func TestCompileAuthoringV1CanonicalizesLowercaseCatalogResourceType(t *testing.T) { - snapshot := authoringTestSnapshot(t) - snapshot.Catalog.Nodes = []explorer.CatalogNode{{ID: "n_specimen", ResourceType: "specimen"}} - snapshot.Catalog.Edges = nil - snapshot.Catalog.Selections = map[string]explorer.CatalogSelection{} - document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "specimens"}, BaseNodeID: "n_specimen", RowNodeID: "n_specimen"} - result, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) - if err != nil { - t.Fatal(err) - } - output := result.Receipt.Bundle.Outputs[0] - if output.RootResourceType != "Specimen" || output.RowGrain != "specimen" { - t.Fatalf("lowered output root=%q grain=%q, want Specimen/specimen", output.RootResourceType, output.RowGrain) - } -} - -func TestCompileAuthoringV1RejectsLegacyLowercaseNodeID(t *testing.T) { - snapshot := authoringTestSnapshot(t) - canonicalNodeID := explorer.OpaqueID("n_", "Specimen") - legacyNodeID := explorer.OpaqueID("n_", "specimen") - snapshot.Catalog.Nodes = []explorer.CatalogNode{{ID: canonicalNodeID, ResourceType: "Specimen"}} - snapshot.Catalog.Edges = nil - snapshot.Catalog.Selections = map[string]explorer.CatalogSelection{} - document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "specimen"}, BaseNodeID: legacyNodeID, RowNodeID: legacyNodeID} - _, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) - if err == nil || !strings.Contains(err.Error(), "STALE_BASE_NODE") { - t.Fatalf("legacy node identity was accepted: %v", err) - } -} - -func TestCompileAuthoringV1NormalizesLegacyCandidateOccurrence(t *testing.T) { - snapshot := authoringTestSnapshot(t) - document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"s_base"}} - bundle := explorer.ExplorerAuthoringBundleV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, Project: "project-a", ExplorerID: "custom", Documents: []explorer.ExplorerBuilderDocumentV1{document}} - result, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: bundle, SnapshotToken: snapshot.Token}) - if err != nil { - t.Fatal(err) - } - documents := result.Bundle.AuthoringDocuments() - if len(documents) != 1 || len(documents[0].CandidateOccurrences) != 1 || documents[0].CandidateOccurrences[0].CandidateID != "s_base" || documents[0].CandidateOccurrences[0].OccurrenceID != "base" { - t.Fatalf("legacy candidate was not normalized: %#v", documents) - } -} - -func TestResolveAuthoringBundleUsesBaseNodeResourceTypesForGroupMemberAndFile(t *testing.T) { - snapshot := authoringTestSnapshot(t) - snapshot.Catalog.Nodes = []explorer.CatalogNode{{ID: "n_group", ResourceType: "Group"}, {ID: "n_file", ResourceType: "DocumentReference"}} - snapshot.Catalog.Edges = nil - snapshot.Catalog.Selections = map[string]explorer.CatalogSelection{} - bundle := authoringTestBundle(explorer.ExplorerBuilderDocumentV1{}) - bundle.Document = explorer.ExplorerBuilderDocumentV1{} - bundle.Documents = []explorer.ExplorerBuilderDocumentV1{ - {Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "groupmember", Title: "Members"}, BaseNodeID: "n_group", RowNodeID: "n_group"}, - {Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "file", Title: "Files"}, BaseNodeID: "n_file", RowNodeID: "n_file"}, - } - result, err := ResolveAuthoringBundle(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: bundle, SnapshotToken: snapshot.Token}) - if err != nil { - t.Fatal(err) - } - if len(result.ResolvedBindings) != 2 || result.ResolvedBindings[0].BaseResourceType != "Group" || result.ResolvedBindings[0].RouteKind != "ZERO_HOP" || result.ResolvedBindings[1].BaseResourceType != "DocumentReference" { - t.Fatalf("resolved bindings=%#v", result.ResolvedBindings) - } -} - -func TestCompileAuthoringV1PreservesMultipleOutputsAndTabs(t *testing.T) { - snapshot := authoringTestSnapshot(t) - patient := explorer.ExplorerBuilderDocumentV1{ - Kind: explorer.ExplorerBuilderV1Kind, - Output: explorer.ExplorerOutputIdentityV1{ID: "patient", Title: "Patients"}, - BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"s_base"}, - CandidateOccurrences: []explorer.ExplorerCandidateOccurrenceV1{{CandidateID: "s_base", OccurrenceID: "base"}}, - } - observations := explorer.ExplorerBuilderDocumentV1{ - Kind: explorer.ExplorerBuilderV1Kind, - Output: explorer.ExplorerOutputIdentityV1{ID: "observations", Title: "Observations"}, - BaseNodeID: "n_child", RowNodeID: "n_child", CandidateIDs: []string{"s_child"}, - CandidateOccurrences: []explorer.ExplorerCandidateOccurrenceV1{{CandidateID: "s_child", OccurrenceID: "base"}}, - } - bundle := authoringTestBundle(patient) - bundle.Document = explorer.ExplorerBuilderDocumentV1{} - bundle.Documents = []explorer.ExplorerBuilderDocumentV1{patient, observations} - bundle.Tabs = []explorer.ExplorerTabV1{ - {ID: "observations", Title: "Observations", OutputID: "observations", Order: 1}, - {ID: "patient", Title: "Patients", OutputID: "patient", Order: 0}, - } - result, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: bundle, SnapshotToken: snapshot.Token}) - if err != nil { - t.Fatal(err) - } - if len(result.Receipt.Bundle.Outputs) != 2 || len(result.Receipt.OutputFingerprints) != 2 { - t.Fatalf("compiled outputs=%#v fingerprints=%#v", result.Receipt.Bundle.Outputs, result.Receipt.OutputFingerprints) - } - var config explorer.ConfigV2 - if err := json.Unmarshal(result.Receipt.CompiledConfig, &config); err != nil { - t.Fatal(err) - } - if len(config.Views) != 2 || config.Views[0].ID != "patient" || config.Views[1].ID != "observations" || config.Views[0].Output != "patient" || config.Views[1].Output != "observations" { - t.Fatalf("tabs were not preserved: %#v", config.Views) - } - if strings.Contains(string(result.Receipt.NormalizedBundle), `"document"`) || !strings.Contains(string(result.Receipt.NormalizedBundle), `"documents"`) { - t.Fatalf("multi-output bundle was not canonicalized: %s", result.Receipt.NormalizedBundle) - } -} - -func TestCompileAuthoringV1MultiHopInboundAndRepeatedCandidateEmissions(t *testing.T) { - snapshot := authoringTestSnapshot(t) - // Catalog edges are already normalized into Builder direction. The - // compiler preserves the target occurrence while the lowerer independently - // proves that this Builder edge uses an inbound stored traversal. - snapshot.Catalog.Edges = []explorer.CatalogEdge{{ID: "e_inbound", FromNodeID: "n_base", ToNodeID: "n_child", Label: "subject"}} - document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_child", RouteEdgeIDs: []string{"e_inbound"}, RouteOccurrences: []explorer.ExplorerRouteOccurrenceV1{{ID: "child-1", Index: 0, NodeID: "n_child"}}, CandidateIDs: []string{"s_base", "s_child"}, CandidateOccurrences: []explorer.ExplorerCandidateOccurrenceV1{{CandidateID: "s_base", OccurrenceID: "base"}, {CandidateID: "s_child", OccurrenceID: "child-1"}, {CandidateID: "s_child", OccurrenceID: "child-1"}}} - if _, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}); err == nil || !strings.Contains(err.Error(), "DUPLICATE_CANDIDATE_OCCURRENCE") { - t.Fatalf("duplicate candidate occurrence error=%v", err) - } - document.CandidateOccurrences = document.CandidateOccurrences[:2] - result, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) - if err != nil { - t.Fatal(err) - } - if len(result.Receipt.Bundle.Outputs[0].Traversals) != 1 || result.Receipt.Bundle.Outputs[0].Traversals[0].ToResourceType != "Observation" { - t.Fatalf("bundle=%#v", result.Receipt.Bundle) - } - // The same candidate can intentionally emit once at two exact route - // occurrences when a resource type repeats. - snapshot.Catalog.Edges = append(snapshot.Catalog.Edges, explorer.CatalogEdge{ID: "e_back", FromNodeID: "n_child", ToNodeID: "n_base", Label: "patient"}) - repeated := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base", RouteEdgeIDs: []string{"e_inbound", "e_back"}, RouteOccurrences: []explorer.ExplorerRouteOccurrenceV1{{ID: "child-1", Index: 0, NodeID: "n_child"}, {ID: "base-2", Index: 1, NodeID: "n_base"}}, CandidateIDs: []string{"s_base"}, CandidateOccurrences: []explorer.ExplorerCandidateOccurrenceV1{{CandidateID: "s_base", OccurrenceID: "base"}, {CandidateID: "s_base", OccurrenceID: "base-2"}}} - repeatedResult, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(repeated), SnapshotToken: snapshot.Token}) - if err != nil { - t.Fatal(err) - } - count := 0 - for _, mapping := range repeatedResult.Receipt.IdentityMappings { - if mapping.CandidateID == "s_base" { - count += len(mapping.EmissionIDs) - } - } - if count != 2 { - t.Fatalf("candidate-to-emission mapping=%#v", repeatedResult.Receipt.IdentityMappings) - } -} - -func TestCompileAuthoringV1ReportsStaleCandidateBeforeRecipeValidation(t *testing.T) { - snapshot := authoringTestSnapshot(t) - document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"stale"}} - _, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) - if err == nil || !strings.Contains(err.Error(), "STALE_CANDIDATE_ID") { - t.Fatalf("error=%v", err) - } -} - -func TestCompileAuthoringV1ReportsCandidateNotOnRoute(t *testing.T) { - snapshot := authoringTestSnapshot(t) - document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"s_child"}} - _, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) - if err == nil || !strings.Contains(err.Error(), "SELECTION_NODE_MISMATCH") { - t.Fatalf("error=%v", err) - } -} - -func TestCompileAuthoringV1ReportsStaleRouteIdentities(t *testing.T) { - snapshot := authoringTestSnapshot(t) - baseStale := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "stale", RowNodeID: "stale"} - if _, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(baseStale), SnapshotToken: snapshot.Token}); err == nil || !strings.Contains(err.Error(), "STALE_BASE_NODE") { - t.Fatalf("stale base node error=%v", err) - } - staleEdge := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_child", RouteEdgeIDs: []string{"stale-edge"}, RouteOccurrences: []explorer.ExplorerRouteOccurrenceV1{{ID: "child", Index: 0, NodeID: "n_child"}}} - if _, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(staleEdge), SnapshotToken: snapshot.Token}); err == nil || !strings.Contains(err.Error(), "STALE_ROUTE_EDGE") { - t.Fatalf("stale route edge error=%v", err) - } -} - -func TestCompileAuthoringV1ReportsSnapshotConflict(t *testing.T) { - snapshot := authoringTestSnapshot(t) - document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base"} - _, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: "sha256:stale"}) - if err == nil || !strings.Contains(err.Error(), "STALE_CATALOG_SNAPSHOT") { - t.Fatalf("snapshot conflict error=%v", err) - } -} - -func TestCompileAuthoringV1RejectsStaleEmissionBeforeRecipeValidation(t *testing.T) { - snapshot := authoringTestSnapshot(t) - document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"s_base"}, Presentation: map[string]explorer.ExplorerPresentationBindingV1{"em_missing": {Label: "bad"}}} - _, err := compileExplorerAuthoringV1(context.Background(), nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) - if err == nil || !strings.Contains(err.Error(), "STALE_EMISSION") { - t.Fatalf("error=%v", err) - } -} - -func TestAuthoringV1ReceiptBoundLifecycleAndExport(t *testing.T) { - t.Skip("receipt/draft lifecycle removed by publish-only Builder cutover") - store := explorer.NewMemoryStore() - service, err := explorer.NewService(store) - if err != nil { - t.Fatal(err) - } - if _, err := store.CreateInteractive(context.Background(), explorer.Explorer{Project: "project-a", ExplorerID: "custom", ManagementMode: explorer.ManagementInteractive, DraftVersion: 1}); err != nil { - t.Fatal(err) - } - snapshot := authoringTestSnapshot(t) - compilerCalls := 0 - compiler := func(ctx context.Context, request ExplorerAuthoringV1CompileRequest) (ExplorerAuthoringV1CompileResult, error) { - compilerCalls++ - return compileExplorerAuthoringV1(ctx, nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, request) - } - previewCalls := 0 - materializeCalls := 0 - preview := func(_ context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (map[string][]map[string]any, error) { - previewCalls++ - if bindings.OutputNames[0] != bundle.Outputs[0].Name { - t.Fatalf("preview output=%v", bindings.OutputNames) - } - return map[string][]map[string]any{"patient": {{"id": "p1"}}}, nil - } - materialize := func(_ context.Context, bundle recipe.Bundle, _ recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { - materializeCalls++ - return graphresolver.RecipeExecution{ID: "execution-a", SourceGeneration: "generation-a", Outputs: []graphresolver.RecipeExecutionOutput{{Name: bundle.Outputs[0].Name, State: "PUBLISHED", Columns: nil}}}, nil - } - app := fiber.New() - RegisterExplorerAuthoringV1Routes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{AuthoringCompile: compiler, Catalog: func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, Preview: preview, Materialize: materialize, ValidateReleaseGeneration: func(context.Context, string, string) error { return nil }, ActivateRelease: func(context.Context, string, string, []dataset.DataframeSelector) error { return nil }}) - document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"s_base"}} - bundle := authoringTestBundle(document) - legacyCompileRequest := map[string]any{"apiVersion": bundle.APIVersion, "kind": bundle.Kind, "project": bundle.Project, "explorerId": bundle.ExplorerID, "document": bundle.Document, "snapshotToken": snapshot.Token} - legacyCompileRaw, _ := json.Marshal(legacyCompileRequest) - legacyCompile := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/compile", string(legacyCompileRaw)) - if legacyCompile.StatusCode != http.StatusNotFound { - t.Fatalf("legacy compile route status=%d body=%s", legacyCompile.StatusCode, legacyCompile.Body) - } - var compiledBody struct { - ReceiptID string `json:"receiptId"` - IntentDigest string `json:"intentDigest"` - } - directDraftRaw, _ := json.Marshal(map[string]any{"apiVersion": bundle.APIVersion, "kind": bundle.Kind, "project": bundle.Project, "explorerId": bundle.ExplorerID, "document": bundle.Document, "snapshotToken": snapshot.Token, "expectedDraftVersion": 1}) - saved := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/custom/authoring/v1/draft", string(directDraftRaw)) - if saved.StatusCode != http.StatusOK { - t.Fatalf("save=%d %s", saved.StatusCode, saved.Body) - } - decodeBody(t, saved.Body, &compiledBody) - saveRaw, _ := json.Marshal(map[string]any{"receiptId": compiledBody.ReceiptID, "expectedDraftVersion": 1}) - staleSave := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/custom/authoring/v1/draft", string(saveRaw)) - if staleSave.StatusCode != http.StatusConflict || !strings.Contains(staleSave.Body, "DRAFT_CONFLICT") { - t.Fatalf("stale save=%d %s", staleSave.StatusCode, staleSave.Body) - } - draftExport := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v1/bundle/draft", "") - if draftExport.StatusCode != http.StatusOK || !strings.Contains(draftExport.Body, compiledBody.IntentDigest) { - t.Fatalf("draft export=%d body=%s", draftExport.StatusCode, draftExport.Body) - } - previewRaw := `{"receiptId":"` + compiledBody.ReceiptID + `","outputId":"patient","limit":1}` - previewResponse := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/preview", previewRaw) - if previewResponse.StatusCode != http.StatusOK || previewCalls != 1 { - t.Fatalf("preview=%d calls=%d %s", previewResponse.StatusCode, previewCalls, previewResponse.Body) - } - directPreviewRequest := map[string]any{"apiVersion": bundle.APIVersion, "kind": bundle.Kind, "project": bundle.Project, "explorerId": bundle.ExplorerID, "document": bundle.Document, "snapshotToken": snapshot.Token, "outputId": "patient", "limit": 1} - directPreviewRaw, _ := json.Marshal(directPreviewRequest) - directPreview := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/preview", string(directPreviewRaw)) - if directPreview.StatusCode != http.StatusOK || previewCalls != 2 || compilerCalls != 2 || !strings.Contains(directPreview.Body, "candidateId") { - t.Fatalf("direct preview=%d previewCalls=%d compilerCalls=%d %s", directPreview.StatusCode, previewCalls, compilerCalls, directPreview.Body) - } - directDraftRequest := map[string]any{"apiVersion": bundle.APIVersion, "kind": bundle.Kind, "project": bundle.Project, "explorerId": bundle.ExplorerID, "document": bundle.Document, "snapshotToken": snapshot.Token, "expectedDraftVersion": 2} - directDraftRaw, _ = json.Marshal(directDraftRequest) - directDraft := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/custom/authoring/v1/draft", string(directDraftRaw)) - if directDraft.StatusCode != http.StatusOK || compilerCalls != 3 { - t.Fatalf("direct draft=%d compilerCalls=%d %s", directDraft.StatusCode, compilerCalls, directDraft.Body) - } - directPublished := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/publish", `{"expectedDraftVersion":3}`) - if directPublished.StatusCode != http.StatusOK || materializeCalls != 1 { - t.Fatalf("direct publish=%d materializeCalls=%d %s", directPublished.StatusCode, materializeCalls, directPublished.Body) - } - if got := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/preview", `{"receiptId":"`+compiledBody.ReceiptID+`","outputId":"patient","bundle":{}}`); got.StatusCode != http.StatusBadRequest { - t.Fatalf("browser recipe packet status=%d body=%s", got.StatusCode, got.Body) - } - published := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/publish", `{"receiptId":"`+compiledBody.ReceiptID+`","requestId":"retry-a"}`) - if published.StatusCode != http.StatusOK { - t.Fatalf("publish=%d %s", published.StatusCode, published.Body) - } - retried := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/publish", `{"receiptId":"`+compiledBody.ReceiptID+`","requestId":"retry-a"}`) - if retried.StatusCode != http.StatusOK || materializeCalls != 1 { - t.Fatalf("idempotent publish=%d %s", retried.StatusCode, retried.Body) - } - exported := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v1/bundle/active", "") - if exported.StatusCode != http.StatusOK || exported.Body == "" || !strings.Contains(exported.Body, compiledBody.IntentDigest) { - t.Fatalf("export=%d body=%s", exported.StatusCode, exported.Body) - } -} - -func TestAuthoringV1MaterializationFailureRetainsActiveRevision(t *testing.T) { - t.Skip("receipt-based publish request removed by publish-only Builder cutover") - ctx := context.Background() - store := explorer.NewMemoryStore() - service, err := explorer.NewService(store) - if err != nil { - t.Fatal(err) - } - if _, err := store.CreateInteractive(ctx, explorer.Explorer{Project: "project-a", ExplorerID: "custom", ManagementMode: explorer.ManagementInteractive}); err != nil { - t.Fatal(err) - } - if _, err := store.InsertRevision(ctx, explorer.Revision{ID: "prior", Project: "project-a", ExplorerID: "custom", Status: explorer.RevisionReady}); err != nil { - t.Fatal(err) - } - if err := store.ActivateInteractive(ctx, "project-a", "custom", "prior"); err != nil { - t.Fatal(err) - } - snapshot := authoringTestSnapshot(t) - document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base"} - compiled, err := compileExplorerAuthoringV1(ctx, nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: authoringTestBundle(document), SnapshotToken: snapshot.Token}) - if err != nil { - t.Fatal(err) - } - if _, err := service.StoreCompilationReceipt(ctx, compiled.Receipt); err != nil { - t.Fatal(err) - } - releaseCalls := 0 - app := fiber.New() - RegisterExplorerAuthoringV1Routes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{ - Materialize: func(context.Context, recipe.Bundle, recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { - return graphresolver.RecipeExecution{}, errors.New("materialization unavailable") - }, - ValidateReleaseGeneration: func(context.Context, string, string) error { return nil }, - ActivateRelease: func(context.Context, string, string, []dataset.DataframeSelector) error { releaseCalls++; return nil }, - }) - request := `{"receiptId":"` + compiled.Receipt.ID + `","requestId":"materialize-failure"}` - response := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/publish", request) - if response.StatusCode != http.StatusConflict || !strings.Contains(response.Body, "MATERIALIZATION_FAILED") { - t.Fatalf("publish failure=%d %s", response.StatusCode, response.Body) - } - if releaseCalls != 0 { - t.Fatalf("release activation happened after materialization failure") - } - active, err := service.ActiveRevision(ctx, "project-a", "custom") - if err != nil || active.ID != "prior" { - t.Fatalf("active revision changed after failed materialization: %#v err=%v", active, err) - } -} diff --git a/internal/server/explorer_authoring_v2_migration_test.go b/internal/server/explorer_authoring_v2_migration_test.go deleted file mode 100644 index ed23979a..00000000 --- a/internal/server/explorer_authoring_v2_migration_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package server - -import ( - "testing" - - "github.com/calypr/loom/internal/explorer" - "github.com/calypr/loom/internal/explorer/authoringv2" - "github.com/calypr/loom/internal/explorer/capability" -) - -func TestMigrateV1WorkspaceMapsLegacyCandidateOccurrencePresentation(t *testing.T) { - visible := true - order := 0 - legacyCandidateID := explorer.OpaqueID("s_", "Patient\x00id") - snapshot := capability.Snapshot{ - Identity: capability.SnapshotIdentity{Project: "project-a", Generation: "generation-a", AuthorizationScopeDigest: "scope-a"}, - Policy: capability.Policy{Route: capability.RoutePolicy{AllowsRepeatedEdges: true, AllowsSelfLoops: true}}, - Status: capability.StatusReady, Complete: true, Token: "snapshot-a", - Nodes: []capability.Node{{ID: "patient-node", ResourceType: "Patient", RowRootEligible: true, RowGrain: "patient", Populated: true, DocumentCount: 3}}, - Candidates: []capability.Candidate{{ - ID: "patient-id", NodeID: "patient-node", ResourceType: "Patient", FieldPath: "id", Label: "Identifier", LogicalType: "string", Cardinality: "scalar", - ProjectionModes: []capability.ProjectionMode{capability.ProjectionScalar}, FilterOperators: []capability.FilterOperator{capability.FilterEquals}, ChartAggregations: []capability.ChartAggregation{capability.ChartCount}, Populated: true, - }}, - } - wire := authoringV2Catalog(snapshot, "default") - bundle := explorer.ExplorerAuthoringBundleV1{ - APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, - Project: "project-a", ExplorerID: "default", Title: "Default", - Documents: []explorer.ExplorerBuilderDocumentV1{{ - Kind: explorer.ExplorerBuilderV1Kind, - Output: explorer.ExplorerOutputIdentityV1{ID: "patients", Title: "Patients"}, - BaseNodeID: explorer.OpaqueID("n_", "Patient"), RowNodeID: explorer.OpaqueID("n_", "Patient"), - CandidateIDs: []string{legacyCandidateID}, - CandidateOccurrences: []explorer.ExplorerCandidateOccurrenceV1{{CandidateID: legacyCandidateID, OccurrenceID: "base", ProjectionMode: "SCALAR"}}, - Presentation: map[string]explorer.ExplorerPresentationBindingV1{ - legacyCandidateID + "\x00base": { - Label: "Patient identifier", Visible: &visible, Order: &order, - Table: &explorer.ExplorerTableBindingV1{Pinned: true}, - Filter: &explorer.ExplorerFilterBindingV1{Label: "Patient ID"}, - Chart: &explorer.ExplorerChartBindingV1{Type: "bar", Title: "Patients"}, - }, - }, - }}, - Tabs: []explorer.ExplorerTabV1{{ID: "patients-tab", Title: "Patients", OutputID: "patients", Order: 0, Visible: &visible}}, - } - - workspace, err := migrateV1WorkspaceToCapability(bundle, snapshot, wire, nil) - if err != nil { - t.Fatal(err) - } - if len(workspace.Documents) != 1 || len(workspace.Tabs) != 1 { - t.Fatalf("workspace = %#v", workspace) - } - document := workspace.Documents[0] - if len(document.Selections) != 1 || document.Selections[0].CandidateID != "patient-id" || document.Selections[0].ProjectionMode != "VALUE" { - t.Fatalf("selections = %#v", document.Selections) - } - key := authoringv2.PresentationKey("patient-id", "base", "VALUE") - presentation, ok := document.Presentation[key] - if !ok || presentation.Label != "Patient identifier" || presentation.Table == nil || !presentation.Table.Pinned || presentation.Filter == nil || presentation.Filter.Label != "Patient ID" || presentation.Chart == nil || presentation.Chart.Type != "bar" || presentation.Chart.Title != "Patients" { - t.Fatalf("presentation = %#v", document.Presentation) - } -} diff --git a/internal/server/explorer_authoring_v2_routes.go b/internal/server/explorer_authoring_v2_routes.go index 417cff40..b6e36fc5 100644 --- a/internal/server/explorer_authoring_v2_routes.go +++ b/internal/server/explorer_authoring_v2_routes.go @@ -2,6 +2,7 @@ package server import ( "context" + "encoding/json" "errors" "fmt" "net/http" @@ -22,8 +23,7 @@ import ( ) // RegisterExplorerAuthoringV2Routes is the hard-cut traversal Builder -// contract. V1 remains an internal stored-document migration format and is -// deliberately not registered as an HTTP surface. +// contract. Retired authoring formats are not registered as an HTTP surface. func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, explorers *explorer.Service, capabilities ExplorerV2LifecycleConfig) { if app == nil || authorizer == nil || authorizeRead == nil || explorers == nil { return @@ -52,7 +52,7 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth return c.JSON(explorerv2api.AuthoringCapability{ ApiVersion: explorerv2api.LoomCalyprOrgexplorerAuthoringv2, Kind: explorerv2api.ExplorerAuthoringCapabilities, - Operations: []explorerv2api.AuthoringCapabilityOperations{explorerv2api.Builder, explorerv2api.Compile, explorerv2api.Suggestions, explorerv2api.Preview, explorerv2api.Publish}, + Operations: []explorerv2api.AuthoringCapabilityOperations{explorerv2api.Builder, explorerv2api.Compile, explorerv2api.Draft, explorerv2api.Export, explorerv2api.Suggestions, explorerv2api.Preview, explorerv2api.Publish}, PreviewLimits: []int{10, 25, 50, 100}, Features: explorerv2api.AuthoringFeatures{EmissionFilters: true, EmissionCharts: true}, }) @@ -129,7 +129,7 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth if err := authoringRead(c, authorizeRead); err != nil { return err } - snapshot, wire, err := readCapability(c) + _, wire, err := readCapability(c) if err != nil { return authoringHTTPError(c, err) } @@ -138,24 +138,31 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth if err != nil { return authoringHTTPError(c, err) } - _ = owner - state := authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, Catalog: wire} - if active, activeErr := explorers.ActiveRevision(c.Context(), project, id); activeErr == nil && len(active.AuthoringBundle) != 0 { - if workspace, decodeErr := authoringv2.DecodeWorkspace(active.AuthoringBundle); decodeErr == nil { - state.Workspace = &workspace - } else if document, decodeErr := authoringv2.DecodeDocument(active.AuthoringBundle); decodeErr == nil { - document.APIVersion = "" - workspace := authoringv2.Workspace{APIVersion: authoringv2.APIVersion, Kind: authoringv2.WorkspaceKind, Documents: []authoringv2.Document{document}, Tabs: []authoringv2.Tab{{ID: document.Output.ID, Title: document.Output.Title, OutputID: document.Output.ID, Order: 0, Visible: true}}} - state.Workspace = &workspace - } else if bundle, decodeErr := explorer.DecodeAuthoringBundleV1ForMigration(active.AuthoringBundle); decodeErr == nil { - workspace, migrateErr := migrateV1WorkspaceToCapability(bundle, snapshot, wire, active.EmittedColumns) - if migrateErr != nil { - return authoringHTTPError(c, authoringSemanticRoute("migration", "$", "MIGRATION_FAILED", migrateErr.Error(), nil)) - } - state.Workspace = &workspace + state := authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, LifecycleState: authoringv2.LifecycleNew, Catalog: wire} + var activeWorkspace *authoringv2.Workspace + if owner.ActiveRevisionID != "" { + active, activeErr := explorers.ActiveRevision(c.Context(), project, id) + if activeErr != nil { + return authoringHTTPError(c, explorerConflict("builder", "AUTHORING_STATE_MISSING", "the active Explorer revision cannot be loaded as V2 authoring state", map[string]any{"revisionId": owner.ActiveRevisionID})) + } + workspace, decodeErr := authoringv2.DecodeWorkspace(active.AuthoringBundle) + if decodeErr != nil { + return authoringHTTPError(c, explorerConflict("builder", "AUTHORING_STATE_MISSING", "the active Explorer revision has no valid V2 workspace", map[string]any{"revisionId": active.ID})) + } + activeWorkspace = &workspace + } + if len(owner.DraftConfig) != 0 { + workspace, decodeErr := authoringv2.DecodeWorkspace(owner.DraftConfig) + if decodeErr != nil { + return authoringHTTPError(c, explorerConflict("builder", "DRAFT_STATE_INVALID", "the saved Explorer draft is not a valid V2 workspace", map[string]any{"draftVersion": owner.DraftVersion})) + } + state.Workspace = &workspace + state.LifecycleState = authoringv2.LifecycleReady + } else { + state.Workspace = activeWorkspace + if activeWorkspace != nil { + state.LifecycleState = authoringv2.LifecycleReady } - } else if activeErr != nil && !errors.Is(activeErr, explorer.ErrNotFound) { - return authoringHTTPError(c, activeErr) } if err := state.Validate(); err != nil { return authoringHTTPError(c, explorerUnavailable("capability", "CAPABILITY_UNAVAILABLE", err.Error())) @@ -163,6 +170,74 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth return c.JSON(state) }) + app.Put(prefix+"/draft", func(c fiber.Ctx) error { + if err := authoringWrite(c, authorizer); err != nil { + return err + } + var request struct { + Workspace authoringv2.Workspace `json:"workspace"` + SnapshotToken string `json:"snapshotToken"` + ExpectedDraftVersion *int64 `json:"expectedDraftVersion"` + ExpectedDraftDigest string `json:"expectedDraftDigest,omitempty"` + } + if err := decodeAuthoringStrict(c.Body(), &request); err != nil || request.ExpectedDraftVersion == nil || strings.TrimSpace(request.SnapshotToken) == "" { + if err == nil { + err = fmt.Errorf("workspace, snapshotToken, and expectedDraftVersion are required") + } + return authoringHTTPError(c, malformedRouteError("draft", err)) + } + if capabilities.CapabilityToken == nil { + return authoringHTTPError(c, explorerUnavailable("draft", "CAPABILITY_UNAVAILABLE", "Explorer capability lookup is not configured")) + } + project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) + snapshot, err := capabilities.CapabilityToken(c.Context(), project, request.SnapshotToken) + if err != nil { + return authoringHTTPError(c, explorerConflict("draft", "STALE_CATALOG_SNAPSHOT", "the catalog snapshot is stale or unavailable", nil)) + } + state := authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, LifecycleState: authoringv2.LifecycleReady, Workspace: &request.Workspace, Catalog: authoringV2Catalog(snapshot, id)} + if err := state.Validate(); err != nil { + return authoringHTTPError(c, authoringSemanticRoute("draft", "$", workspaceValidationCode(err), err.Error(), nil)) + } + stored, err := explorers.SaveWorkspaceDraft(c.Context(), project, id, request.Workspace, *request.ExpectedDraftVersion, request.ExpectedDraftDigest, subjectFromFiber(c)) + if errors.Is(err, explorer.ErrDraftConflict) { + return authoringHTTPError(c, explorerConflict("draft", "DRAFT_CONFLICT", "the Explorer draft changed; reload before saving", nil)) + } + if err != nil { + return authoringHTTPError(c, err) + } + return c.JSON(fiber.Map{"workspace": json.RawMessage(stored.DraftConfig), "draftVersion": stored.DraftVersion, "draftDigest": stored.DraftDigest}) + }) + + app.Get(prefix+"/export", func(c fiber.Ctx) error { + if err := authoringRead(c, authorizeRead); err != nil { + return err + } + project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) + owner, err := explorers.Get(c.Context(), project, id) + if err != nil { + return authoringHTTPError(c, err) + } + raw := owner.DraftConfig + if len(raw) == 0 && owner.ActiveRevisionID != "" { + active, activeErr := explorers.ActiveRevision(c.Context(), project, id) + if activeErr != nil { + return authoringHTTPError(c, explorerConflict("export", "AUTHORING_STATE_MISSING", "the active Explorer revision cannot be exported", nil)) + } + raw = active.AuthoringBundle + } + workspace, err := authoringv2.DecodeWorkspace(raw) + if err != nil { + return authoringHTTPError(c, explorerConflict("export", "AUTHORING_STATE_MISSING", "no canonical V2 workspace is available for export", nil)) + } + canonical, err := workspace.CanonicalJSON() + if err != nil { + return authoringHTTPError(c, err) + } + c.Set(fiber.HeaderContentType, fiber.MIMEApplicationJSON) + c.Set(fiber.HeaderContentDisposition, `attachment; filename="`+id+`.explorer-workspace.json"`) + return c.Send(canonical) + }) + compileHandler := func(c fiber.Ctx) error { if err := authoringWrite(c, authorizer); err != nil { return err @@ -171,7 +246,7 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth if err := decodeAuthoringStrict(c.Body(), &request); err != nil { return authoringHTTPError(c, malformedRouteError("intent", err)) } - if (capabilities.CapabilityToken == nil && capabilities.AuthorizedCapabilityCompile == nil) || (capabilities.CompileReceipt == nil && capabilities.AuthoringCompile == nil) { + if (capabilities.CapabilityToken == nil && capabilities.AuthorizedCapabilityCompile == nil) || capabilities.CompileReceipt == nil { return authoringHTTPError(c, explorerUnavailable("compile", "CAPABILITY_UNAVAILABLE", "Explorer V2 compiler is not configured")) } project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) @@ -192,23 +267,7 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth if err := state.Validate(); err != nil { return authoringHTTPError(c, authoringSemanticRoute("intent", "$", workspaceValidationCode(err), err.Error(), nil)) } - var stored *explorer.CompilationReceipt - nativeReceipt := capabilities.CompileReceipt != nil - if nativeReceipt { - stored, err = capabilities.CompileReceipt(c.Context(), ExplorerV2ReceiptCompileRequest{Project: project, ExplorerID: id, Workspace: request.Workspace, SnapshotToken: snapshot.Token, RequestID: requestIDFromFiber(c), Authorized: authorized}) - } else { - // Compatibility path for migration-only callers. Production wiring - // supplies CompileReceipt and never enters this V1 adapter. - bundle, bundleErr := authoringV2WorkspaceBundle(project, id, request.Workspace, wire) - if bundleErr != nil { - return authoringHTTPError(c, authoringSemanticRoute("intent", "$", "INVALID_AUTHORING_INTENT", bundleErr.Error(), nil)) - } - resolved, compileErr := capabilities.AuthoringCompile(c.Context(), ExplorerAuthoringV1CompileRequest{Bundle: bundle, SnapshotToken: snapshot.Token, RequestID: requestIDFromFiber(c)}) - if compileErr == nil { - stored = &resolved.Receipt - } - err = compileErr - } + stored, err := capabilities.CompileReceipt(c.Context(), ExplorerV2ReceiptCompileRequest{Project: project, ExplorerID: id, Workspace: request.Workspace, SnapshotToken: snapshot.Token, RequestID: requestIDFromFiber(c), Authorized: authorized}) if err != nil { var compileErr *explorercompilation.Error if errors.As(err, &compileErr) { @@ -219,15 +278,6 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth if stored == nil || strings.TrimSpace(stored.ID) == "" { return authoringHTTPError(c, explorerUnavailable("compile", "COMPILATION_RECEIPT_STORE_FAILED", "compiled authoring receipt was not persisted")) } - // The native compiler owns durable insert/readback so an idempotent hit is - // one tenant-scoped lookup. The V1 migration adapter still needs the route - // to persist its legacy receipt. - if !nativeReceipt { - stored, err = explorers.StoreCompilationReceipt(c.Context(), *stored) - if err != nil { - return authoringHTTPError(c, explorerUnavailable("compile", "COMPILATION_RECEIPT_STORE_FAILED", "compiled authoring receipt could not be persisted")) - } - } return c.JSON(v2ReceiptResponse(stored, request.Workspace)) } app.Post(prefix+"/builder", compileHandler) @@ -412,7 +462,7 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth } now := time.Now().UTC() revisionID := "authoring_" + strings.TrimPrefix(receipt.ID, "receipt_") - revision, err := explorers.PublishAuthoring(c.Context(), *receipt, explorer.Revision{ID: revisionID, Project: receipt.Project, ExplorerID: receipt.ExplorerID, Config: receipt.CompiledConfig, ConfigDigest: receipt.IntentDigest, AuthoringBundle: receipt.NormalizedBundle, IntentDigest: receipt.IntentDigest, CompilationReceiptID: receipt.ID, Recipe: receipt.Bundle, RecipeDigest: receipt.RecipeDigest, ResolvedSchemaDigest: receipt.ResolvedSchemaDigest, SourceGeneration: receipt.SourceGeneration, Materializations: explorerMaterializations(receipt.Bundle, execution), EmittedColumns: receipt.EmittedColumns, Dataset: datasetMetadataFromExecution(receipt.Bundle, receipt.SourceGeneration, receipt.ResolvedSchemaDigest, execution), Publication: explorer.PublicationMetadata{State: string(explorer.RevisionReady), Generation: receipt.SourceGeneration, ExecutionID: execution.ID, UpdatedAt: now}, Status: explorer.RevisionReady, CreatedBy: subjectFromFiber(c), CreatedAt: now, ReadyAt: &now}) + revision, err := explorers.PublishAuthoring(c.Context(), *receipt, explorer.Revision{ID: revisionID, Project: receipt.Project, ExplorerID: receipt.ExplorerID, Config: receipt.CompiledConfig, ConfigDigest: receipt.IntentDigest, AuthoringBundle: receipt.NormalizedBundle, IntentDigest: receipt.IntentDigest, CompilationReceiptID: receipt.ID, PublicOutputContract: receipt.PublicOutputContract, Recipe: receipt.Bundle, RecipeDigest: receipt.RecipeDigest, ResolvedSchemaDigest: receipt.ResolvedSchemaDigest, SourceGeneration: receipt.SourceGeneration, Materializations: explorerMaterializations(receipt.Bundle, execution), EmittedColumns: receipt.EmittedColumns, Dataset: datasetMetadataFromExecution(receipt.Bundle, receipt.SourceGeneration, receipt.ResolvedSchemaDigest, execution), Publication: explorer.PublicationMetadata{State: string(explorer.RevisionReady), Generation: receipt.SourceGeneration, ExecutionID: execution.ID, UpdatedAt: now}, Status: explorer.RevisionReady, CreatedBy: subjectFromFiber(c), CreatedAt: now, ReadyAt: &now}) if err != nil { return authoringHTTPError(c, err) } @@ -524,93 +574,6 @@ func applyAuthorizedScope(bindings *recipe.RuntimeBindings, authorized Authorize bindings.IncludeAuthResourcePath = includeAuthResourcePath } -func authoringV2Bundle(project, explorerID string, document authoringv2.Document, catalog authoringv2.CatalogSnapshot) (explorer.ExplorerAuthoringBundleV1, error) { - occurrences, err := document.Occurrences(catalog) - if err != nil { - return explorer.ExplorerAuthoringBundleV1{}, err - } - v1 := explorer.ExplorerBuilderDocumentV1{ - Kind: explorer.ExplorerBuilderV1Kind, - Output: explorer.ExplorerOutputIdentityV1{ID: document.Output.ID, Title: document.Output.Title}, - BaseNodeID: document.RootNodeID, RowNodeID: occurrences[len(occurrences)-1].NodeID, - Presentation: map[string]explorer.ExplorerPresentationBindingV1{}, - } - for _, step := range document.RouteSteps { - v1.RouteEdgeIDs = append(v1.RouteEdgeIDs, step.EdgeID) - } - for i, occurrence := range occurrences { - v1.RouteOccurrences = append(v1.RouteOccurrences, explorer.ExplorerRouteOccurrenceV1{ID: occurrence.ID, Index: i, NodeID: occurrence.NodeID, IncomingEdgeID: occurrence.IncomingEdgeID}) - } - seenCandidates := map[string]bool{} - for _, selection := range document.Selections { - if !seenCandidates[selection.CandidateID] { - v1.CandidateIDs = append(v1.CandidateIDs, selection.CandidateID) - seenCandidates[selection.CandidateID] = true - } - occurrenceID := selection.OccurrenceID - if occurrenceID == "" { - occurrenceID = occurrences[len(occurrences)-1].ID - } - v1.CandidateOccurrences = append(v1.CandidateOccurrences, explorer.ExplorerCandidateOccurrenceV1{CandidateID: selection.CandidateID, OccurrenceID: occurrenceID, ProjectionMode: selection.ProjectionMode}) - } - for key, presentation := range document.Presentation { - v1.Presentation[key] = explorer.ExplorerPresentationBindingV1{Label: presentation.Label, Visible: presentation.Visible, Order: presentation.Order} - } - return explorer.ExplorerAuthoringBundleV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, Project: projectid.Canonical(project), ExplorerID: explorerID, Title: document.Output.Title, Documents: []explorer.ExplorerBuilderDocumentV1{v1}, Tabs: []explorer.ExplorerTabV1{}}, nil -} - -func authoringV2WorkspaceBundle(project, explorerID string, workspace authoringv2.Workspace, catalog authoringv2.CatalogSnapshot) (explorer.ExplorerAuthoringBundleV1, error) { - result := explorer.ExplorerAuthoringBundleV1{APIVersion: explorer.ExplorerAuthoringV1APIVersion, Kind: explorer.ExplorerAuthoringV1Kind, Project: projectid.Canonical(project), ExplorerID: explorerID, Documents: []explorer.ExplorerBuilderDocumentV1{}, Tabs: []explorer.ExplorerTabV1{}} - for _, document := range workspace.Documents { - one, err := authoringV2Bundle(project, explorerID, document, catalog) - if err != nil { - return result, err - } - result.Documents = append(result.Documents, one.Documents...) - } - for _, tab := range workspace.Tabs { - visible := tab.Visible - result.Tabs = append(result.Tabs, explorer.ExplorerTabV1{ID: tab.ID, Title: tab.Title, OutputID: tab.OutputID, Order: tab.Order, Visible: &visible}) - } - return result, nil -} - -func migrateV1WorkspaceToCapability(bundle explorer.ExplorerAuthoringBundleV1, snapshot capability.Snapshot, wire authoringv2.CatalogSnapshot, emitted []explorer.EmittedColumn) (authoringv2.Workspace, error) { - workspace := authoringv2.Workspace{APIVersion: authoringv2.APIVersion, Kind: authoringv2.WorkspaceKind, Documents: []authoringv2.Document{}, Tabs: []authoringv2.Tab{}} - for i, input := range bundle.AuthoringDocuments() { - if len(input.Presentation) > 0 { - mapped := make(map[string]explorer.ExplorerPresentationBindingV1, len(input.Presentation)) - for key, binding := range input.Presentation { - mappedKey := key - for _, emission := range emitted { - if emission.OutputID == input.Output.ID && emission.EmissionID == key { - mappedKey = emission.CandidateID + "\x00" + emission.OccurrenceID - break - } - } - mapped[mappedKey] = binding - } - input.Presentation = mapped - } - document, err := migrateV1DocumentToCapability(input, snapshot, wire) - if err != nil { - return workspace, fmt.Errorf("documents[%d]: %w", i, err) - } - workspace.Documents = append(workspace.Documents, document) - } - for _, input := range bundle.AuthoringTabs() { - visible := true - if input.Visible != nil { - visible = *input.Visible - } - workspace.Tabs = append(workspace.Tabs, authoringv2.Tab{ID: input.ID, Title: input.Title, OutputID: input.OutputID, Order: input.Order, Visible: visible}) - } - if err := (authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, Workspace: &workspace, Catalog: wire}).Validate(); err != nil { - return workspace, err - } - return workspace, nil -} - func v2ReceiptResponse(receipt *explorer.CompilationReceipt, workspace authoringv2.Workspace) explorerv2api.CompileResponse { outputs := make([]explorerv2api.ReceiptOutput, 0, len(workspace.Documents)) for _, document := range workspace.Documents { @@ -621,18 +584,18 @@ func v2ReceiptResponse(receipt *explorer.CompilationReceipt, workspace authoring break } } - emissions := []explorerv2api.Emission{} + columns := []explorerv2api.ContractColumn{} for _, column := range receipt.EmittedColumns { if column.OutputID != document.Output.ID { continue } - mode, label := column.ProjectionMode, column.Label + label := column.Label if label == "" { label = column.PublicColumn } - emissions = append(emissions, explorerv2api.Emission{OutputId: column.OutputID, CandidateId: column.CandidateID, OccurrenceId: column.OccurrenceID, ProjectionMode: mode, EmissionId: column.EmissionID, PublicColumn: column.PublicColumn, Label: label, LogicalType: column.LogicalType, Filterable: column.Filterable, Chartable: column.Chartable}) + columns = append(columns, explorerv2api.ContractColumn{Column: column.PublicColumn, Label: label, LogicalType: column.LogicalType, Filterable: column.Filterable, Chartable: column.Chartable}) } - outputs = append(outputs, explorerv2api.ReceiptOutput{OutputId: document.Output.ID, Title: document.Output.Title, RowGrain: rowGrain, Emissions: emissions}) + outputs = append(outputs, explorerv2api.ReceiptOutput{OutputId: document.Output.ID, Title: document.Output.Title, RowGrain: rowGrain, Columns: columns}) } return explorerv2api.CompileResponse{ ApiVersion: explorerv2api.LoomCalyprOrgexplorerAuthoringv2, @@ -643,150 +606,3 @@ func v2ReceiptResponse(receipt *explorer.CompilationReceipt, workspace authoring Outputs: outputs, Diagnostics: []explorerv2api.Diagnostic{}, } } - -func migrateV1DocumentToCapability(input explorer.ExplorerBuilderDocumentV1, snapshot capability.Snapshot, wire authoringv2.CatalogSnapshot) (authoringv2.Document, error) { - nodeIDs := map[string]string{} - for _, node := range snapshot.Nodes { - nodeIDs[node.ID] = node.ID - nodeIDs[explorer.OpaqueID("n_", node.ResourceType)] = node.ID - } - edgeIDs := map[string]string{} - for _, edge := range snapshot.Edges { - edgeIDs[edge.ID] = edge.ID - edgeIDs[explorer.OpaqueID("e_", edge.SourceResourceType+"\x00"+edge.Label+"\x00"+edge.TargetResourceType)] = edge.ID - } - candidateIDs := map[string]string{} - for _, candidate := range snapshot.Candidates { - candidateIDs[candidate.ID] = candidate.ID - candidateIDs[explorer.OpaqueID("s_", candidate.ResourceType+"\x00"+candidate.FieldPath)] = candidate.ID - } - root := nodeIDs[input.BaseNodeID] - if root == "" { - return authoringv2.Document{}, fmt.Errorf("stored root node is not present in the current capability snapshot") - } - title := input.Output.Title - if strings.TrimSpace(title) == "" { - title = input.Output.ID - } - document := authoringv2.Document{APIVersion: authoringv2.APIVersion, Kind: authoringv2.Kind, Output: authoringv2.Output{ID: input.Output.ID, Title: title}, RootNodeID: root, RouteSteps: []authoringv2.RouteStep{}, Selections: []authoringv2.Selection{}, Presentation: map[string]authoringv2.Presentation{}} - document.APIVersion = "" - for i, oldEdgeID := range input.RouteEdgeIDs { - edgeID := edgeIDs[oldEdgeID] - if edgeID == "" { - return authoringv2.Document{}, fmt.Errorf("stored route edge is not present in the current capability snapshot") - } - occurrenceID := "" - occurrenceIndex := i - if len(input.RouteOccurrences) == len(input.RouteEdgeIDs)+1 { - occurrenceIndex++ - } - if occurrenceIndex < len(input.RouteOccurrences) { - occurrenceID = input.RouteOccurrences[occurrenceIndex].ID - } - document.RouteSteps = append(document.RouteSteps, authoringv2.RouteStep{EdgeID: edgeID, OccurrenceID: occurrenceID}) - } - candidates := map[string]authoringv2.CatalogCandidate{} - for _, candidate := range wire.Candidates { - candidates[candidate.ID] = candidate - } - references := append([]explorer.ExplorerCandidateOccurrenceV1(nil), input.CandidateOccurrences...) - if len(references) == 0 { - occurrences, err := document.Occurrences(wire) - if err != nil { - return authoringv2.Document{}, err - } - for _, oldCandidateID := range input.CandidateIDs { - candidateID := candidateIDs[oldCandidateID] - if candidateID == "" { - return authoringv2.Document{}, fmt.Errorf("stored candidate %q is not present in the current capability snapshot", oldCandidateID) - } - matches := []string{} - for _, occurrence := range occurrences { - if occurrence.NodeID == candidates[candidateID].NodeID { - matches = append(matches, occurrence.ID) - } - } - if len(matches) != 1 { - return authoringv2.Document{}, fmt.Errorf("stored candidate %q cannot be mapped to exactly one route occurrence", oldCandidateID) - } - references = append(references, explorer.ExplorerCandidateOccurrenceV1{CandidateID: oldCandidateID, OccurrenceID: matches[0]}) - } - } - for _, reference := range references { - candidateID := candidateIDs[reference.CandidateID] - if candidateID == "" { - return authoringv2.Document{}, fmt.Errorf("stored candidate %q is not present in the current capability snapshot", reference.CandidateID) - } - mode := reference.ProjectionMode - if mode == "" || !containsString(candidates[candidateID].ProjectionModes, mode) { - mode = candidates[candidateID].DefaultProjectionMode - } - document.Selections = append(document.Selections, authoringv2.Selection{CandidateID: candidateID, OccurrenceID: reference.OccurrenceID, ProjectionMode: mode}) - } - for oldKey, binding := range input.Presentation { - matchedKey := "" - for _, selection := range document.Selections { - occurrence := selection.OccurrenceID - if occurrence == "" { - occurrence = authoringv2.RootOccurrenceID - if len(document.RouteSteps) > 0 { - occurrence = authoringv2.DerivedOccurrenceID(len(document.RouteSteps) - 1) - } - } - newKey := authoringv2.PresentationKey(selection.CandidateID, occurrence, selection.ProjectionMode) - if !legacyPresentationKeyMatches(oldKey, input.Output.ID, selection.CandidateID, occurrence, newKey, references, candidateIDs) { - continue - } - if matchedKey != "" && matchedKey != newKey { - return authoringv2.Document{}, fmt.Errorf("stored presentation %q maps to more than one selection", oldKey) - } - matchedKey = newKey - } - if matchedKey == "" { - return authoringv2.Document{}, fmt.Errorf("stored presentation %q cannot be mapped exactly", oldKey) - } - if _, exists := document.Presentation[matchedKey]; exists { - return authoringv2.Document{}, fmt.Errorf("multiple stored presentations map to selection %q", matchedKey) - } - presentation := authoringv2.Presentation{Label: binding.Label, Visible: binding.Visible, Order: binding.Order} - if binding.Table != nil { - presentation.Table = &authoringv2.TablePresentation{Pinned: binding.Table.Pinned} - } - if binding.Filter != nil { - presentation.Filter = &authoringv2.FilterPresentation{Label: binding.Filter.Label} - } - if binding.Chart != nil { - presentation.Chart = &authoringv2.ChartPresentation{Type: binding.Chart.Type, Title: binding.Chart.Title} - } - document.Presentation[matchedKey] = presentation - } - if err := (authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, Document: &document, Catalog: wire}).Validate(); err != nil { - return authoringv2.Document{}, err - } - return document, nil -} - -func legacyPresentationKeyMatches(oldKey, outputID, currentCandidateID, occurrenceID, newKey string, references []explorer.ExplorerCandidateOccurrenceV1, ids map[string]string) bool { - aliases := map[string]bool{ - currentCandidateID: true, - currentCandidateID + "\x00" + occurrenceID: true, - explorer.OpaqueID("em_", outputID+"\x00"+occurrenceID+"\x00"+currentCandidateID): true, - newKey: true, - } - for _, reference := range references { - if ids[reference.CandidateID] != currentCandidateID { - continue - } - referenceOccurrence := reference.OccurrenceID - if referenceOccurrence == "" { - referenceOccurrence = occurrenceID - } - if referenceOccurrence != occurrenceID { - continue - } - aliases[reference.CandidateID] = true - aliases[reference.CandidateID+"\x00"+occurrenceID] = true - aliases[explorer.OpaqueID("em_", outputID+"\x00"+occurrenceID+"\x00"+reference.CandidateID)] = true - } - return aliases[oldKey] || ids[oldKey] == currentCandidateID -} diff --git a/internal/server/explorer_builder_lifecycle.go b/internal/server/explorer_builder_lifecycle.go index 64f4f7c2..34ceff00 100644 --- a/internal/server/explorer_builder_lifecycle.go +++ b/internal/server/explorer_builder_lifecycle.go @@ -1,15 +1,12 @@ package server import ( - "context" "errors" - "fmt" "net/http" "strings" "github.com/calypr/loom/internal/authscope" "github.com/calypr/loom/internal/explorer" - "github.com/calypr/loom/internal/projectid" "github.com/gofiber/fiber/v3" ) @@ -40,7 +37,7 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author if err := authorizeRead(c.Context(), principalFromFiber(c), project); err != nil { return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") } - state, err := loadExplorerRuntimeState(c.Context(), explorers, project, id) + state, err := explorers.LoadExplorerState(c.Context(), project, id) if errors.Is(err, explorer.ErrNotFound) { return explorerV2Error(c, 404, "EXPLORER_NOT_FOUND", "Explorer not found") } @@ -80,88 +77,3 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author return c.Status(http.StatusCreated).JSON(explorer.ExplorerSummaryV1{Project: project, ExplorerID: value.ExplorerID, Title: value.Title, Management: value.ManagementMode, UpdatedAt: value.UpdatedAt}) }) } - -// loadExplorerRuntimeState reads the Explorer identity and its immutable active -// revision directly. The selected runtime endpoint must not pass through the -// retired ExplorerConfigV2 reconciliation state: the revision is the sole -// source of published configuration, materializations, and diagnostics. -func loadExplorerRuntimeState(ctx context.Context, service *explorer.Service, project, id string) (explorer.ExplorerStateV1, error) { - project = projectid.Canonical(project) - id = strings.TrimSpace(id) - owner, err := service.Get(ctx, project, id) - if errors.Is(err, explorer.ErrNotFound) && id == "default" { - // Repository bootstrap can briefly expose its repository record before - // the Explorer identity is created. Preserve the read contract for that - // window without manufacturing editable authoring state. - repository, repositoryErr := service.RepositoryConfig(ctx, project) - if repositoryErr != nil { - return explorer.ExplorerStateV1{}, err - } - owner = &explorer.Explorer{ - Project: projectid.Legacy(project), - ExplorerID: "default", - Title: configV2Title(repository.Config), - ManagementMode: explorer.ManagementRepository, - ActiveRevisionID: repository.ActiveRevisionID, - Publication: repository.Publication, - UpdatedAt: repository.UpdatedAt, - } - err = nil - } - if err != nil { - return explorer.ExplorerStateV1{}, err - } - if owner == nil { - return explorer.ExplorerStateV1{}, fmt.Errorf("Explorer %s/%s resolved to an empty identity", project, id) - } - - state := explorerStateV1FromIdentity(owner) - if owner.ActiveRevisionID == "" { - return state, nil - } - revision, err := service.Revision(ctx, owner.ActiveRevisionID) - if err != nil { - return explorer.ExplorerStateV1{}, fmt.Errorf("load active Explorer revision %q: %w", owner.ActiveRevisionID, err) - } - state.Active.RevisionID = revision.ID - state.Active.IntentDigest = revision.IntentDigest - state.Active.Status = string(revision.Status) - state.Generated.RecipeDigest = revision.RecipeDigest - state.Generated.ResolvedSchemaDigest = revision.ResolvedSchemaDigest - state.Generated.SourceGeneration = revision.SourceGeneration - state.Generated.EmittedColumns = append([]explorer.EmittedColumn(nil), revision.EmittedColumns...) - state.Generated.Materializations, state.Generated.Dataset = explorer.WithDataframeSelectors(revision.Recipe, revision.Materializations, revision.Dataset) - state.Generated.Publication = revision.Publication - state.Generated.Publication.State = string(revision.Status) - state.Generated.Publication.RevisionID = revision.ID - state.Generated.Diagnostics = append([]explorer.Diagnostic(nil), revision.Diagnostics...) - state.Runtime = runtimeV1FromPublishedRevision(revision) - return state, nil -} - -func explorerStateV1FromIdentity(owner *explorer.Explorer) explorer.ExplorerStateV1 { - project := projectid.Canonical(owner.Project) - return explorer.ExplorerStateV1{ - APIVersion: explorer.ExplorerStateV1APIVersion, - Kind: explorer.ExplorerStateV1Kind, - Project: project, - ExplorerID: owner.ExplorerID, - Title: owner.Title, - Management: owner.ManagementMode, - Draft: explorer.ExplorerStateV1Draft{}, - Active: explorer.ExplorerStateV1Active{}, - Generated: explorer.ExplorerStateV1Generated{ - RecipeDigest: owner.RecipeDigest, - ResolvedSchemaDigest: owner.ResolvedSchemaDigest, - SourceGeneration: owner.SourceGeneration, - EmittedColumns: append([]explorer.EmittedColumn(nil), owner.EmittedColumns...), - Materializations: append([]explorer.Materialization(nil), owner.Materializations...), - Dataset: owner.Dataset, - Publication: owner.Publication, - Diagnostics: append([]explorer.Diagnostic(nil), owner.Diagnostics...), - }, - ActiveURL: explorerURL(project, owner.ExplorerID), - UpdatedBy: owner.UpdatedBy, - UpdatedAt: owner.UpdatedAt, - } -} diff --git a/internal/server/explorer_builder_routes_test.go b/internal/server/explorer_builder_routes_test.go deleted file mode 100644 index 89cfe0b0..00000000 --- a/internal/server/explorer_builder_routes_test.go +++ /dev/null @@ -1,429 +0,0 @@ -package server - -import ( - "context" - "encoding/json" - "errors" - "net/http" - "strings" - "testing" - - graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" - "github.com/calypr/loom/internal/authscope" - "github.com/calypr/loom/internal/dataframe/publication" - "github.com/calypr/loom/internal/dataframe/recipe" - "github.com/calypr/loom/internal/dataset" - "github.com/calypr/loom/internal/explorer" - "github.com/gofiber/fiber/v3" -) - -func publishOnlyAuthoringApp(t *testing.T, store *explorer.MemoryStore, snapshot explorer.CatalogSnapshot, preview ExplorerV2Previewer, materialize ExplorerV2Materializer) (*fiber.App, *explorer.Service) { - t.Helper() - service, err := explorer.NewService(store) - if err != nil { - t.Fatal(err) - } - compiler := func(ctx context.Context, request ExplorerAuthoringV1CompileRequest) (ExplorerAuthoringV1CompileResult, error) { - return ResolveAuthoringBundle(ctx, nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, request) - } - app := fiber.New() - RegisterExplorerAuthoringV1Routes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{ - AuthoringCompile: compiler, - Catalog: func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, - Preview: preview, Materialize: materialize, - ValidateReleaseGeneration: func(context.Context, string, string) error { return nil }, - ActivateRelease: func(context.Context, string, string, []dataset.DataframeSelector) error { return nil }, - }) - return app, service -} - -func TestBuilderReadReturnsCombinedEmptyModel(t *testing.T) { - store := explorer.NewMemoryStore() - if _, err := store.CreateInteractive(context.Background(), explorer.Explorer{Project: "project-a", ExplorerID: "custom", Title: "Custom", ManagementMode: explorer.ManagementInteractive}); err != nil { - t.Fatal(err) - } - app, _ := publishOnlyAuthoringApp(t, store, authoringTestSnapshot(t), nil, nil) - response := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v1/builder", "") - if response.StatusCode != http.StatusOK { - t.Fatalf("builder=%d %s", response.StatusCode, response.Body) - } - var state explorer.ExplorerBuilderStateV1 - decodeBody(t, response.Body, &state) - if state.Kind != explorer.ExplorerBuilderStateV1Kind || state.Bundle.ExplorerID != "custom" || len(state.Bundle.AuthoringDocuments()) != 0 || len(state.Catalog.Nodes) == 0 || state.Catalog.SnapshotToken == "" || len(state.Bindings) != 0 { - t.Fatalf("unexpected empty Builder state: %#v", state) - } - for _, removed := range []string{"draftVersion", "draftDigest", "receiptId"} { - if strings.Contains(response.Body, removed) { - t.Fatalf("Builder response leaked removed field %q: %s", removed, response.Body) - } - } - for _, route := range []struct{ method, path string }{ - {http.MethodPut, "/api/v1/projects/project-a/explorers/custom/authoring/v1/draft"}, - {http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v1/bundle/draft"}, - {http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v1/catalog"}, - {http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/compile"}, - } { - response := requestJSON(t, app, route.method, route.path, `{}`) - if response.StatusCode != http.StatusNotFound { - t.Fatalf("removed authoring route %s %s returned %d", route.method, route.path, response.StatusCode) - } - } -} - -func TestBuilderReadRejectsUnmigratedLegacyAuthoring(t *testing.T) { - ctx := context.Background() - store := explorer.NewMemoryStore() - owner, err := store.CreateInteractive(ctx, explorer.Explorer{Project: "project-a", ExplorerID: "default", Title: "Biospecimens", ManagementMode: explorer.ManagementInteractive}) - if err != nil { - t.Fatal(err) - } - canonicalNodeID := explorer.OpaqueID("n_", "Specimen") - legacyNodeID := explorer.OpaqueID("n_", "specimen") - candidateID := explorer.OpaqueID("s_", "Specimen\x00id") - catalog := explorer.Catalog{ - Nodes: []explorer.CatalogNode{{ID: canonicalNodeID, ResourceType: "Specimen"}}, - Selections: map[string]explorer.CatalogSelection{ - candidateID: {ID: candidateID, NodeID: canonicalNodeID, FieldRef: "Specimen.id", Select: "id", LogicalType: "scalar", Filterable: true}, - }, - } - snapshot, err := explorer.NewCatalogSnapshot("project-a", "generation-a", "scope-a", catalog, true, false, nil) - if err != nil { - t.Fatal(err) - } - broken := authoringTestBundle(explorer.ExplorerBuilderDocumentV1{ - Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "specimen", Title: "Biospecimens"}, - BaseNodeID: legacyNodeID, RowNodeID: legacyNodeID, - Presentation: map[string]explorer.ExplorerPresentationBindingV1{ - explorer.OpaqueID("em_", "specimen\x00base\x00legacy-candidate"): {Label: "stale"}, - }, - }) - broken.Project, broken.ExplorerID, broken.Title = "project-a", "default", "Biospecimens" - brokenJSON, err := broken.CanonicalJSON() - if err != nil { - t.Fatal(err) - } - legacyConfig := json.RawMessage(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Biospecimens","management":"repository"},"recipe":{"recipeSchemaVersion":1,"name":"legacy","translationVersion":"v1","outputs":[{"name":"specimen","rootResourceType":"Specimen","rowGrain":"specimen","fields":[{"name":"id","fieldRef":"Specimen.id","expr":{"select":"root.id"}}]}]},"views":[{"id":"specimen","title":"Biospecimens","output":"specimen","table":{"columns":[{"column":"id","label":"Identifier","visible":true}]}}]}`) - revision := explorer.Revision{ - ID: "legacy-specimen", Project: owner.Project, ExplorerID: owner.ExplorerID, - AuthoringBundle: brokenJSON, SourceGeneration: snapshot.Generation, Status: explorer.RevisionReady, - Migration: &explorer.MigrationMetadata{Kind: "ExplorerAuthoringMigration", Source: "frontend-mapping", OriginalConfig: legacyConfig}, - } - if _, err := store.InsertRevision(ctx, revision); err != nil { - t.Fatal(err) - } - if err := store.ActivateInteractive(ctx, owner.Project, owner.ExplorerID, revision.ID); err != nil { - t.Fatal(err) - } - - app, _ := publishOnlyAuthoringApp(t, store, snapshot, nil, nil) - response := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/default/authoring/v1/builder", "") - if response.StatusCode != http.StatusUnprocessableEntity || !strings.Contains(response.Body, "STALE_BASE_NODE") { - t.Fatalf("unmigrated authoring was accepted: status=%d body=%s", response.StatusCode, response.Body) - } -} - -func TestBuilderReadReturnsCanonicalCandidateOccurrences(t *testing.T) { - ctx := context.Background() - store := explorer.NewMemoryStore() - owner, err := store.CreateInteractive(ctx, explorer.Explorer{Project: "project-a", ExplorerID: "custom", Title: "Custom", ManagementMode: explorer.ManagementInteractive}) - if err != nil { - t.Fatal(err) - } - snapshot := authoringTestSnapshot(t) - legacy := authoringTestBundleWithoutCandidateOccurrences(explorer.ExplorerBuilderDocumentV1{ - Kind: explorer.ExplorerBuilderV1Kind, - Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, - BaseNodeID: "n_base", - RowNodeID: "n_base", - CandidateIDs: []string{ - "s_base", - }, - }) - legacy.IntentDigest = "sha256:legacy-before-candidate-occurrences" - raw, err := json.Marshal(legacy) - if err != nil { - t.Fatal(err) - } - if _, err := store.InsertRevision(ctx, explorer.Revision{ID: "legacy", Project: owner.Project, ExplorerID: owner.ExplorerID, AuthoringBundle: raw, SourceGeneration: snapshot.Generation, Status: explorer.RevisionReady}); err != nil { - t.Fatal(err) - } - if err := store.ActivateInteractive(ctx, owner.Project, owner.ExplorerID, "legacy"); err != nil { - t.Fatal(err) - } - app, _ := publishOnlyAuthoringApp(t, store, snapshot, nil, nil) - response := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v1/builder", "") - if response.StatusCode != http.StatusOK { - t.Fatalf("builder=%d %s", response.StatusCode, response.Body) - } - var state explorer.ExplorerBuilderStateV1 - decodeBody(t, response.Body, &state) - documents := state.Bundle.AuthoringDocuments() - if len(documents) != 1 || len(documents[0].CandidateOccurrences) != 1 || documents[0].CandidateOccurrences[0].CandidateID != "s_base" || documents[0].CandidateOccurrences[0].OccurrenceID != "base" { - t.Fatalf("Builder did not return canonical candidate occurrences: %#v", state.Bundle) - } -} - -func TestExplorerCollectionIsSummaryOnlyAndLegacyMutationsAreAbsent(t *testing.T) { - store := explorer.NewMemoryStore() - if _, err := store.CreateInteractive(context.Background(), explorer.Explorer{Project: "project-a", ExplorerID: "custom", Title: "Custom", ManagementMode: explorer.ManagementInteractive, DraftConfig: json.RawMessage(`{"legacy":true}`), DraftVersion: 7, DraftDigest: "draft"}); err != nil { - t.Fatal(err) - } - service, err := explorer.NewService(store) - if err != nil { - t.Fatal(err) - } - app := fiber.New() - RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{}) - list := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers", "") - if list.StatusCode != http.StatusOK || strings.Contains(list.Body, "draft") || strings.Contains(list.Body, "bundle") || strings.Contains(list.Body, "runtime") { - t.Fatalf("collection is not summary-only: %d %s", list.StatusCode, list.Body) - } - for _, route := range []struct{ method, path string }{ - {http.MethodPut, "/api/v1/projects/project-a/explorers/custom/draft"}, - {http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/compile"}, - {http.MethodPost, "/api/v1/projects/project-a/explorers/custom/preview"}, - {http.MethodPost, "/api/v1/projects/project-a/explorers/custom/publish"}, - {http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/catalog"}, - } { - response := requestJSON(t, app, route.method, route.path, `{}`) - if response.StatusCode != http.StatusNotFound { - t.Fatalf("legacy route %s %s remains registered: %d %s", route.method, route.path, response.StatusCode, response.Body) - } - } -} - -func TestSelectedRuntimeReadProjectsActiveRevisionDirectly(t *testing.T) { - ctx := context.Background() - store := explorer.NewMemoryStore() - owner, err := store.CreateInteractive(ctx, explorer.Explorer{Project: "project-a", ExplorerID: "custom", Title: "Custom", ManagementMode: explorer.ManagementInteractive}) - if err != nil { - t.Fatal(err) - } - selector := dataset.DataframeSelector{Recipe: "recipe", TranslationVersion: "authoring-v1", Output: "patient"} - bundle := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "recipe", TranslationVersion: "authoring-v1", Outputs: []recipe.Output{{Name: "patient", RootResourceType: "Patient", RowGrain: "resource", Fields: []recipe.Field{{Name: "c_id", FieldRef: "Patient.id", Expr: recipe.Expression{Select: "root.id"}}}}}} - config, err := json.Marshal(explorer.ConfigV2{ - APIVersion: explorer.ConfigV2APIVersion, - Kind: "ExplorerConfig", - Project: "project-a", - Explorer: explorer.ConfigExplorer{ID: "custom", Title: "Custom", Management: "interactive"}, - Recipe: mustJSON(bundle), - Views: []explorer.ConfigView{{ - ID: "patient", Title: "Patients", Output: "patient", - Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "c_id", Visible: true}}}, - }}, - }) - if err != nil { - t.Fatal(err) - } - revision := explorer.Revision{ - ID: "revision-1", Project: owner.Project, ExplorerID: owner.ExplorerID, Config: config, - Recipe: bundle, RecipeDigest: "recipe-digest", ResolvedSchemaDigest: "schema-digest", SourceGeneration: "generation-a", - Materializations: []explorer.Materialization{{OutputID: "patient", Output: "patient", MaterializationID: "execution-a", Selector: &selector, Columns: []publication.PhysicalColumn{{Name: "patient_c_id", LogicalType: "String"}}}}, - EmittedColumns: []explorer.EmittedColumn{{EmissionID: "em_id", OutputID: "patient", PublicColumn: "c_id", LogicalType: "string"}}, - Dataset: explorer.DatasetMetadata{Generation: "generation-a", Outputs: []explorer.DatasetOutput{{Name: "patient", State: "PUBLISHED", Queryable: true, Selector: &selector, Columns: []publication.PhysicalColumn{{Name: "patient_c_id", LogicalType: "String"}}}}}, - Publication: explorer.PublicationMetadata{State: string(explorer.RevisionReady), Generation: "generation-a"}, Status: explorer.RevisionReady, - } - if _, err := store.InsertRevision(ctx, revision); err != nil { - t.Fatal(err) - } - if err := store.ActivateInteractive(ctx, owner.Project, owner.ExplorerID, revision.ID); err != nil { - t.Fatal(err) - } - - service, err := explorer.NewService(store) - if err != nil { - t.Fatal(err) - } - app := fiber.New() - RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{}) - response := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom", "") - if response.StatusCode != http.StatusOK { - t.Fatalf("runtime read status=%d body=%s", response.StatusCode, response.Body) - } - var state explorer.ExplorerStateV1 - decodeBody(t, response.Body, &state) - if state.Active.RevisionID != revision.ID || state.Runtime == nil || len(state.Runtime.Outputs) != 1 || state.Runtime.Outputs[0].OutputID != "patient" { - t.Fatalf("runtime state=%#v body=%s", state, response.Body) - } - if strings.Contains(response.Body, "draftConfig") || strings.Contains(response.Body, "activeConfig") { - t.Fatalf("runtime response leaked legacy state: %s", response.Body) - } -} - -func TestPreviewUsesIntentAndSnapshotWithoutWrites(t *testing.T) { - ctx := context.Background() - store := explorer.NewMemoryStore() - if _, err := store.CreateInteractive(ctx, explorer.Explorer{Project: "project-a", ExplorerID: "custom", ManagementMode: explorer.ManagementInteractive}); err != nil { - t.Fatal(err) - } - snapshot := authoringTestSnapshot(t) - previewCalls := 0 - app, service := publishOnlyAuthoringApp(t, store, snapshot, func(_ context.Context, _ recipe.Bundle, _ recipe.RuntimeBindings) (map[string][]map[string]any, error) { - previewCalls++ - return map[string][]map[string]any{"patient": {{"id": "p1"}}}, nil - }, nil) - document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"s_base"}} - bundle := authoringTestBundle(document) - resolved, err := ResolveAuthoringBundle(ctx, nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return snapshot, nil }, ExplorerAuthoringV1CompileRequest{Bundle: bundle, SnapshotToken: snapshot.Token}) - if err != nil { - t.Fatal(err) - } - raw, _ := json.Marshal(map[string]any{"bundle": bundle, "snapshotToken": snapshot.Token, "outputId": "patient", "limit": 25}) - response := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/preview", string(raw)) - if response.StatusCode != http.StatusOK || previewCalls != 1 { - t.Fatalf("preview=%d calls=%d %s", response.StatusCode, previewCalls, response.Body) - } - if _, err := service.CompilationReceipt(ctx, resolved.Receipt.ID); !errors.Is(err, explorer.ErrNotFound) { - t.Fatalf("preview persisted receipt: %v", err) - } - if _, err := service.ActiveRevision(ctx, "project-a", "custom"); !errors.Is(err, explorer.ErrNotFound) { - t.Fatalf("preview changed active revision: %v", err) - } -} - -func TestPreviewAndPublishNormalizeLegacyCandidateSelection(t *testing.T) { - ctx := context.Background() - store := explorer.NewMemoryStore() - if _, err := store.CreateInteractive(ctx, explorer.Explorer{Project: "project-a", ExplorerID: "custom", Title: "Custom", ManagementMode: explorer.ManagementInteractive}); err != nil { - t.Fatal(err) - } - snapshot := authoringTestSnapshot(t) - app, _ := publishOnlyAuthoringApp(t, store, snapshot, - func(context.Context, recipe.Bundle, recipe.RuntimeBindings) (map[string][]map[string]any, error) { - return map[string][]map[string]any{"patient": {{"id": "p1"}}}, nil - }, - func(_ context.Context, bundle recipe.Bundle, _ recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { - return graphresolver.RecipeExecution{ID: "execution-a", SourceGeneration: snapshot.Generation, Outputs: []graphresolver.RecipeExecutionOutput{{Name: bundle.Outputs[0].Name, State: "PUBLISHED"}}}, nil - }, - ) - bundle := authoringTestBundleWithoutCandidateOccurrences(explorer.ExplorerBuilderDocumentV1{ - Kind: explorer.ExplorerBuilderV1Kind, - Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, - BaseNodeID: "n_base", - RowNodeID: "n_base", - CandidateIDs: []string{ - "s_base", - }, - }) - raw, err := json.Marshal(map[string]any{"bundle": bundle, "snapshotToken": snapshot.Token, "outputId": "patient", "limit": 25}) - if err != nil { - t.Fatal(err) - } - preview := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/preview", string(raw)) - if preview.StatusCode != http.StatusOK { - t.Fatalf("preview=%d %s", preview.StatusCode, preview.Body) - } - publishRaw, err := json.Marshal(map[string]any{"bundle": bundle, "snapshotToken": snapshot.Token}) - if err != nil { - t.Fatal(err) - } - publish := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/publish", string(publishRaw)) - if publish.StatusCode != http.StatusOK { - t.Fatalf("publish=%d %s", publish.StatusCode, publish.Body) - } -} - -func TestPublishReturnsReloadableResolvedBuilderState(t *testing.T) { - store := explorer.NewMemoryStore() - if _, err := store.CreateInteractive(context.Background(), explorer.Explorer{Project: "project-a", ExplorerID: "custom", Title: "Custom", ManagementMode: explorer.ManagementInteractive}); err != nil { - t.Fatal(err) - } - snapshot := authoringTestSnapshot(t) - materializeCalls := 0 - app, _ := publishOnlyAuthoringApp(t, store, snapshot, nil, func(_ context.Context, bundle recipe.Bundle, _ recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { - materializeCalls++ - return graphresolver.RecipeExecution{ID: "execution-a", SourceGeneration: snapshot.Generation, Outputs: []graphresolver.RecipeExecutionOutput{{Name: bundle.Outputs[0].Name, State: "PUBLISHED"}}}, nil - }) - document := explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient", Title: "Patients"}, BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"s_base"}} - bundle := authoringTestBundle(document) - raw, _ := json.Marshal(map[string]any{"bundle": bundle, "snapshotToken": snapshot.Token}) - published := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/publish", string(raw)) - if published.StatusCode != http.StatusOK || materializeCalls != 1 { - t.Fatalf("publish=%d calls=%d %s", published.StatusCode, materializeCalls, published.Body) - } - var first explorer.ExplorerBuilderStateV1 - decodeBody(t, published.Body, &first) - if first.Active.RevisionID == "" || len(first.Bindings) != 1 || first.Bindings[0].BaseResourceType != "Patient" || first.Bindings[0].RouteKind != "ZERO_HOP" { - t.Fatalf("published Builder state=%#v", first) - } - reloaded := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v1/builder", "") - if reloaded.StatusCode != http.StatusOK { - t.Fatalf("reload=%d %s", reloaded.StatusCode, reloaded.Body) - } - var second explorer.ExplorerBuilderStateV1 - decodeBody(t, reloaded.Body, &second) - if second.Active.RevisionID != first.Active.RevisionID || len(second.Bindings) != 1 || second.Bindings[0].CandidateEmissions[0].EmissionID != first.Bindings[0].CandidateEmissions[0].EmissionID { - t.Fatalf("reload did not preserve authoritative bindings: first=%#v second=%#v", first, second) - } -} - -func TestFailedPublishPreservesActiveRevision(t *testing.T) { - ctx := context.Background() - store := explorer.NewMemoryStore() - if _, err := store.CreateInteractive(ctx, explorer.Explorer{Project: "project-a", ExplorerID: "custom", ManagementMode: explorer.ManagementInteractive}); err != nil { - t.Fatal(err) - } - if _, err := store.InsertRevision(ctx, explorer.Revision{ID: "prior", Project: "project-a", ExplorerID: "custom", Status: explorer.RevisionReady}); err != nil { - t.Fatal(err) - } - if err := store.ActivateInteractive(ctx, "project-a", "custom", "prior"); err != nil { - t.Fatal(err) - } - snapshot := authoringTestSnapshot(t) - app, service := publishOnlyAuthoringApp(t, store, snapshot, nil, func(context.Context, recipe.Bundle, recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { - return graphresolver.RecipeExecution{}, errors.New("offline") - }) - bundle := authoringTestBundle(explorer.ExplorerBuilderDocumentV1{Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient"}, BaseNodeID: "n_base", RowNodeID: "n_base"}) - raw, _ := json.Marshal(map[string]any{"bundle": bundle, "snapshotToken": snapshot.Token}) - response := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/publish", string(raw)) - if response.StatusCode != http.StatusServiceUnavailable || !strings.Contains(response.Body, "MATERIALIZATION_FAILED") { - t.Fatalf("publish=%d %s", response.StatusCode, response.Body) - } - active, err := service.ActiveRevision(ctx, "project-a", "custom") - if err != nil || active.ID != "prior" { - t.Fatalf("active revision changed: %#v err=%v", active, err) - } -} - -func TestPostBuilderReconcilesIntentWithoutWrites(t *testing.T) { - ctx := context.Background() - store := explorer.NewMemoryStore() - if _, err := store.CreateInteractive(ctx, explorer.Explorer{Project: "project-a", ExplorerID: "custom", Title: "Custom", ManagementMode: explorer.ManagementInteractive}); err != nil { - t.Fatal(err) - } - snapshot := authoringTestSnapshot(t) - app, service := publishOnlyAuthoringApp(t, store, snapshot, nil, nil) - document := explorer.ExplorerBuilderDocumentV1{ - Kind: explorer.ExplorerBuilderV1Kind, Output: explorer.ExplorerOutputIdentityV1{ID: "patient", Title: "Patients"}, - BaseNodeID: "n_base", RowNodeID: "n_base", CandidateIDs: []string{"s_base"}, - CandidateOccurrences: []explorer.ExplorerCandidateOccurrenceV1{{CandidateID: "s_base", OccurrenceID: "base"}}, - } - bundle := authoringTestBundle(document) - raw, _ := json.Marshal(map[string]any{"bundle": bundle, "snapshotToken": snapshot.Token}) - response := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/builder", string(raw)) - if response.StatusCode != http.StatusOK { - t.Fatalf("builder reconcile=%d %s", response.StatusCode, response.Body) - } - var state explorer.ExplorerBuilderStateV1 - decodeBody(t, response.Body, &state) - if len(state.Bindings) != 1 || len(state.Bindings[0].CandidateEmissions) != 1 || state.Bindings[0].CandidateEmissions[0].PublicColumn == "" { - t.Fatalf("resolved builder binding=%#v", state.Bindings) - } - if _, err := service.ActiveRevision(ctx, "project-a", "custom"); !errors.Is(err, explorer.ErrNotFound) { - t.Fatalf("POST Builder changed active revision: %v", err) - } -} - -func TestTableIdentityIsServerAllocatedAndIdempotent(t *testing.T) { - store := explorer.NewMemoryStore() - if _, err := store.CreateInteractive(context.Background(), explorer.Explorer{Project: "project-a", ExplorerID: "custom", Title: "Custom", ManagementMode: explorer.ManagementInteractive}); err != nil { - t.Fatal(err) - } - app, _ := publishOnlyAuthoringApp(t, store, authoringTestSnapshot(t), nil, nil) - body := `{"title":"Biospecimens","requestId":"new-table-1","occupiedOutputIds":["biospecimens"],"occupiedTabIds":["biospecimens"]}` - response := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/table-identity", body) - repeated := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v1/table-identity", body) - if response.StatusCode != http.StatusOK || response.Body != repeated.Body || !strings.Contains(response.Body, `"kind":"ExplorerTableIdentity"`) || strings.Contains(response.Body, `"id":"biospecimens`) { - t.Fatalf("table identity=%d %s", response.StatusCode, response.Body) - } -} diff --git a/internal/server/explorer_capability.go b/internal/server/explorer_capability.go index 67676610..09174383 100644 --- a/internal/server/explorer_capability.go +++ b/internal/server/explorer_capability.go @@ -15,7 +15,6 @@ import ( compilerprobe "github.com/calypr/loom/internal/dataframe/compiler/capability" "github.com/calypr/loom/internal/dataframe/spec" "github.com/calypr/loom/internal/dataset" - "github.com/calypr/loom/internal/explorer" "github.com/calypr/loom/internal/explorer/authoringv2" "github.com/calypr/loom/internal/explorer/capability" "github.com/calypr/loom/internal/explorer/capabilitystore" @@ -24,12 +23,19 @@ import ( ) const ( - explorerCapabilityCompilerVersion = "loom-dataframe-compiler-v2" + explorerCapabilityCompilerVersion = "loom-dataframe-compiler-v3" explorerCapabilityProtocolVersion = "loom.calypr.org/explorer-authoring/v2" explorerTraversalPolicyVersion = "finite-unbounded-v1" explorerProjectionPolicyVersion = "compiler-probed-v1" ) +func explorerScopeDigest(scope authscope.ReadScope) string { + paths := append([]string(nil), scope.AuthResourcePaths...) + sort.Strings(paths) + sum := sha256.Sum256([]byte(string(scope.Mode) + "\x00" + strings.Join(paths, "\x00"))) + return hex.EncodeToString(sum[:]) +} + // explorerCapabilityResolver is the one construction boundary for Builder // capabilities. Catalog observations are evidence only; every public item is // intersected with the real dataframe compiler before the immutable snapshot @@ -177,27 +183,6 @@ func (r *explorerCapabilityResolver) Resolve(ctx context.Context, project, reque return value.(capability.Snapshot).Clone(), nil } -// ResolveActiveAuthorized is the scope-preserving form of Resolve. It is used -// by capability/catalog reads that select the active generation directly. The -// legacy Resolve method remains available for adapters that only need the -// public snapshot projection. -func (r *explorerCapabilityResolver) ResolveActiveAuthorized(ctx context.Context, project, requestedGeneration string) (AuthorizedCapability, error) { - snapshot, err := r.Resolve(ctx, project, requestedGeneration) - if err != nil { - return AuthorizedCapability{}, err - } - canonicalProject := projectid.Canonical(project) - principal, _ := authscope.PrincipalFromContext(ctx) - scope, err := r.resolveScope(ctx, principal, projectid.Legacy(canonicalProject), snapshot.Identity.Generation) - if err != nil { - return AuthorizedCapability{}, err - } - if explorerScopeDigest(scope) != snapshot.Identity.AuthorizationScopeDigest { - return AuthorizedCapability{}, capability.ErrStaleSnapshot - } - return AuthorizedCapability{Snapshot: snapshot.Clone(), Scope: scope.Clone()}, nil -} - // ResolveToken loads an exact retained snapshot. It never substitutes the // current active generation, and it re-authorizes the caller against the // snapshot's generation and exact authorization-scope digest. @@ -335,15 +320,27 @@ func capabilityObserverFromEvidence(value catalog.CapabilityEvidence) capability } relationships := map[string]capability.RelationshipObservation{} for _, item := range value.Relationships.Values { - key := strings.Join([]string{item.BuilderFromType, item.Label, item.BuilderToType, item.BuilderDirection}, "\x00") - observation := relationships[key] - observation.SourceResourceType = item.BuilderFromType - observation.TargetResourceType = item.BuilderToType - observation.Label = item.Label - observation.StorageDirection = item.BuilderDirection - observation.ObservedEdgeCount += item.EdgeCount - observation.AllowsRepeatedTarget = true - relationships[key] = observation + // A stored FHIR reference is navigable in both directions. Catalog + // evidence retains the physical OUTBOUND orientation, while the + // dataframe compiler proves whether either generated traversal is + // legal. Publish both observations here and let ProbeEdge remove any + // direction the generated schema cannot lower. + for _, route := range []struct { + from, to, direction string + }{ + {item.StorageFromType, item.StorageToType, "OUTBOUND"}, + {item.StorageToType, item.StorageFromType, "INBOUND"}, + } { + key := strings.Join([]string{route.from, item.Label, route.to, route.direction}, "\x00") + observation := relationships[key] + observation.SourceResourceType = route.from + observation.TargetResourceType = route.to + observation.Label = item.Label + observation.StorageDirection = route.direction + observation.ObservedEdgeCount += item.EdgeCount + observation.AllowsRepeatedTarget = true + relationships[key] = observation + } } for _, item := range relationships { out.relationships = append(out.relationships, item) @@ -435,41 +432,6 @@ func (c explorerCapabilityCompiler) ProbeCandidate(ctx context.Context, candidat return proof, nil } -func legacyCatalogSnapshot(snapshot capability.Snapshot) explorer.CatalogSnapshot { - catalogValue := explorer.Catalog{Selections: map[string]explorer.CatalogSelection{}} - for _, node := range snapshot.Nodes { - catalogValue.Nodes = append(catalogValue.Nodes, explorer.CatalogNode{ID: node.ID, ResourceType: node.ResourceType}) - } - for _, edge := range snapshot.Edges { - catalogValue.Edges = append(catalogValue.Edges, explorer.CatalogEdge{ID: edge.ID, FromNodeID: edge.FromNodeID, ToNodeID: edge.ToNodeID, Label: edge.Label}) - } - for _, candidate := range snapshot.Candidates { - catalogValue.Selections[candidate.ID] = explorer.CatalogSelection{ - ID: candidate.ID, NodeID: candidate.NodeID, - FieldRef: explorerFieldRef(candidate.ResourceType, candidate.FieldPath), Select: candidate.FieldPath, - LogicalType: candidate.LogicalType, - Cardinality: candidate.Cardinality, - ProjectionModes: stringProjectionModes(candidate.ProjectionModes), - DefaultProjectionMode: defaultProjectionMode(stringProjectionModes(candidate.ProjectionModes)), - FilterOperators: stringFilterOperators(candidate.FilterOperators), - ChartOperations: stringChartOperations(candidate.ChartAggregations), - Filterable: len(candidate.FilterOperators) > 0, - Chartable: len(candidate.ChartAggregations) > 0, - } - } - diagnostics := make([]explorer.Diagnostic, 0, len(snapshot.Diagnostics)) - for _, diagnostic := range snapshot.Diagnostics { - diagnostics = append(diagnostics, explorer.Diagnostic{Severity: diagnostic.Severity, Code: diagnostic.Code, Message: diagnostic.Message, Retryable: diagnostic.Retryable}) - } - return explorer.CatalogSnapshot{ - Project: snapshot.Identity.Project, Generation: snapshot.Identity.Generation, - AuthorizationScopeDigest: snapshot.Identity.AuthorizationScopeDigest, - ResolvedSchemaDigest: snapshot.Identity.SchemaDigest, - Catalog: catalogValue, Complete: snapshot.Complete, Truncated: snapshot.Truncated, - Diagnostics: diagnostics, Token: snapshot.Token, - } -} - func authoringV2Catalog(snapshot capability.Snapshot, explorerID string) authoringv2.CatalogSnapshot { result := authoringv2.CatalogSnapshot{ APIVersion: authoringv2.APIVersion, Kind: authoringv2.CatalogKind, @@ -500,6 +462,7 @@ func authoringV2Catalog(snapshot capability.Snapshot, explorerID string) authori count := candidate.ObservedDocumentCount wire := authoringv2.CatalogCandidate{ ID: candidate.ID, NodeID: candidate.NodeID, Label: candidate.Label, + FieldPath: candidate.FieldPath, LogicalType: candidate.LogicalType, Cardinality: candidate.Cardinality, Repeated: candidate.Cardinality != "scalar", Filterable: len(candidate.FilterOperators) > 0, Chartable: len(candidate.ChartAggregations) > 0, ProjectionModes: projectionModes, DefaultProjectionMode: defaultProjectionMode(projectionModes), diff --git a/internal/server/explorer_capability_test.go b/internal/server/explorer_capability_test.go index ef076dc5..97bce33c 100644 --- a/internal/server/explorer_capability_test.go +++ b/internal/server/explorer_capability_test.go @@ -2,21 +2,14 @@ package server import ( "context" - "encoding/json" "errors" - "net/http" "strings" "testing" "github.com/calypr/loom/internal/authscope" "github.com/calypr/loom/internal/catalog" - "github.com/calypr/loom/internal/dataframe/recipe" "github.com/calypr/loom/internal/dataset" - "github.com/calypr/loom/internal/explorer" - "github.com/calypr/loom/internal/explorer/authoringv2" "github.com/calypr/loom/internal/explorer/capability" - "github.com/calypr/loom/internal/explorer/capabilitystore" - "github.com/gofiber/fiber/v3" ) type staticCapabilityEvidence struct { @@ -72,9 +65,29 @@ func testCapabilityScopeResolver(paths []string) *authscope.ScopeResolver { }) } +func TestAuthoringV2CatalogExposesCandidateFieldPath(t *testing.T) { + snapshot := capability.NewSnapshot( + capability.SnapshotIdentity{Project: "project-a", Generation: "generation-a"}, + capability.Policy{}, capability.StatusReady, true, false, + []capability.Node{{ID: "n_patient", ResourceType: "Patient", RowRootEligible: true}}, + nil, + []capability.Candidate{{ + ID: "c_patient_birth_date", NodeID: "n_patient", ResourceType: "Patient", + FieldPath: "birthDate", Label: "Birth date", LogicalType: "date", + ProjectionModes: []capability.ProjectionMode{capability.ProjectionFirst}, + }}, + nil, + ) + + wire := authoringV2Catalog(snapshot, "default") + if len(wire.Candidates) != 1 || wire.Candidates[0].FieldPath != "birthDate" { + t.Fatalf("catalog candidates = %#v", wire.Candidates) + } +} + func TestExplorerCapabilityResolverAuthorizedCompilationRequiresActiveGeneration(t *testing.T) { manifest := testCapabilityManifest(t) - store := capabilitystore.NewMemoryStore() + store := newTestCapabilityStore() snapshot := testAuthorizedCapabilitySnapshot(t, "generation-a", authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}) if _, err := store.Put(context.Background(), snapshot); err != nil { t.Fatal(err) @@ -102,7 +115,7 @@ func TestExplorerCapabilityResolverAuthorizedCompilationRequiresActiveGeneration func TestExplorerCapabilityResolverAuthorizedExecutionRetainsInactiveGeneration(t *testing.T) { manifest := testCapabilityManifest(t) - store := capabilitystore.NewMemoryStore() + store := newTestCapabilityStore() snapshot := testAuthorizedCapabilitySnapshot(t, "generation-old", authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}) if _, err := store.Put(context.Background(), snapshot); err != nil { t.Fatal(err) @@ -122,7 +135,7 @@ func TestExplorerCapabilityResolverAuthorizedExecutionRetainsInactiveGeneration( func TestExplorerCapabilityResolverEnforcesProjectAuthorizationWithoutScopeResolver(t *testing.T) { manifest := testCapabilityManifest(t) - store := capabilitystore.NewMemoryStore() + store := newTestCapabilityStore() snapshot := testAuthorizedCapabilitySnapshot(t, "generation-a", authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}) if _, err := store.Put(context.Background(), snapshot); err != nil { t.Fatal(err) @@ -139,7 +152,7 @@ func TestExplorerCapabilityResolverEnforcesProjectAuthorizationWithoutScopeResol func TestExplorerCapabilityResolverRejectsChangedScopeAndPreservesRestrictedEmpty(t *testing.T) { manifest := testCapabilityManifest(t) - store := capabilitystore.NewMemoryStore() + store := newTestCapabilityStore() unrestricted := testAuthorizedCapabilitySnapshot(t, "generation-a", authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}) if _, err := store.Put(context.Background(), unrestricted); err != nil { t.Fatal(err) @@ -189,7 +202,7 @@ func TestExplorerCapabilityResolverBuildsAndReusesCompilerProvenSnapshot(t *test relationships: catalog.RelationshipObservationResult{Values: []catalog.RelationshipObservation{}, Available: true, Complete: true, Status: catalog.EvidenceEmpty, Digest: relationshipDigest}, fields: catalog.FieldEnrichmentResult{Values: fields, Available: true, Complete: true, Status: catalog.EvidenceAvailable, Digest: fieldDigest}, } - repository := capabilitystore.NewMemoryStore() + repository := newTestCapabilityStore() resolver, err := newExplorerCapabilityResolver(evidence, nil, staticActiveManifest{manifest: manifest}, repository) if err != nil { t.Fatal(err) @@ -226,7 +239,7 @@ func TestExplorerCapabilityResolverFailsClosedOnIncompleteFieldEnrichment(t *tes relationships: catalog.RelationshipObservationResult{Values: []catalog.RelationshipObservation{}, Available: true, Complete: true, Status: catalog.EvidenceEmpty, Digest: "sha256:relationships"}, fields: catalog.FieldEnrichmentResult{Values: []catalog.FieldEnrichmentObservation{}, Available: true, Complete: false, Status: catalog.EvidenceIncomplete, Digest: "sha256:fields"}, } - resolver, err := newExplorerCapabilityResolver(evidence, nil, staticActiveManifest{manifest: manifest}, capabilitystore.NewMemoryStore()) + resolver, err := newExplorerCapabilityResolver(evidence, nil, staticActiveManifest{manifest: manifest}, newTestCapabilityStore()) if err != nil { t.Fatal(err) } @@ -235,77 +248,23 @@ func TestExplorerCapabilityResolverFailsClosedOnIncompleteFieldEnrichment(t *tes } } -func TestExplorerAuthoringV2HardCutCompilesAndPreviewsReceipt(t *testing.T) { - snapshot := testAuthoringV2CapabilitySnapshot() - store := explorer.NewMemoryStore() - service, err := explorer.NewService(store) - if err != nil { - t.Fatal(err) - } - if _, err := service.CreateEmptyInteractive(context.Background(), "project-a", "custom", "Custom", "test"); err != nil { - t.Fatal(err) - } - legacy := legacyCatalogSnapshot(snapshot) - compile := func(ctx context.Context, request ExplorerAuthoringV1CompileRequest) (ExplorerAuthoringV1CompileResult, error) { - return ResolveAuthoringBundle(ctx, nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { return legacy, nil }, request) - } - app := fiber.New() - RegisterExplorerAuthoringV2Routes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{ - Capability: func(context.Context, string, string, string) (capability.Snapshot, error) { return snapshot, nil }, - CapabilityToken: func(_ context.Context, _ string, token string) (capability.Snapshot, error) { - if err := snapshot.ValidateToken(token); err != nil { - return capability.Snapshot{}, err - } - return snapshot, nil - }, - AuthorizedCapabilityExecution: func(_ context.Context, _, token string) (AuthorizedCapability, error) { - if err := snapshot.ValidateToken(token); err != nil { - return AuthorizedCapability{}, err - } - return AuthorizedCapability{Snapshot: snapshot, Scope: authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}}, nil - }, - AuthoringCompile: compile, - Preview: func(_ context.Context, _ recipe.Bundle, _ recipe.RuntimeBindings) (map[string][]map[string]any, error) { - return map[string][]map[string]any{"patients": {{"id": "patient-1"}}}, nil - }, +func TestCapabilityObserverPublishesBothStoredRelationshipDirections(t *testing.T) { + observer := capabilityObserverFromEvidence(catalog.CapabilityEvidence{ + Relationships: catalog.RelationshipObservationResult{Values: []catalog.RelationshipObservation{{ + Label: "subject_Patient", EdgeCount: 7, + StorageFromType: "Specimen", StorageToType: "Patient", StorageDirection: "OUTBOUND", + BuilderFromType: "Patient", BuilderToType: "Specimen", BuilderDirection: "INBOUND", + }}}, }) - - get := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v2/builder", "") - if get.StatusCode != http.StatusOK { - t.Fatalf("GET builder status=%d body=%s", get.StatusCode, get.Body) - } - legacyResponse := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v1/builder", "") - if legacyResponse.StatusCode != http.StatusNotFound { - t.Fatalf("V1 Builder remains registered: status=%d", legacyResponse.StatusCode) - } - suggestions := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v2/capabilities/"+snapshot.Token+"/candidates/c_patient_id/suggestions", "") - if suggestions.StatusCode != http.StatusOK || !strings.Contains(suggestions.Body, `"patient-1"`) { - t.Fatalf("candidate suggestions status=%d body=%s", suggestions.StatusCode, suggestions.Body) - } - body := `{"workspace":{"apiVersion":"` + authoringv2.APIVersion + `","kind":"` + authoringv2.WorkspaceKind + `","documents":[{"kind":"` + authoringv2.Kind + `","output":{"id":"patients","title":"Patients"},"rootNodeId":"n_patient","routeSteps":[],"selections":[{"candidateId":"c_patient_id","occurrenceId":"base","projectionMode":"FIRST"}],"presentation":{}}],"tabs":[{"id":"patients-tab","title":"Patients","outputId":"patients","order":0,"visible":true}]},"snapshotToken":"` + snapshot.Token + `"}` - compiled := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/builder", body) - if compiled.StatusCode != http.StatusOK { - t.Fatalf("POST builder status=%d body=%s", compiled.StatusCode, compiled.Body) - } - var result struct { - ReceiptID string `json:"receiptId"` - } - if err := json.Unmarshal([]byte(compiled.Body), &result); err != nil { - t.Fatal(err) - } - if result.ReceiptID == "" { - t.Fatal("compile result omitted receiptId") - } - receipt, err := service.CompilationReceipt(context.Background(), result.ReceiptID) - if err != nil { - t.Fatal(err) + got := map[string]capability.RelationshipObservation{} + for _, relationship := range observer.relationships { + got[relationship.SourceResourceType+"->"+relationship.TargetResourceType] = relationship } - if got := receipt.Bundle.Outputs[0].Fields[0].ValueMode; got != recipe.ValueModeFirst { - t.Fatalf("V2 projection mode was not carried into the executable recipe: %q", got) + if outbound := got["Specimen->Patient"]; outbound.StorageDirection != "OUTBOUND" || outbound.ObservedEdgeCount != 7 { + t.Fatalf("outbound relationship = %#v", outbound) } - preview := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/preview", `{"receiptId":"`+result.ReceiptID+`","outputId":"patients","limit":5}`) - if preview.StatusCode != http.StatusOK { - t.Fatalf("preview status=%d body=%s", preview.StatusCode, preview.Body) + if inbound := got["Patient->Specimen"]; inbound.StorageDirection != "INBOUND" || inbound.ObservedEdgeCount != 7 { + t.Fatalf("inbound relationship = %#v", inbound) } } diff --git a/internal/server/explorer_config_route.go b/internal/server/explorer_config_route.go index 9be86c46..7379b560 100644 --- a/internal/server/explorer_config_route.go +++ b/internal/server/explorer_config_route.go @@ -12,18 +12,18 @@ import ( "github.com/calypr/loom/internal/dataframe/recipe" "github.com/calypr/loom/internal/dataset" "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/explorer/authoringv2" "github.com/calypr/loom/internal/projectid" "github.com/gofiber/fiber/v3" ) // RegisterExplorerConfigV2Route is the sole repository Explorer deployment -// surface. The body is the portable, executable baseline ExplorerConfigV2 -// document; generation and source commit are deployment context, while live -// schema/readiness and publication metadata are derived by Loom. +// surface. The body is the portable V2 authoring workspace. Repository and +// browser publication deliberately share the same compiler receipt pipeline. type explorerConfigReadAuthorizer func(context.Context, *authscope.Principal, string) error func RegisterExplorerConfigV2Route(app *fiber.App, authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, explorers *explorer.Service, materialize graphresolver.ExplorerBundleMaterializer, lifecycle ...ExplorerV2LifecycleConfig) { - if app == nil || authorizer == nil || authorizeRead == nil || explorers == nil || materialize == nil { + if app == nil || authorizer == nil || authorizeRead == nil || explorers == nil { return } app.Post("/api/v1/projects/:project/generations/:generation/explorer-config", func(c fiber.Ctx) error { @@ -38,50 +38,78 @@ func RegisterExplorerConfigV2Route(app *fiber.App, authorizer authscope.Authoriz if err := authorizer.AuthorizeWrite(c.Context(), principal, project, authResourcePath); err != nil { return c.Status(http.StatusForbidden).JSON(fiber.Map{"error": "forbidden"}) } - _, bundle, err := explorer.DecodeConfigV2(c.Body(), project) + workspace, err := authoringv2.DecodeWorkspace(c.Body()) if err != nil { return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()}) } - // Version the execution by the checked-out repository commit while - // retaining a data-only recipe body. A project-specific bundle name - // prevents two repository configs from sharing a publication namespace. + if err := workspace.ValidateForPublication(); err != nil { + return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()}) + } commit := strings.TrimSpace(c.Get("X-Loom-Source-Commit")) if commit == "" { return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "X-Loom-Source-Commit is required"}) } - // Recipe names are storage/execution identifiers, not public project - // URLs. Keep the historical hyphenated form so a canonical slash in the - // route never becomes an invalid name containing '/'. - bundle.Name = "explorer_" + projectid.Legacy(project) + "_default" - bundle.TranslationVersion = "repository-" + commit - if err := bundle.Validate(); err != nil { - return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"error": fmt.Sprintf("invalid recipe: %v", err)}) + if len(lifecycle) == 0 || lifecycle[0].Capability == nil || lifecycle[0].AuthorizedCapabilityCompile == nil || lifecycle[0].CompileReceipt == nil { + return c.Status(http.StatusServiceUnavailable).JSON(fiber.Map{"error": "repository V2 compilation is not configured"}) } - _, _, canonicalConfig, configDigest, err := explorer.CanonicalConfigV2(c.Body(), project, "default", "repository") + config := lifecycle[0] + snapshot, err := config.Capability(c.Context(), project, "default", generation) + if err != nil || !snapshot.Usable() || snapshot.Identity.Generation != generation { + if err == nil { + err = fmt.Errorf("capability generation %q does not match deployment generation %q", snapshot.Identity.Generation, generation) + } + return c.Status(http.StatusConflict).JSON(fiber.Map{"error": fmt.Sprintf("resolve repository V2 capability: %v", err)}) + } + authorized, err := config.AuthorizedCapabilityCompile(c.Context(), project, snapshot.Token) if err != nil { - return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error()}) + return c.Status(http.StatusForbidden).JSON(fiber.Map{"error": fmt.Sprintf("authorize repository V2 compilation: %v", err)}) + } + receipt, err := config.CompileReceipt(c.Context(), ExplorerV2ReceiptCompileRequest{Project: project, ExplorerID: "default", Workspace: workspace, SnapshotToken: snapshot.Token, RequestID: requestIDFromFiber(c), Authorized: authorized}) + if err != nil || receipt == nil { + if err == nil { + err = fmt.Errorf("compiler returned no receipt") + } + return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"error": fmt.Sprintf("compile repository V2 workspace: %v", err)}) + } + if receipt.SourceGeneration != generation { + return c.Status(http.StatusConflict).JSON(fiber.Map{"error": "compiled receipt generation does not match deployment generation"}) + } + if config.AuthorizedCapabilityExecution != nil { + authorized, err = config.AuthorizedCapabilityExecution(c.Context(), project, receipt.SnapshotToken) + if err != nil { + return c.Status(http.StatusForbidden).JSON(fiber.Map{"error": fmt.Sprintf("authorize repository V2 materialization: %v", err)}) + } + } + bindings := recipe.RuntimeBindings{Project: projectid.Legacy(project), DatasetGeneration: generation} + applyAuthorizedScope(&bindings, authorized, true) + var execution graphresolver.RecipeExecution + if config.MaterializeReceipt != nil { + execution, err = config.MaterializeReceipt(c.Context(), receipt, bindings) + } else if materialize != nil { + execution, err = materialize(c.Context(), receipt.Bundle, bindings) + } else { + err = fmt.Errorf("repository V2 materialization is not configured") } - execution, err := materialize(c.Context(), bundle, recipe.RuntimeBindings{Project: projectid.Legacy(project), DatasetGeneration: generation}) if err != nil { - return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"error": fmt.Sprintf("materialize ExplorerConfigV2: %v", err)}) + return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"error": fmt.Sprintf("materialize repository V2 workspace: %v", err)}) } - if err := verifyQueryableOutputs(bundle, execution); err != nil { + if err := verifyQueryableOutputs(receipt.Bundle, execution); err != nil { return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"error": err.Error(), "executionId": execution.ID}) } - materializations := explorerMaterializations(bundle, execution) - dataset := datasetMetadataFromExecution(bundle, generation, execution.ResolvedSchemaDigest, execution) + materializations := explorerMaterializations(receipt.Bundle, execution) + dataset := datasetMetadataFromExecution(receipt.Bundle, generation, receipt.ResolvedSchemaDigest, execution) publication := explorer.PublicationMetadata{State: string(explorer.RevisionReady), Generation: generation, ExecutionID: execution.ID, UpdatedAt: time.Now().UTC()} - owner, revision, err := explorers.UpsertRepositoryV2(c.Context(), canonicalConfig, commit, generation, "", explorer.Compilation{Bundle: bundle, RecipeDigest: mustBundleDigest(bundle)}, execution.ResolvedSchemaDigest, materializations, dataset, publication) + owner, revision, err := explorers.UpsertRepositoryV2(c.Context(), *receipt, commit, subjectFromFiber(c), materializations, dataset, publication) if err != nil { return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": fmt.Sprintf("persist Explorer lifecycle V2: %v", err)}) } if owner.ManagementMode != explorer.ManagementRepository { return c.Status(http.StatusConflict).JSON(fiber.Map{"error": "default Explorer has invalid management mode"}) } - if len(lifecycle) == 0 || lifecycle[0].ActivateRelease == nil { + if config.ActivateRelease == nil { return c.Status(http.StatusServiceUnavailable).JSON(fiber.Map{"error": "release activation is not configured", "executionId": execution.ID}) } - if err := lifecycle[0].ActivateRelease(c.Context(), projectid.Legacy(project), generation, selectorsForBundle(bundle)); err != nil { + if err := config.ActivateRelease(c.Context(), projectid.Legacy(project), generation, selectorsForBundle(receipt.Bundle)); err != nil { _, _ = explorers.FailRevision(c.Context(), revision.ID, []explorer.Diagnostic{{Severity: "ERROR", Code: "RELEASE_ACTIVATION_FAILED", Message: err.Error(), Retryable: true}}) return c.Status(http.StatusConflict).JSON(fiber.Map{"error": fmt.Sprintf("activate published ExplorerConfigV2: %v", err), "executionId": execution.ID}) } @@ -91,10 +119,10 @@ func RegisterExplorerConfigV2Route(app *fiber.App, authorizer authscope.Authoriz publication.State = string(explorer.RevisionActive) publication.RevisionID = revision.ID publication.UpdatedAt = time.Now().UTC() - if _, err := explorers.SaveRepositoryConfig(c.Context(), explorer.RepositoryConfig{Project: project, Config: canonicalConfig, ConfigDigest: configDigest, ActiveRevisionID: revision.ID, DraftVersion: owner.DraftVersion, SourceGeneration: generation, SourceCommit: commit, ExecutionID: execution.ID, Materializations: materializations, Dataset: dataset, Publication: publication}); err != nil { + if _, err := explorers.SaveRepositoryConfig(c.Context(), explorer.RepositoryConfig{Project: project, Config: append([]byte(nil), receipt.CompiledConfig...), Workspace: append([]byte(nil), receipt.NormalizedBundle...), ConfigDigest: receipt.IntentDigest, IntentDigest: receipt.IntentDigest, CompilationReceiptID: receipt.ID, PublicOutputContract: append([]byte(nil), receipt.PublicOutputContract...), ActiveRevisionID: revision.ID, DraftVersion: owner.DraftVersion, SourceGeneration: generation, SourceCommit: commit, ExecutionID: execution.ID, Materializations: materializations, Dataset: dataset, Publication: publication}); err != nil { return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": fmt.Sprintf("persist ExplorerConfigV2: %v", err)}) } - return c.Status(http.StatusOK).JSON(fiber.Map{"project": project, "generation": generation, "explorerId": "default", "executionId": execution.ID, "recipe": bundle.Name, "translationVersion": bundle.TranslationVersion, "activated": true}) + return c.Status(http.StatusOK).JSON(fiber.Map{"project": project, "generation": generation, "explorerId": "default", "receiptId": receipt.ID, "revisionId": revision.ID, "executionId": execution.ID, "recipe": receipt.Bundle.Name, "translationVersion": receipt.Bundle.TranslationVersion, "activated": true}) }) app.Get("/api/v1/projects/:project/explorer-config", func(c fiber.Ctx) error { project := explorerProjectParam(c) diff --git a/internal/server/explorer_config_route_test.go b/internal/server/explorer_config_route_test.go index c54bd42e..d70ee535 100644 --- a/internal/server/explorer_config_route_test.go +++ b/internal/server/explorer_config_route_test.go @@ -2,6 +2,7 @@ package server import ( "context" + "fmt" "io" "net/http" "net/http/httptest" @@ -10,46 +11,61 @@ import ( graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/dataframe/publication" "github.com/calypr/loom/internal/dataframe/recipe" "github.com/calypr/loom/internal/dataset" "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/explorer/capability" "github.com/gofiber/fiber/v3" ) func TestRepositoryDeploymentPersistsExecutableDataframeSelectors(t *testing.T) { - service, err := explorer.NewService(explorer.NewMemoryStore()) + store := newTestExplorerStore() + service, err := explorer.NewService(store) if err != nil { t.Fatal(err) } + snapshot := testAuthoringV2CapabilitySnapshot() materialize := func(_ context.Context, bundle recipe.Bundle, _ recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { - if bundle.Name != "explorer_project-a_default" || bundle.TranslationVersion != "repository-commit-a" { + if bundle.Name != "native-test" { t.Fatalf("materialized identity = %s/%s", bundle.Name, bundle.TranslationVersion) } - return graphresolver.RecipeExecution{ID: "execution-a", SourceGeneration: "generation-a", State: "PUBLISHED", Outputs: []graphresolver.RecipeExecutionOutput{{Name: "DocumentReference", State: "PUBLISHED"}}}, nil + return graphresolver.RecipeExecution{ID: "execution-a", SourceGeneration: "generation-a", State: "PUBLISHED", Outputs: []graphresolver.RecipeExecutionOutput{{Name: "patients", State: "PUBLISHED", Columns: []publication.PhysicalColumn{{Name: "c_patient", LogicalType: "string", ClickHouse: "String"}}}}}, nil } activationCount := 0 activateRelease := func(_ context.Context, project, generation string, selectors []dataset.DataframeSelector) error { activationCount++ - if project != "project-a" || generation != "generation-a" || len(selectors) != 1 || selectors[0].Output != "DocumentReference" { + if project != "project-a" || generation != "generation-a" || len(selectors) != 1 || selectors[0].Output != "patients" { t.Fatalf("release activation = %s/%s %#v", project, generation, selectors) } return nil } app := fiber.New() - RegisterExplorerConfigV2Route(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, materialize, ExplorerV2LifecycleConfig{ActivateRelease: activateRelease}) + config := ExplorerV2LifecycleConfig{ + Capability: func(context.Context, string, string, string) (capability.Snapshot, error) { return snapshot, nil }, + CapabilityToken: func(context.Context, string, string) (capability.Snapshot, error) { return snapshot, nil }, + AuthorizedCapabilityCompile: func(context.Context, string, string) (AuthorizedCapability, error) { + return AuthorizedCapability{Snapshot: snapshot, Scope: authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}}, nil + }, + CompileReceipt: func(ctx context.Context, request ExplorerV2ReceiptCompileRequest) (*explorer.CompilationReceipt, error) { + return persistTestNativeReceipt(ctx, t, service, request, snapshot) + }, + ActivateRelease: activateRelease, + } + RegisterExplorerConfigV2Route(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, materialize, config) - request := requestJSONWithHeaders(t, app, http.MethodPost, "/api/v1/projects/project-a/generations/generation-a/explorer-config", string(baselineExplorerConfigV2("project-a", "Default")), map[string]string{"X-Loom-Source-Commit": "commit-a"}) + request := requestJSONWithHeaders(t, app, http.MethodPost, "/api/v1/projects/project-a/generations/generation-a/explorer-config", string(baselineExplorerWorkspaceV2()), map[string]string{"X-Loom-Source-Commit": "commit-a"}) if request.StatusCode != http.StatusOK { t.Fatalf("deploy status=%d body=%s", request.StatusCode, request.Body) } - repeated := requestJSONWithHeaders(t, app, http.MethodPost, "/api/v1/projects/project-a/generations/generation-a/explorer-config", string(baselineExplorerConfigV2("project-a", "Default")), map[string]string{"X-Loom-Source-Commit": "commit-a"}) + repeated := requestJSONWithHeaders(t, app, http.MethodPost, "/api/v1/projects/project-a/generations/generation-a/explorer-config", string(baselineExplorerWorkspaceV2()), map[string]string{"X-Loom-Source-Commit": "commit-a"}) if repeated.StatusCode != http.StatusOK { t.Fatalf("repeated deploy status=%d body=%s", repeated.StatusCode, repeated.Body) } if activationCount != 2 { t.Fatalf("release activation count = %d, want 2", activationCount) } - state, err := getExplorerV2State(context.Background(), service, "project-a", "default") + state, err := service.Get(context.Background(), "project-a", "default") if err != nil { t.Fatal(err) } @@ -57,12 +73,58 @@ func TestRepositoryDeploymentPersistsExecutableDataframeSelectors(t *testing.T) t.Fatalf("dataset selector missing: %#v", state.Dataset.Outputs) } selector := state.Dataset.Outputs[0].Selector - if selector.Recipe != "explorer_project-a_default" || selector.TranslationVersion != "repository-commit-a" || selector.Output != "DocumentReference" { + if selector.Recipe != "native-test" || selector.Output != "patients" { t.Fatalf("dataset selector = %#v", selector) } if len(state.Materializations) != 1 || state.Materializations[0].Selector == nil || *state.Materializations[0].Selector != *selector { t.Fatalf("materialization selector = %#v", state.Materializations) } + active, err := service.ActiveRevision(context.Background(), "project-a", "default") + if err != nil { + t.Fatal(err) + } + if len(active.AuthoringBundle) == 0 || active.CompilationReceiptID == "" || len(active.PublicOutputContract) == 0 { + t.Fatalf("active repository revision lost V2 artifacts: %#v", active) + } + builder := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/default/authoring/v2/builder", "") + if builder.StatusCode != http.StatusOK || !strings.Contains(builder.Body, `"workspace"`) { + t.Fatalf("builder reload status=%d body=%s", builder.StatusCode, builder.Body) + } + draftBody := `{"workspace":` + string(baselineExplorerWorkspaceV2()) + `,"snapshotToken":"` + snapshot.Token + `","expectedDraftVersion":` + fmt.Sprint(state.DraftVersion) + `,"expectedDraftDigest":"` + state.DraftDigest + `"}` + draft := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/default/authoring/v2/draft", draftBody) + if draft.StatusCode != http.StatusOK || !strings.Contains(draft.Body, `"draftDigest":"sha256:`) { + t.Fatalf("save draft status=%d body=%s", draft.StatusCode, draft.Body) + } + stale := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/default/authoring/v2/draft", draftBody) + if stale.StatusCode != http.StatusConflict || !strings.Contains(stale.Body, `"code":"DRAFT_CONFLICT"`) { + t.Fatalf("stale draft status=%d body=%s", stale.StatusCode, stale.Body) + } + exported := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/default/authoring/v2/export", "") + if exported.StatusCode != http.StatusOK || exported.Body != string(baselineExplorerWorkspaceV2()) { + t.Fatalf("export status=%d body=%s", exported.StatusCode, exported.Body) + } + viewer := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/default", "") + if viewer.StatusCode != http.StatusOK || !strings.Contains(viewer.Body, `"label":"Patient ID"`) { + t.Fatalf("viewer state status=%d body=%s", viewer.StatusCode, viewer.Body) + } + store.mu.Lock() + broken := store.revisions[active.ID] + broken.PublicOutputContract = nil + store.revisions[active.ID] = broken + store.mu.Unlock() + withoutContract := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/default/authoring/v2/builder", "") + if withoutContract.StatusCode != http.StatusOK || !strings.Contains(withoutContract.Body, `"workspace"`) { + t.Fatalf("builder should hydrate valid intent without runtime contract: status=%d body=%s", withoutContract.StatusCode, withoutContract.Body) + } + store.mu.Lock() + broken = store.revisions[active.ID] + broken.AuthoringBundle = nil + store.revisions[active.ID] = broken + store.mu.Unlock() + missing := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/default/authoring/v2/builder", "") + if missing.StatusCode != http.StatusConflict || !strings.Contains(missing.Body, `"code":"AUTHORING_STATE_MISSING"`) { + t.Fatalf("missing active authoring state status=%d body=%s", missing.StatusCode, missing.Body) + } } func requestJSONWithHeaders(t *testing.T, app *fiber.App, method, path, body string, headers map[string]string) testHTTPResponse { diff --git a/internal/server/explorer_lifecycle_helpers.go b/internal/server/explorer_lifecycle_helpers.go new file mode 100644 index 00000000..85e0382c --- /dev/null +++ b/internal/server/explorer_lifecycle_helpers.go @@ -0,0 +1,65 @@ +package server + +import ( + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "net/url" + "strings" + + graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataframe/recipe/engine" + "github.com/calypr/loom/internal/dataset" +) + +func selectorsForBundle(bundle recipe.Bundle) []dataset.DataframeSelector { + selectors := make([]dataset.DataframeSelector, 0, len(bundle.Outputs)) + for _, output := range bundle.Outputs { + selectors = append(selectors, dataset.DataframeSelector{Recipe: bundle.Name, TranslationVersion: bundle.TranslationVersion, Output: output.Name}) + } + return selectors +} + +func verifyQueryableOutputs(bundle recipe.Bundle, execution graphresolver.RecipeExecution) error { + states := map[string]string{} + for _, output := range execution.Outputs { + states[output.Name] = strings.ToUpper(output.State) + } + for _, output := range bundle.Outputs { + state := states[output.Name] + if state != "PUBLISHED" && state != "READY" && state != "ACTIVE" { + return fmt.Errorf("output %q is not queryable (state %q)", output.Name, state) + } + } + return nil +} + +func mustBundleDigest(bundle recipe.Bundle) string { + digest, _ := bundle.Digest() + return digest +} + +func explorerURL(project, id string) string { + return "/api/v1/projects/" + url.PathEscape(project) + "/explorers/" + url.PathEscape(id) +} + +func resolvedOutputFingerprints(resolved engine.Resolved) map[string]string { + result := make(map[string]string, len(resolved.Compiled.Outputs)) + for _, output := range resolved.Compiled.Outputs { + payload, err := json.Marshal(struct { + Version int `json:"version"` + Name string `json:"name"` + Scope string `json:"scope"` + Generation string `json:"generation"` + Output any `json:"output"` + }{Version: 1, Name: output.Name, Scope: resolved.Semantic.ScopeDigest, Generation: resolved.Compiled.SourceGeneration, Output: output}) + if err != nil { + continue + } + sum := sha256.Sum256(payload) + result[output.Name] = hex.EncodeToString(sum[:]) + } + return result +} diff --git a/internal/server/explorer_lifecycle_types.go b/internal/server/explorer_lifecycle_types.go new file mode 100644 index 00000000..8be75728 --- /dev/null +++ b/internal/server/explorer_lifecycle_types.go @@ -0,0 +1,48 @@ +package server + +import ( + "context" + "log/slog" + + graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataframe/recipe/engine" + "github.com/calypr/loom/internal/dataset" + "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/explorer/authoringv2" +) + +type ExplorerV2Previewer func(context.Context, recipe.Bundle, recipe.RuntimeBindings) (map[string][]map[string]any, error) +type ExplorerV2Materializer = graphresolver.ExplorerBundleMaterializer + +type ExplorerV2ReceiptCompileRequest struct { + Project string + ExplorerID string + Workspace authoringv2.Workspace + SnapshotToken string + RequestID string + Authorized AuthorizedCapability +} + +type ExplorerV2ReceiptCompiler func(context.Context, ExplorerV2ReceiptCompileRequest) (*explorer.CompilationReceipt, error) +type ExplorerV2ReceiptReader func(context.Context, string, string, string) (*explorer.CompilationReceipt, error) +type ExplorerV2ReceiptPreviewer func(context.Context, *explorer.CompilationReceipt, recipe.RuntimeBindings, func(map[string]any) error) (engine.PreviewSummary, error) +type ExplorerV2ReceiptMaterializer func(context.Context, *explorer.CompilationReceipt, recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) +type ExplorerV2GenerationValidator func(context.Context, string, string) error +type ExplorerV2ReleaseActivator func(context.Context, string, string, []dataset.DataframeSelector) error + +type ExplorerV2LifecycleConfig struct { + CompileReceipt ExplorerV2ReceiptCompiler + Capability ExplorerCapabilityReader + CapabilityToken ExplorerCapabilityTokenReader + AuthorizedCapabilityCompile ExplorerAuthorizedCapabilityCompilationReader + AuthorizedCapabilityExecution ExplorerAuthorizedCapabilityExecutionReader + Preview ExplorerV2Previewer + PreviewReceipt ExplorerV2ReceiptPreviewer + Materialize ExplorerV2Materializer + MaterializeReceipt ExplorerV2ReceiptMaterializer + ReceiptLookup ExplorerV2ReceiptReader + Logger *slog.Logger + ValidateReleaseGeneration ExplorerV2GenerationValidator + ActivateRelease ExplorerV2ReleaseActivator +} diff --git a/internal/server/explorer_preview_response.go b/internal/server/explorer_preview_response.go index 56b00ee3..f690c6c1 100644 --- a/internal/server/explorer_preview_response.go +++ b/internal/server/explorer_preview_response.go @@ -78,7 +78,7 @@ type previewResponseTooLargeError struct { Limit int } -type v2EmissionWire = explorerv2api.Emission +type v2EmissionWire = explorerv2api.ContractColumn func v2EmissionColumns(columns []explorer.EmittedColumn) []v2EmissionWire { out := make([]v2EmissionWire, 0, len(columns)) @@ -88,10 +88,7 @@ func v2EmissionColumns(columns []explorer.EmittedColumn) []v2EmissionWire { label = column.PublicColumn } out = append(out, v2EmissionWire{ - OutputId: column.OutputID, CandidateId: column.CandidateID, - OccurrenceId: column.OccurrenceID, ProjectionMode: column.ProjectionMode, - EmissionId: column.EmissionID, PublicColumn: column.PublicColumn, - Label: label, LogicalType: column.LogicalType, + Column: column.PublicColumn, Label: label, LogicalType: column.LogicalType, Filterable: column.Filterable, Chartable: column.Chartable, }) } diff --git a/internal/server/explorer_preview_security.go b/internal/server/explorer_preview_security.go index 51103a91..9284aa9c 100644 --- a/internal/server/explorer_preview_security.go +++ b/internal/server/explorer_preview_security.go @@ -96,10 +96,10 @@ func validateReceiptOutputContract(receipt *explorer.CompilationReceipt, outputI return receiptExecutionContractError("requested output %q is not in the receipt recipe", outputID) } -// validateReceiptEnginePublicColumns compares the engine's authoritative -// ordered public projection schema with the receipt's ordered emitted-column -// contract. Internal identity/provenance projections are excluded from both -// the public contract and this comparison. +// validateReceiptEnginePublicColumns proves that the engine and receipt expose +// exactly the same public columns. Column order is deliberately not compared: +// the compiler owns execution order while the receipt's output contract owns +// presentation order. Internal identity/provenance projections are excluded. func validateReceiptEnginePublicColumns(receipt *explorer.CompilationReceipt, resolved engine.Resolved) error { if receipt == nil { return receiptExecutionContractError("receipt is required") @@ -120,7 +120,7 @@ func validateReceiptEnginePublicColumns(receipt *explorer.CompilationReceipt, re actual = append(actual, column.Name) } } - if !sameOrderedStrings(actual, want[output.Name]) { + if !sameUniqueStrings(actual, want[output.Name]) { return receiptExecutionContractError("engine public columns for output %q differ from receipt", output.Name) } } @@ -132,12 +132,24 @@ func validateReceiptEnginePublicColumns(receipt *explorer.CompilationReceipt, re return nil } -func sameOrderedStrings(left, right []string) bool { +func sameUniqueStrings(left, right []string) bool { if len(left) != len(right) { return false } - for index := range left { - if left[index] != right[index] { + values := make(map[string]struct{}, len(left)) + for _, value := range left { + if _, duplicate := values[value]; duplicate { + return false + } + values[value] = struct{}{} + } + seen := make(map[string]struct{}, len(right)) + for _, value := range right { + if _, duplicate := seen[value]; duplicate { + return false + } + seen[value] = struct{}{} + if _, ok := values[value]; !ok { return false } } diff --git a/internal/server/explorer_preview_security_test.go b/internal/server/explorer_preview_security_test.go index 13cab928..059e5c71 100644 --- a/internal/server/explorer_preview_security_test.go +++ b/internal/server/explorer_preview_security_test.go @@ -97,7 +97,7 @@ func TestValidateReceiptOutputContract(t *testing.T) { } } -func TestValidateReceiptEnginePublicColumnsUsesOrderedPublicColumnsOnly(t *testing.T) { +func TestValidateReceiptEnginePublicColumnsUsesExactPublicColumnSet(t *testing.T) { snapshot := testAuthorizedCapabilitySnapshot(t, "generation-a", authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}) receipt := testSecurityReceipt(t, snapshot, "patients", []string{"id", "name"}) resolved := engine.Resolved{Compiled: lower.CompiledRecipe{Outputs: []lower.CompiledRecipeOutput{{Name: "patients", OutputSchema: []lower.CompiledOutputColumn{{Name: "id"}, {Name: "__loom_row_id", Internal: true}, {Name: "name"}}}}}} @@ -107,8 +107,8 @@ func TestValidateReceiptEnginePublicColumnsUsesOrderedPublicColumnsOnly(t *testi wrongOrder := *receipt wrongOrder.EmittedColumns = append([]explorer.EmittedColumn(nil), receipt.EmittedColumns...) wrongOrder.EmittedColumns[0], wrongOrder.EmittedColumns[1] = wrongOrder.EmittedColumns[1], wrongOrder.EmittedColumns[0] - if err := validateReceiptEnginePublicColumns(&wrongOrder, resolved); !errors.Is(err, ErrReceiptExecutionContract) { - t.Fatalf("wrong column order error=%v, want contract mismatch", err) + if err := validateReceiptEnginePublicColumns(&wrongOrder, resolved); err != nil { + t.Fatalf("presentation order must not change execution compatibility: %v", err) } hidden := *receipt hidden.EmittedColumns = append([]explorer.EmittedColumn(nil), receipt.EmittedColumns...) @@ -116,6 +116,17 @@ func TestValidateReceiptEnginePublicColumnsUsesOrderedPublicColumnsOnly(t *testi if err := validateReceiptEnginePublicColumns(&hidden, resolved); !errors.Is(err, ErrReceiptExecutionContract) { t.Fatalf("hidden-column error=%v, want contract mismatch", err) } + duplicate := *receipt + duplicate.EmittedColumns = append([]explorer.EmittedColumn(nil), receipt.EmittedColumns...) + duplicate.EmittedColumns[1].PublicColumn = "id" + if err := validateReceiptEnginePublicColumns(&duplicate, resolved); !errors.Is(err, ErrReceiptExecutionContract) { + t.Fatalf("duplicate-column error=%v, want contract mismatch", err) + } + extra := *receipt + extra.EmittedColumns = append(append([]explorer.EmittedColumn(nil), receipt.EmittedColumns...), explorer.EmittedColumn{OutputID: "patients", PublicColumn: "extra"}) + if err := validateReceiptEnginePublicColumns(&extra, resolved); !errors.Is(err, ErrReceiptExecutionContract) { + t.Fatalf("extra-column error=%v, want contract mismatch", err) + } } func testSecurityReceipt(t *testing.T, snapshot capability.Snapshot, output string, columns []string) *explorer.CompilationReceipt { @@ -126,7 +137,7 @@ func testSecurityReceipt(t *testing.T, snapshot capability.Snapshot, output stri for _, column := range columns { fields = append(fields, recipe.Field{Name: column, Expr: recipe.Expression{Select: "root." + column}}) emitted = append(emitted, explorer.EmittedColumn{EmissionID: "em_" + column, OutputID: output, CandidateID: "c_" + column, OccurrenceID: "base", ProjectionMode: "VALUE", PublicColumn: column, Label: column, LogicalType: "string"}) - contractColumns = append(contractColumns, explorer.PublicOutputColumn{EmissionID: "em_" + column, PublicColumn: column, CandidateID: "c_" + column, OccurrenceID: "base", ProjectionMode: "VALUE", Label: column, LogicalType: "string"}) + contractColumns = append(contractColumns, explorer.PublicOutputColumn{Column: column, Label: column, LogicalType: "string"}) } bundle := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "security", TranslationVersion: "test", Outputs: []recipe.Output{{Name: output, RootResourceType: "Patient", RowGrain: "resource", Fields: fields}}} contract, err := json.Marshal(explorer.PublicOutputContracts{Outputs: []explorer.PublicOutputContract{{OutputID: output, Columns: contractColumns}}}) diff --git a/internal/server/explorer_receipt_contract.go b/internal/server/explorer_receipt_contract.go index 4c14a612..49371d0e 100644 --- a/internal/server/explorer_receipt_contract.go +++ b/internal/server/explorer_receipt_contract.go @@ -2,8 +2,6 @@ package server import ( "context" - "crypto/sha256" - "encoding/hex" "encoding/json" "fmt" "sort" @@ -18,48 +16,6 @@ import ( "github.com/calypr/loom/internal/projectid" ) -func compiledExplorerConfigV2(project, explorerID string, compiled explorercompilation.Result) ([]byte, error) { - if len(compiled.EmittedColumns) == 0 { - // An empty selection is a valid mutable editor state and may receive a - // receipt, but there is no valid interactive ExplorerConfig until the user - // selects a public column. Publication rejects this state explicitly. - return nil, nil - } - recipeJSON, err := json.Marshal(compiled.Bundle) - if err != nil { - return nil, fmt.Errorf("marshal compiled recipe: %w", err) - } - columns := append([]explorercompilation.PresentationColumn(nil), compiled.Presentation.Columns...) - sort.SliceStable(columns, func(i, j int) bool { - if columns[i].Order != columns[j].Order { - return columns[i].Order < columns[j].Order - } - return columns[i].EmissionID < columns[j].EmissionID - }) - table := make([]explorer.ConfigColumn, 0, len(columns)) - for _, column := range columns { - table = append(table, explorer.ConfigColumn{Column: column.PublicColumn, Label: column.Label, Visible: column.Visible}) - } - sum := sha256.Sum256([]byte(compiled.Presentation.OutputID)) - viewID := "view-" + hex.EncodeToString(sum[:])[:12] - config := explorer.ConfigV2{ - APIVersion: explorer.ConfigV2APIVersion, - Kind: "ExplorerConfig", - Project: projectid.Canonical(project), - Explorer: explorer.ConfigExplorer{ - ID: explorerID, Title: compiled.Presentation.Title, - Management: explorer.ConfigManagementForID(explorerID), - }, - Recipe: recipeJSON, - Views: []explorer.ConfigView{{ - ID: viewID, Title: compiled.Presentation.Title, - Output: compiled.Presentation.OutputID, - Table: explorer.ConfigTable{Columns: table}, - }}, - } - return json.Marshal(config) -} - func compiledExplorerWorkspaceConfigV2(project, explorerID string, compiled explorercompilation.WorkspaceResult) ([]byte, error) { if len(compiled.EmittedColumns) == 0 { return nil, nil @@ -90,9 +46,17 @@ func compiledExplorerWorkspaceConfigV2(project, explorerID string, compiled expl } return columns[i].EmissionID < columns[j].EmissionID }) + document, found := semanticWorkspaceDocument(compiled.Workspace, tab.OutputID) view := explorer.ConfigView{ID: tab.ID, Title: tab.Title, Output: tab.OutputID, Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{}}} + if found { + view.RowLabel = document.Output.RowLabel + } for _, column := range columns { - view.Table.Columns = append(view.Table.Columns, explorer.ConfigColumn{Column: column.PublicColumn, Label: column.Label, Visible: column.Visible, Pinned: column.Pinned}) + cellRenderer := "" + if authored, ok := semanticWorkspaceColumn(document, column.PublicColumn); ok && authored.Table != nil { + cellRenderer = authored.Table.CellRenderer + } + view.Table.Columns = append(view.Table.Columns, explorer.ConfigColumn{Column: column.PublicColumn, Label: column.Label, Visible: column.Visible, Pinned: column.Pinned, CellRenderer: cellRenderer}) if column.FilterLabel != "" { view.Filters = append(view.Filters, explorer.ConfigFilter{Column: column.PublicColumn, Label: column.FilterLabel}) } @@ -100,16 +64,75 @@ func compiledExplorerWorkspaceConfigV2(project, explorerID string, compiled expl view.Charts = append(view.Charts, explorer.ConfigChart{Column: column.PublicColumn, Type: column.ChartType, Title: column.ChartTitle}) } } + if found { + for _, fixed := range document.FixedFilters { + if view.FixedFilters == nil { + view.FixedFilters = map[string][]string{} + } + view.FixedFilters[fixed.Column] = append([]string(nil), fixed.Values...) + } + for _, action := range document.Actions { + compiledAction := explorer.ConfigAction{Type: action.Type, Title: action.Title, FileName: action.FileName, Output: document.Output.ID} + for _, binding := range action.Columns { + compiledAction.Columns = append(compiledAction.Columns, binding.Column) + if binding.ExportHeader != "" { + if compiledAction.ExportHeaders == nil { + compiledAction.ExportHeaders = map[string]string{} + } + compiledAction.ExportHeaders[binding.Column] = binding.ExportHeader + } + } + view.Actions = append(view.Actions, compiledAction) + } + } views = append(views, view) } - title := explorerID + title := firstNonEmptyWorkspaceTitle(compiled.Workspace.Explorer.Title, explorerID) if len(tabs) > 0 { - title = tabs[0].Title + title = firstNonEmptyWorkspaceTitle(compiled.Workspace.Explorer.Title, tabs[0].Title, explorerID) } - config := explorer.ConfigV2{APIVersion: explorer.ConfigV2APIVersion, Kind: "ExplorerConfig", Project: projectid.Canonical(project), Explorer: explorer.ConfigExplorer{ID: explorerID, Title: title, Management: explorer.ConfigManagementForID(explorerID)}, Recipe: recipeJSON, Views: views} + shared := map[string][]explorer.SharedFilter{} + for name, bindings := range compiled.Workspace.SharedFilters { + for _, binding := range bindings { + shared[name] = append(shared[name], explorer.SharedFilter{Output: binding.OutputID, Column: binding.Column}) + } + } + fileActions := explorer.FileActions{} + if compiled.Workspace.FileActions != nil { + fileActions.Extensions = compiled.Workspace.FileActions.Extensions + fileActions.Actions = compiled.Workspace.FileActions.Actions + } + config := explorer.ConfigV2{APIVersion: explorer.ConfigV2APIVersion, Kind: "ExplorerConfig", Project: projectid.Canonical(project), Explorer: explorer.ConfigExplorer{ID: explorerID, Title: title, Description: compiled.Workspace.Explorer.Description, Management: explorer.ConfigManagementForID(explorerID)}, Recipe: recipeJSON, Views: views, SharedFilters: shared, FileActions: fileActions} return json.Marshal(config) } +func semanticWorkspaceDocument(workspace authoringv2.Workspace, outputID string) (authoringv2.Document, bool) { + for _, document := range workspace.Documents { + if document.Output.ID == outputID { + return document, true + } + } + return authoringv2.Document{}, false +} + +func semanticWorkspaceColumn(document authoringv2.Document, column string) (authoringv2.Column, bool) { + for _, authored := range document.Columns { + if authored.Column == column { + return authored, true + } + } + return authoringv2.Column{}, false +} + +func firstNonEmptyWorkspaceTitle(values ...string) string { + for _, value := range values { + if strings.TrimSpace(value) != "" { + return value + } + } + return "Explorer" +} + func validateReceiptCapability(receipt *explorer.CompilationReceipt, snapshot capability.Snapshot) error { if receipt == nil { return fmt.Errorf("compilation receipt is required") diff --git a/internal/server/explorer_receipt_contract_test.go b/internal/server/explorer_receipt_contract_test.go index 5391883b..ae76b7d0 100644 --- a/internal/server/explorer_receipt_contract_test.go +++ b/internal/server/explorer_receipt_contract_test.go @@ -18,26 +18,6 @@ import ( "github.com/gofiber/fiber/v3" ) -func TestCompiledExplorerConfigV2UsesCompilerOwnedPresentation(t *testing.T) { - bundle := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "compiled", TranslationVersion: explorercompilation.TranslationVersion, Outputs: []recipe.Output{{Name: "patients", RootResourceType: "Patient", RowGrain: "patient", Fields: []recipe.Field{{Name: "c_one", Expr: recipe.Expression{Select: "root.id"}}}}}} - compiled := explorercompilation.Result{ - Bundle: bundle, - EmittedColumns: []explorercompilation.EmittedColumn{{EmissionID: "em_one", OutputID: "patients", PublicColumn: "c_one"}}, - Presentation: explorercompilation.PresentationConfig{OutputID: "patients", Title: "Patients", Columns: []explorercompilation.PresentationColumn{{EmissionID: "em_one", PublicColumn: "c_one", Label: "Patient ID", Visible: true}}}, - } - raw, err := compiledExplorerConfigV2("project-a", "custom", compiled) - if err != nil { - t.Fatal(err) - } - config, decoded, err := explorer.DecodeInteractiveConfigV2(raw, "project-a", "custom") - if err != nil { - t.Fatal(err) - } - if decoded.Name != bundle.Name || len(config.Views) != 1 || config.Views[0].Table.Columns[0].Label != "Patient ID" { - t.Fatalf("compiled config = %#v, recipe = %#v", config, decoded) - } -} - func TestCompileValidatedReceiptResolutionChecksAllOutputsForScopedPreview(t *testing.T) { recipeEngine, err := engine.New(engine.Config{ Registry: compilerTestRegistry{}, @@ -53,7 +33,10 @@ func TestCompileValidatedReceiptResolutionChecksAllOutputsForScopedPreview(t *te Name: "multi-output-preview", TranslationVersion: explorercompilation.TranslationVersion, Outputs: []recipe.Output{ - {Name: "patients", RootResourceType: "Patient", RowGrain: "patient", Fields: []recipe.Field{{Name: "patient_id", Expr: recipe.Expression{Select: "root.id"}}}}, + {Name: "patients", RootResourceType: "Patient", RowGrain: "patient", Fields: []recipe.Field{ + {Name: "patient_id", Expr: recipe.Expression{Select: "root.id"}}, + {Name: "patient_gender", Expr: recipe.Expression{Select: "root.gender"}}, + }}, {Name: "specimens", RootResourceType: "Specimen", RowGrain: "resource", Fields: []recipe.Field{{Name: "specimen_id", Expr: recipe.Expression{Select: "root.id"}}}}, }, } @@ -73,6 +56,9 @@ func TestCompileValidatedReceiptResolutionChecksAllOutputsForScopedPreview(t *te ResolvedSchemaDigest: compiled.ResolvedSchemaDigest, OutputFingerprints: resolvedOutputFingerprints(compiled), EmittedColumns: []explorer.EmittedColumn{ + // Presentation order is intentionally different from compiler field + // order. It must not invalidate an otherwise identical receipt. + {OutputID: "patients", PublicColumn: "patient_gender"}, {OutputID: "patients", PublicColumn: "patient_id"}, {OutputID: "specimens", PublicColumn: "specimen_id"}, }, @@ -95,8 +81,7 @@ func TestNativeV2RouteUsesAuthorizedPersistedReceipt(t *testing.T) { snapshot := testAuthoringV2CapabilitySnapshot() scope := authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted} executionScope := scope - store := explorer.NewMemoryStore() - service, err := explorer.NewService(store) + service, err := explorer.NewService(newTestExplorerStore()) if err != nil { t.Fatal(err) } @@ -138,11 +123,18 @@ func TestNativeV2RouteUsesAuthorizedPersistedReceipt(t *testing.T) { } app := fiber.New() RegisterExplorerAuthoringV2Routes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, config) - body := `{"workspace":{"apiVersion":"` + authoringv2.APIVersion + `","kind":"` + authoringv2.WorkspaceKind + `","documents":[{"kind":"` + authoringv2.Kind + `","output":{"id":"patients","title":"Patients"},"rootNodeId":"n_patient","routeSteps":[],"selections":[{"candidateId":"c_patient_id","occurrenceId":"base","projectionMode":"FIRST"}],"presentation":{}}],"tabs":[{"id":"patients-tab","title":"Patients","outputId":"patients","order":0,"visible":true}]},"snapshotToken":"` + snapshot.Token + `"}` + body := `{"workspace":` + string(baselineExplorerWorkspaceV2()) + `,"snapshotToken":"` + snapshot.Token + `"}` compiled := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/compile", body) if compiled.StatusCode != http.StatusOK { t.Fatalf("compile status=%d body=%s", compiled.StatusCode, compiled.Body) } + ownerAfterCompile, err := service.Get(context.Background(), "project-a", "custom") + if err != nil { + t.Fatal(err) + } + if ownerAfterCompile.ActiveRevisionID != "" || len(ownerAfterCompile.DraftConfig) != 0 { + t.Fatalf("compile mutated active or draft state: %#v", ownerAfterCompile) + } var result struct { ReceiptID string `json:"receiptId"` } @@ -153,6 +145,13 @@ func TestNativeV2RouteUsesAuthorizedPersistedReceipt(t *testing.T) { if preview.StatusCode != http.StatusOK { t.Fatalf("preview status=%d body=%s", preview.StatusCode, preview.Body) } + ownerAfterPreview, err := service.Get(context.Background(), "project-a", "custom") + if err != nil { + t.Fatal(err) + } + if ownerAfterPreview.ActiveRevisionID != "" || len(ownerAfterPreview.DraftConfig) != 0 { + t.Fatalf("preview mutated active or draft state: %#v", ownerAfterPreview) + } if compileCalls != 1 || previewCalls != 1 { t.Fatalf("compile calls=%d preview calls=%d", compileCalls, previewCalls) } @@ -174,52 +173,11 @@ func TestNativeV2RouteUsesAuthorizedPersistedReceipt(t *testing.T) { if widened.StatusCode != http.StatusConflict || !strings.Contains(widened.Body, `"code":"RECEIPT_STALE"`) || previewCalls != 1 { t.Fatalf("scope mismatch status=%d calls=%d body=%s", widened.StatusCode, previewCalls, widened.Body) } - stats, err := service.CompilationReceiptStats(context.Background(), "project-a") - if err != nil || stats.Count != 1 { - t.Fatalf("receipt stats=%+v err=%v", stats, err) - } -} - -func TestBuilderReadRestoresPublishedNativeV2Document(t *testing.T) { - snapshot := testAuthoringV2CapabilitySnapshot() - store := explorer.NewMemoryStore() - service, err := explorer.NewService(store) - if err != nil { - t.Fatal(err) - } - if _, err := service.CreateEmptyInteractive(context.Background(), "project-a", "custom", "Custom", "test"); err != nil { - t.Fatal(err) - } - document := authoringv2.Document{APIVersion: authoringv2.APIVersion, Kind: authoringv2.Kind, Output: authoringv2.Output{ID: "patients", Title: "Patients"}, RootNodeID: "n_patient", RouteSteps: []authoringv2.RouteStep{}, Selections: []authoringv2.Selection{{CandidateID: "c_patient_id", OccurrenceID: authoringv2.RootOccurrenceID, ProjectionMode: "FIRST"}}, Presentation: map[string]authoringv2.Presentation{}} - receipt, err := persistTestNativeReceipt(context.Background(), t, service, ExplorerV2ReceiptCompileRequest{Project: "project-a", ExplorerID: "custom", Document: document, SnapshotToken: snapshot.Token}, snapshot) - if err != nil { - t.Fatal(err) - } - now := time.Now().UTC() - if _, err := service.PublishAuthoring(context.Background(), *receipt, explorer.Revision{ID: "native-v2-revision", Project: "project-a", ExplorerID: "custom", CompilationReceiptID: receipt.ID, IntentDigest: receipt.IntentDigest, AuthoringBundle: receipt.NormalizedBundle, Recipe: receipt.Bundle, RecipeDigest: receipt.RecipeDigest, ResolvedSchemaDigest: receipt.ResolvedSchemaDigest, SourceGeneration: receipt.SourceGeneration, Status: explorer.RevisionReady, CreatedAt: now}); err != nil { - t.Fatal(err) - } - app := fiber.New() - RegisterExplorerAuthoringV2Routes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{Capability: func(context.Context, string, string, string) (capability.Snapshot, error) { return snapshot, nil }}) - response := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom/authoring/v2/builder", "") - if response.StatusCode != http.StatusOK { - t.Fatalf("builder status=%d body=%s", response.StatusCode, response.Body) - } - var state authoringv2.BuilderState - if err := json.Unmarshal([]byte(response.Body), &state); err != nil { - t.Fatal(err) - } - if state.Workspace == nil || len(state.Workspace.Documents) != 1 || state.Workspace.Documents[0].Output.ID != document.Output.ID || state.Workspace.Documents[0].Selections[0].CandidateID != document.Selections[0].CandidateID { - t.Fatalf("restored workspace = %#v", state.Workspace) - } } func persistTestNativeReceipt(ctx context.Context, t *testing.T, service *explorer.Service, request ExplorerV2ReceiptCompileRequest, snapshot capability.Snapshot) (*explorer.CompilationReceipt, error) { t.Helper() workspace := request.Workspace - if workspace.APIVersion == "" { - workspace = authoringv2.Workspace{APIVersion: authoringv2.APIVersion, Kind: authoringv2.WorkspaceKind, Documents: []authoringv2.Document{request.Document}, Tabs: []authoringv2.Tab{{ID: "patients-tab", Title: request.Document.Output.Title, OutputID: request.Document.Output.ID, Order: 0, Visible: true}}} - } normalized, err := workspace.CanonicalJSON() if err != nil { return nil, err @@ -233,7 +191,7 @@ func persistTestNativeReceipt(ctx context.Context, t *testing.T, service *explor if err != nil { return nil, err } - contract := json.RawMessage(`{"outputs":[{"outputId":"patients","columns":[{"emissionId":"em_patient","publicColumn":"c_patient","candidateId":"c_patient_id","occurrenceId":"base","projectionMode":"FIRST","label":"Patient ID","logicalType":"string","filterable":true,"chartable":true}]}]}`) + contract := json.RawMessage(`{"outputs":[{"outputId":"patients","columns":[{"column":"c_patient","label":"Patient ID","logicalType":"string","filterable":true,"chartable":true}]}]}`) contractDigest, err := explorer.CompilationArtifactDigest(contract) if err != nil { return nil, err @@ -244,7 +202,7 @@ func persistTestNativeReceipt(ctx context.Context, t *testing.T, service *explor AuthorizationScopeDigest: snapshot.Identity.AuthorizationScopeDigest, CapabilitySchemaDigest: snapshot.Identity.SchemaDigest, SourceGeneration: snapshot.Identity.Generation, RecipeDigest: bundleDigest, ResolvedRecipeDigest: bundleDigest, ResolvedSchemaDigest: "resolved-schema", OutputContractDigest: contractDigest, - NormalizedBundle: normalized, Bundle: bundle, PublicOutputContract: contract, + NormalizedBundle: normalized, Bundle: bundle, CompiledConfig: json.RawMessage(`{}`), PublicOutputContract: contract, EmittedColumns: []explorer.EmittedColumn{{EmissionID: "em_patient", OutputID: "patients", CandidateID: "c_patient_id", OccurrenceID: authoringv2.RootOccurrenceID, ProjectionMode: "FIRST", PublicColumn: "c_patient", Label: "Patient ID", LogicalType: "string", Filterable: true, Chartable: true}}, OutputFingerprints: map[string]string{"patients": "fingerprint"}, CreatedAt: time.Now().UTC(), } diff --git a/internal/server/explorer_state_route_test.go b/internal/server/explorer_state_route_test.go new file mode 100644 index 00000000..a0ebbe05 --- /dev/null +++ b/internal/server/explorer_state_route_test.go @@ -0,0 +1,169 @@ +package server + +import ( + "context" + "encoding/json" + "net/http" + "testing" + + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/dataframe/publication" + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/dataset" + "github.com/calypr/loom/internal/explorer" + "github.com/gofiber/fiber/v3" +) + +func TestExplorerStateRouteBuildsDefaultProjectionFromRecipe(t *testing.T) { + store := newTestExplorerStore() + service, err := explorer.NewService(store) + if err != nil { + t.Fatal(err) + } + if _, err := service.CreateEmptyInteractive(context.Background(), "project-a", "patients", "Patients", "test"); err != nil { + t.Fatal(err) + } + selector := dataset.DataframeSelector{Recipe: "patients-query", TranslationVersion: "v1", Output: "patients"} + revision := explorer.Revision{ + ID: "revision-a", + Project: "project-a", + ExplorerID: "patients", + Recipe: recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: selector.Recipe, TranslationVersion: selector.TranslationVersion, Outputs: []recipe.Output{{Name: "patients", RootResourceType: "Patient", RowGrain: "patient", Fields: []recipe.Field{{Name: "patient_id", FieldRef: "Patient.id"}}}}}, + SourceGeneration: "generation-a", + Dataset: explorer.DatasetMetadata{Generation: "generation-a", Outputs: []explorer.DatasetOutput{{ + Name: "patients", State: "ACTIVE", Queryable: true, Selector: &selector, + Columns: []publication.PhysicalColumn{{Name: "patient_id", LogicalType: "string", ClickHouse: "String"}}, + }}}, + EmittedColumns: []explorer.EmittedColumn{{OutputID: "patients", EmissionID: "em_patient_id", PublicColumn: "patient_id", Label: "Patient ID", LogicalType: "string"}}, + PublicOutputContract: json.RawMessage(`{"outputs":[{"outputId":"patients","columns":[{"column":"patient_id","label":"Patient ID","logicalType":"string","filterable":false,"chartable":false}]}]}`), + Publication: explorer.PublicationMetadata{State: "ACTIVE", Generation: "generation-a"}, + Status: explorer.RevisionActive, + } + store.mu.Lock() + store.revisions[revision.ID] = revision + owner := store.explorers[testExplorerKey("project-a", "patients")] + owner.ActiveRevisionID = revision.ID + store.explorers[testExplorerKey("project-a", "patients")] = owner + store.mu.Unlock() + + app := fiber.New() + RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{}) + response := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/patients", "") + if response.StatusCode != http.StatusOK { + t.Fatalf("status=%d body=%s", response.StatusCode, response.Body) + } + var state explorer.ExplorerStateV1 + if err := json.Unmarshal([]byte(response.Body), &state); err != nil { + t.Fatal(err) + } + if state.APIVersion != explorer.ExplorerStateV1APIVersion || state.Kind != explorer.ExplorerStateV1Kind { + t.Fatalf("state identity = %q/%q", state.APIVersion, state.Kind) + } + if state.Runtime == nil { + t.Fatalf("runtime projection is nil: %s", response.Body) + } + if state.Runtime.Status != "ACTIVE" || len(state.Runtime.Outputs) != 1 { + t.Fatalf("runtime = %#v", state.Runtime) + } + output := state.Runtime.Outputs[0] + if output.OutputID != "patients" || output.Selector != selector || len(output.Columns) != 1 || output.Columns[0].Column != "patient_id" { + t.Fatalf("default output = %#v", output) + } + if !output.Columns[0].Visible || len(output.Table.Columns) != 1 || len(output.Filters) != 0 || len(output.Charts) != 0 { + t.Fatalf("default presentation = %#v", output) + } +} + +func TestViewerProjectionDoesNotInventColumnsWithoutPublishedSchema(t *testing.T) { + service, err := explorer.NewService(newTestExplorerStore()) + if err != nil { + t.Fatal(err) + } + selector := dataset.DataframeSelector{Recipe: "patients-query", TranslationVersion: "v1", Output: "patients"} + revision := explorer.Revision{ + Recipe: recipe.Bundle{ + RecipeSchemaVersion: recipe.CurrentSchemaVersion, + Name: selector.Recipe, + TranslationVersion: selector.TranslationVersion, + Outputs: []recipe.Output{{Name: "patients", RootResourceType: "Patient", RowGrain: "patient"}}, + }, + Dataset: explorer.DatasetMetadata{Outputs: []explorer.DatasetOutput{{Name: "patients", Selector: &selector}}}, + EmittedColumns: []explorer.EmittedColumn{{ + OutputID: "patients", EmissionID: "em_patient_id", PublicColumn: "patient_id", Label: "Patient ID", LogicalType: "string", + }}, + } + + runtime := service.BuildViewerProjection(&revision) + if runtime == nil || len(runtime.Outputs) != 1 { + t.Fatalf("runtime = %#v", runtime) + } + output := runtime.Outputs[0] + if len(output.Columns) != 0 { + t.Fatalf("invented columns = %#v", output.Columns) + } +} + +func TestViewerProjectionRejectsAliasedPhysicalColumns(t *testing.T) { + service, err := explorer.NewService(newTestExplorerStore()) + if err != nil { + t.Fatal(err) + } + selector := dataset.DataframeSelector{Recipe: "patients-query", TranslationVersion: "v1", Output: "patients"} + revision := explorer.Revision{ + Recipe: recipe.Bundle{ + RecipeSchemaVersion: recipe.CurrentSchemaVersion, + Name: selector.Recipe, + TranslationVersion: selector.TranslationVersion, + Outputs: []recipe.Output{{ + Name: "patients", RootResourceType: "Patient", RowGrain: "patient", + Fields: []recipe.Field{{Name: "patient_id", FieldRef: "Patient.id"}}, + }}, + }, + Dataset: explorer.DatasetMetadata{Outputs: []explorer.DatasetOutput{{ + Name: "patients", Selector: &selector, + Columns: []publication.PhysicalColumn{{Name: "route_0__patient_id", LogicalType: "string", ClickHouse: "String"}}, + }}}, + EmittedColumns: []explorer.EmittedColumn{{ + OutputID: "patients", EmissionID: "em_patient_id", PublicColumn: "patient_id", Label: "Patient ID", LogicalType: "string", + }}, + } + + runtime := service.BuildViewerProjection(&revision) + if runtime == nil || len(runtime.Outputs) != 1 { + t.Fatalf("runtime = %#v", runtime) + } + if len(runtime.Outputs[0].Columns) != 0 { + t.Fatalf("aliased columns leaked = %#v", runtime.Outputs[0].Columns) + } +} + +func TestExplorerStateRouteReturnsExplicitUnpublishedProjection(t *testing.T) { + service, err := explorer.NewService(newTestExplorerStore()) + if err != nil { + t.Fatal(err) + } + if _, err := service.CreateEmptyInteractive(context.Background(), "project-a", "empty", "Empty", "test"); err != nil { + t.Fatal(err) + } + + app := fiber.New() + RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{}) + response := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/empty", "") + if response.StatusCode != http.StatusOK { + t.Fatalf("status=%d body=%s", response.StatusCode, response.Body) + } + var wire map[string]json.RawMessage + if err := json.Unmarshal([]byte(response.Body), &wire); err != nil { + t.Fatal(err) + } + if raw, ok := wire["runtime"]; !ok || string(raw) != "null" { + t.Fatalf("runtime = %s, want explicit null", raw) + } + var state explorer.ExplorerStateV1 + if err := json.Unmarshal([]byte(response.Body), &state); err != nil { + t.Fatal(err) + } + if state.Runtime != nil || state.Generated.Publication.State != explorer.ExplorerRuntimeV1NotPublished { + t.Fatalf("unpublished state = %#v", state) + } +} diff --git a/internal/server/explorer_v2_engine.go b/internal/server/explorer_v2_engine.go deleted file mode 100644 index 5fc0366e..00000000 --- a/internal/server/explorer_v2_engine.go +++ /dev/null @@ -1,147 +0,0 @@ -package server - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "encoding/json" - "fmt" - "strings" - - "github.com/calypr/loom/internal/dataframe/compiler/lower" - "github.com/calypr/loom/internal/dataframe/recipe" - "github.com/calypr/loom/internal/dataframe/recipe/engine" - "github.com/calypr/loom/internal/explorer" - "github.com/calypr/loom/internal/projectid" -) - -type explorerV2CatalogReader func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) - -func explorerV2Compiler(recipeEngine *engine.Engine, catalogReader explorerV2CatalogReader) ExplorerV2Compiler { - return func(ctx context.Context, request ExplorerV2CompileRequest) (ExplorerV2CompileResult, error) { - cfg, bundle, canonical, digest, err := explorer.CanonicalConfigV2(request.Config, request.Project, request.ExplorerID, explorer.ConfigManagementForID(request.ExplorerID)) - if err != nil { - return ExplorerV2CompileResult{}, err - } - var sourceGeneration string - // Every request that reaches the production recipe engine must resolve - // against the active dataset generation. An absent catalog capability is - // a wiring failure, never permission to fall back to the null-generation - // namespace. - if catalogReader != nil { - snapshot, err := catalogReader(ctx, request.Project, request.ExplorerID, "") - if err != nil { - return ExplorerV2CompileResult{}, err - } - if strings.TrimSpace(snapshot.Generation) == "" { - return ExplorerV2CompileResult{}, fmt.Errorf("active dataset generation is unavailable") - } - sourceGeneration = snapshot.Generation - if request.SnapshotToken != "" || len(request.SelectedCandidateIDsByNode) > 0 { - if err := snapshot.ValidateToken(request.SnapshotToken); err != nil { - return ExplorerV2CompileResult{}, err - } - } - for nodeID, candidateIDs := range request.SelectedCandidateIDsByNode { - lookupNodeID := nodeID - if nodeID == "root" { - for _, output := range bundle.Outputs { - if output.Name == request.Output { - lookupNodeID = explorer.OpaqueID("n_", output.RootResourceType) - break - } - } - } - if _, ok := catalogNodeForREST(snapshot.Catalog, lookupNodeID); !ok { - return ExplorerV2CompileResult{}, fmt.Errorf("unresolved catalog node %q", nodeID) - } - for _, candidateID := range candidateIDs { - selection, ok := catalogSelectionForREST(snapshot.Catalog, candidateID) - if !ok { - return ExplorerV2CompileResult{}, fmt.Errorf("catalog candidate %q is absent from the current snapshot for node %q", candidateID, nodeID) - } - if selection.NodeID != lookupNodeID { - return ExplorerV2CompileResult{}, fmt.Errorf("catalog candidate %q belongs to node %q, not requested node %q (resolved as %q)", candidateID, selection.NodeID, nodeID, lookupNodeID) - } - } - } - } else { - return ExplorerV2CompileResult{}, fmt.Errorf("catalog discovery is not configured") - } - if recipeEngine == nil { - return ExplorerV2CompileResult{Config: canonical, Bundle: bundle, RecipeDigest: digest, SourceGeneration: sourceGeneration}, nil - } - resolved, err := recipeEngine.ResolveBundle(ctx, bundle, recipe.RuntimeBindings{Project: projectid.Legacy(request.Project), DatasetGeneration: sourceGeneration}) - if err != nil { - return ExplorerV2CompileResult{}, err - } - emitted := make([]explorer.EmittedColumn, 0) - for _, output := range resolved.Compiled.Outputs { - for _, column := range output.OutputSchema { - if column.Internal { - continue - } - emitted = append(emitted, explorer.EmittedColumn{OutputID: output.Name, PublicColumn: column.Name, SelectionID: column.SemanticPath, LogicalType: column.Kind, Filterable: true, Chartable: true}) - } - } - cfg, presentationDiagnostics, err := synchronizeExplorerV2Views(cfg, resolved.Compiled.Outputs) - if err != nil { - return ExplorerV2CompileResult{}, err - } - repairedConfig, err := json.Marshal(cfg) - if err != nil { - return ExplorerV2CompileResult{}, fmt.Errorf("marshal repaired ExplorerConfigV2: %w", err) - } - return ExplorerV2CompileResult{Config: repairedConfig, Bundle: bundle, RecipeDigest: resolved.StoredRecipeDigest, ResolvedSchemaDigest: resolved.ResolvedSchemaDigest, SourceGeneration: resolved.Compiled.SourceGeneration, OutputFingerprints: resolvedOutputFingerprints(resolved), EmittedColumns: emitted, Diagnostics: presentationDiagnostics}, nil - } -} - -// resolvedOutputFingerprints are intentionally output-scoped. A bundle-level -// schema digest changes when any output changes, which would defeat reuse of -// the other tables. The lowered physical plan captures catalog resolution, -// discovered columns, filters, and row shape for only this output. -func resolvedOutputFingerprints(resolved engine.Resolved) map[string]string { - result := make(map[string]string, len(resolved.Compiled.Outputs)) - for _, output := range resolved.Compiled.Outputs { - payload, err := json.Marshal(struct { - Version int `json:"version"` - Name string `json:"name"` - Scope string `json:"scope"` - Generation string `json:"generation"` - Output any `json:"output"` - }{Version: 1, Name: output.Name, Scope: resolved.Semantic.ScopeDigest, Generation: resolved.Compiled.SourceGeneration, Output: output}) - if err != nil { - continue - } - sum := sha256.Sum256(payload) - result[output.Name] = hex.EncodeToString(sum[:]) - } - return result -} - -// The explorer package intentionally keeps Catalog's internal lookup methods -// private. These tiny adapters keep REST wiring from exposing catalog fields. -func catalogNodeForREST(c explorer.Catalog, id string) (explorer.CatalogNode, bool) { - for _, node := range c.Nodes { - if node.ID == id { - return node, true - } - } - return explorer.CatalogNode{}, false -} -func catalogSelectionForREST(c explorer.Catalog, id string) (explorer.CatalogSelection, bool) { - value, ok := c.Selections[id] - return value, ok -} - -func synchronizeExplorerV2Views(cfg explorer.ConfigV2, outputs []lower.CompiledRecipeOutput) (explorer.ConfigV2, []explorer.Diagnostic, error) { - columns := map[string]map[string]bool{} - for _, output := range outputs { - columns[output.Name] = map[string]bool{} - for _, column := range output.Columns { - columns[output.Name][column] = true - } - } - repaired, diagnostics, err := explorer.RepairConfigV2Presentation(cfg, columns) - return repaired, diagnostics, err -} diff --git a/internal/server/explorer_v2_engine_test.go b/internal/server/explorer_v2_engine_test.go deleted file mode 100644 index b403c31f..00000000 --- a/internal/server/explorer_v2_engine_test.go +++ /dev/null @@ -1,235 +0,0 @@ -package server - -import ( - "context" - "encoding/json" - "strconv" - "strings" - "testing" - - "github.com/calypr/loom/internal/dataframe/recipe" - "github.com/calypr/loom/internal/dataframe/recipe/engine" - "github.com/calypr/loom/internal/dataframe/recipe/exec" - "github.com/calypr/loom/internal/explorer" -) - -type compilerTestRegistry struct{} - -func (compilerTestRegistry) LoadRecipe(context.Context, string) (exec.Entry, error) { - return exec.Entry{}, nil -} - -func TestExplorerV2CompilerUsesActiveGenerationWithoutSnapshotToken(t *testing.T) { - var resolvedGeneration string - recipeEngine, err := engine.New(engine.Config{ - Registry: compilerTestRegistry{}, - ResolveBundle: func(_ context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (recipe.Bundle, error) { - resolvedGeneration = bindings.DatasetGeneration - return bundle, nil - }, - QueryRows: func(context.Context, string, int, map[string]any, func(map[string]any) error) error { - return nil - }, - }) - if err != nil { - t.Fatal(err) - } - - snapshot, err := explorer.NewCatalogSnapshot("project-a", "generation-live", "scope", explorer.Catalog{}, true, false, nil) - if err != nil { - t.Fatal(err) - } - compiler := explorerV2Compiler(recipeEngine, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { - return snapshot, nil - }) - - var configV2 explorer.ConfigV2 - if err := json.Unmarshal(baselineExplorerConfigV2("project-a", "Default"), &configV2); err != nil { - t.Fatal(err) - } - configV2.Explorer.ID = "custom" - configV2.Explorer.Management = "interactive" - bundle := testV2Bundle("compiler-test") - bundle.Outputs[0].RowGrain = "file" - configV2.Recipe, err = json.Marshal(bundle) - if err != nil { - t.Fatal(err) - } - configV2.Views = []explorer.ConfigView{{ - ID: "documents", Title: "Documents", Output: "DocumentReference", - Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "id", Label: "ID", Visible: true}, {Column: "category_coding_code", Label: "Legacy", Visible: true}}}, - }} - config, err := json.Marshal(configV2) - if err != nil { - t.Fatal(err) - } - result, err := compiler(context.Background(), ExplorerV2CompileRequest{ - Project: "project-a", - ExplorerID: "custom", - Config: json.RawMessage(config), - }) - if err != nil { - t.Fatal(err) - } - if result.SourceGeneration != "generation-live" || resolvedGeneration != "generation-live" { - t.Fatalf("compiler generation = %q, resolver generation = %q; want generation-live", result.SourceGeneration, resolvedGeneration) - } - var repaired explorer.ConfigV2 - if err := json.Unmarshal(result.Config, &repaired); err != nil { - t.Fatal(err) - } - if len(repaired.Views) != 1 || len(repaired.Views[0].Table.Columns) != 1 || repaired.Views[0].Table.Columns[0].Column != "id" { - t.Fatalf("stale presentation was not removed: %#v", repaired.Views) - } - if len(result.Diagnostics) != 1 || result.Diagnostics[0].Code != "STALE_PRESENTATION_REFERENCE" { - t.Fatalf("repair diagnostics = %#v", result.Diagnostics) - } -} - -func TestExplorerV2CompilerResolvesRootCandidatesForRequestedOutput(t *testing.T) { - firstOutput := testV2Bundle("compiler-test").Outputs[0] - secondOutput := recipe.Output{ - Name: "SubstanceDefinition", - RootResourceType: "SubstanceDefinition", - RowGrain: "substance_definition", - Fields: []recipe.Field{{ - Name: "id", - FieldRef: "SubstanceDefinition.id", - Expr: recipe.Expression{Select: "root.id"}, - }}, - } - bundle := recipe.Bundle{ - RecipeSchemaVersion: recipe.CurrentSchemaVersion, - Name: "compiler-test", - TranslationVersion: "interactive", - Outputs: []recipe.Output{firstOutput, secondOutput}, - } - configV2 := explorer.ConfigV2{ - APIVersion: explorer.ConfigV2APIVersion, - Kind: "ExplorerConfig", - Project: "project-a", - Explorer: explorer.ConfigExplorer{ - ID: "custom", - Title: "Custom", - Management: "interactive", - }, - Views: []explorer.ConfigView{{ - ID: "substance-definition", Title: "Substance definitions", Output: secondOutput.Name, - Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "id", Visible: true}}}, - }}, - } - configV2.Recipe, _ = json.Marshal(bundle) - config, err := json.Marshal(configV2) - if err != nil { - t.Fatal(err) - } - - firstNodeID := explorer.OpaqueID("n_", firstOutput.RootResourceType) - secondNodeID := explorer.OpaqueID("n_", secondOutput.RootResourceType) - secondSelectionID := explorer.OpaqueID("s_", "SubstanceDefinition\x00id") - snapshot, err := explorer.NewCatalogSnapshot( - "project-a", - "generation-live", - "scope", - explorer.Catalog{ - Nodes: []explorer.CatalogNode{ - {ID: firstNodeID, ResourceType: firstOutput.RootResourceType}, - {ID: secondNodeID, ResourceType: secondOutput.RootResourceType}, - }, - Selections: map[string]explorer.CatalogSelection{ - secondSelectionID: { - ID: secondSelectionID, - NodeID: secondNodeID, - }, - }, - }, - true, - false, - nil, - ) - if err != nil { - t.Fatal(err) - } - - compiler := explorerV2Compiler(nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { - return snapshot, nil - }) - _, err = compiler(context.Background(), ExplorerV2CompileRequest{ - Project: "project-a", - ExplorerID: "custom", - Config: config, - SnapshotToken: snapshot.Token, - Output: secondOutput.Name, - SelectedCandidateIDsByNode: map[string][]string{ - "root": {secondSelectionID}, - }, - }) - if err != nil { - t.Fatalf("requested output root candidate was rejected: %v", err) - } -} - -func TestExplorerV2CompilerDistinguishesMissingAndWrongNodeCandidates(t *testing.T) { - bundle := testV2Bundle("compiler-test") - configV2 := explorer.ConfigV2{ - APIVersion: explorer.ConfigV2APIVersion, - Kind: "ExplorerConfig", - Project: "project-a", - Explorer: explorer.ConfigExplorer{ - ID: "custom", Title: "Custom", Management: "interactive", - }, - Views: []explorer.ConfigView{{ - ID: "documents", Title: "Documents", Output: bundle.Outputs[0].Name, - Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "id", Visible: true}}}, - }}, - } - configV2.Recipe, _ = json.Marshal(bundle) - config, err := json.Marshal(configV2) - if err != nil { - t.Fatal(err) - } - - rootNodeID := explorer.OpaqueID("n_", bundle.Outputs[0].RootResourceType) - otherNodeID := explorer.OpaqueID("n_", "SubstanceDefinition") - wrongSelectionID := explorer.OpaqueID("s_", "SubstanceDefinition\x00id") - snapshot, err := explorer.NewCatalogSnapshot( - "project-a", - "generation-live", - "scope", - explorer.Catalog{ - Nodes: []explorer.CatalogNode{ - {ID: rootNodeID, ResourceType: bundle.Outputs[0].RootResourceType}, - {ID: otherNodeID, ResourceType: "SubstanceDefinition"}, - }, - Selections: map[string]explorer.CatalogSelection{ - wrongSelectionID: {ID: wrongSelectionID, NodeID: otherNodeID}, - }, - }, - true, - false, - nil, - ) - if err != nil { - t.Fatal(err) - } - compiler := explorerV2Compiler(nil, func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { - return snapshot, nil - }) - compile := func(candidateID string) error { - _, err := compiler(context.Background(), ExplorerV2CompileRequest{ - Project: "project-a", ExplorerID: "custom", Config: config, - SnapshotToken: snapshot.Token, Output: bundle.Outputs[0].Name, - SelectedCandidateIDsByNode: map[string][]string{"root": {candidateID}}, - }) - return err - } - - missingErr := compile("s_missing") - if missingErr == nil || !strings.Contains(missingErr.Error(), "is absent from the current snapshot") { - t.Fatalf("missing candidate error = %v", missingErr) - } - wrongNodeErr := compile(wrongSelectionID) - if wrongNodeErr == nil || !strings.Contains(wrongNodeErr.Error(), "belongs to node "+strconv.Quote(otherNodeID)) { - t.Fatalf("wrong-node candidate error = %v", wrongNodeErr) - } -} diff --git a/internal/server/explorer_v2_lifecycle.go b/internal/server/explorer_v2_lifecycle.go deleted file mode 100644 index 94b1665c..00000000 --- a/internal/server/explorer_v2_lifecycle.go +++ /dev/null @@ -1,1971 +0,0 @@ -package server - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "log/slog" - "net/http" - "net/url" - "sort" - "strings" - "time" - - graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" - "github.com/calypr/loom/internal/authscope" - "github.com/calypr/loom/internal/dataframe/publication" - "github.com/calypr/loom/internal/dataframe/recipe" - "github.com/calypr/loom/internal/dataframe/recipe/engine" - "github.com/calypr/loom/internal/dataset" - "github.com/calypr/loom/internal/explorer" - "github.com/calypr/loom/internal/explorer/authoringv2" - "github.com/calypr/loom/internal/projectid" - "github.com/gofiber/fiber/v3" -) - -// ExplorerV2CompileRequest is the server-side authoring seam. Browser -// requests contain opaque candidate IDs only; the compiler resolves them from -// Loom's authoritative catalog. -type ExplorerV2CompileRequest struct { - Project string - ExplorerID string - RequestID string - Config []byte - SnapshotToken string - SelectedCandidateIDsByNode map[string][]string - Output string -} - -type ExplorerV2CompileResult struct { - Config []byte - Bundle recipe.Bundle - RecipeDigest string - ResolvedSchemaDigest string - SourceGeneration string - OutputFingerprints map[string]string - EmittedColumns []explorer.EmittedColumn - Diagnostics []explorer.Diagnostic -} - -type ExplorerV2Compiler func(context.Context, ExplorerV2CompileRequest) (ExplorerV2CompileResult, error) -type ExplorerV2Previewer func(context.Context, recipe.Bundle, recipe.RuntimeBindings) (map[string][]map[string]any, error) -type ExplorerV2Materializer = graphresolver.ExplorerBundleMaterializer - -// ExplorerV2ReceiptCompileRequest is the native V2 compile request. The -// compiler owns canonicalization, capability validation, and persistence of -// the immutable receipt before returning it to the HTTP layer. -type ExplorerV2ReceiptCompileRequest struct { - Project string - ExplorerID string - Workspace authoringv2.Workspace - // Document remains for internal legacy tests and migration callers. - Document authoringv2.Document - SnapshotToken string - RequestID string - // Authorized is the exact active capability already resolved by the HTTP - // boundary. Production compilation reuses it so idempotent editor compiles - // do not repeat manifest and authorization discovery. - Authorized AuthorizedCapability -} - -type ExplorerV2ReceiptCompiler func(context.Context, ExplorerV2ReceiptCompileRequest) (*explorer.CompilationReceipt, error) -type ExplorerV2ReceiptReader func(context.Context, string, string, string) (*explorer.CompilationReceipt, error) - -// ExplorerV2ReceiptPreviewer is the bounded transport seam. The -// engine invokes visitor once per public row and returns summary metadata; -// handlers can encode rows without retaining an unbounded result map. -type ExplorerV2ReceiptPreviewer func(context.Context, *explorer.CompilationReceipt, recipe.RuntimeBindings, func(map[string]any) error) (engine.PreviewSummary, error) - -type ExplorerV2ReceiptMaterializer func(context.Context, *explorer.CompilationReceipt, recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) -type ExplorerV2GenerationValidator func(context.Context, string, string) error -type ExplorerV2ReleaseActivator func(context.Context, string, string, []dataset.DataframeSelector) error -type ExplorerAuthoringV1Compiler func(context.Context, ExplorerAuthoringV1CompileRequest) (ExplorerAuthoringV1CompileResult, error) - -// ExplorerV2LifecycleConfig contains explicit capabilities for the REST -// surface. The HTTP layer does not reach into catalog, compiler, or storage -// internals. -type ExplorerV2LifecycleConfig struct { - Compile ExplorerV2Compiler - // CompileReceipt is the production V2 authoring compiler. It returns only - // after the receipt has been durably persisted. - CompileReceipt ExplorerV2ReceiptCompiler - Catalog explorerV2CatalogReader - // Capability and CapabilityToken expose the compiler-owned immutable V2 - // snapshot. Catalog remains an internal V1 migration projection only. - Capability ExplorerCapabilityReader - CapabilityToken ExplorerCapabilityTokenReader - AuthorizedCapabilityCompile ExplorerAuthorizedCapabilityCompilationReader - AuthorizedCapabilityExecution ExplorerAuthorizedCapabilityExecutionReader - Preview ExplorerV2Previewer - PreviewReceipt ExplorerV2ReceiptPreviewer - Materialize ExplorerV2Materializer - MaterializeReceipt ExplorerV2ReceiptMaterializer - // ReceiptLookup must enforce project and Explorer tenancy in the backing - // repository. The legacy service lookup remains a compatibility fallback - // for older tests and stored-document migration. - ReceiptLookup ExplorerV2ReceiptReader - Logger *slog.Logger - // ValidateReleaseGeneration preflights the immutable snapshot required by - // release activation before Publish performs expensive materialization. - ValidateReleaseGeneration ExplorerV2GenerationValidator - // Publish invokes ActivateRelease when the draft requires outputs that are - // not already present in the active dataset release. - ActivateRelease ExplorerV2ReleaseActivator - // AuthoringCompile accepts only V1 authoring intent. It is separate from - // Compile, which remains the repository/ETL packet seam. - AuthoringCompile ExplorerAuthoringV1Compiler -} - -type explorerV2State struct { - Project string `json:"project"` - ExplorerID string `json:"explorerId"` - Title string `json:"-"` - Management explorer.ManagementMode `json:"management"` - ActiveAuthoringBundle json.RawMessage `json:"-"` - ActiveIntentDigest string `json:"-"` - // BaselineConfig is present for the repository default. It is the - // presentation-free recipe/schema projection of the current default draft. - BaselineConfig json.RawMessage `json:"baselineConfig,omitempty"` - // DraftConfig is returned for custom Explorers and for the editable default. - DraftConfig json.RawMessage `json:"draftConfig,omitempty"` - DraftVersion int64 `json:"draftVersion"` - DraftDigest string `json:"draftDigest"` - ActiveConfig json.RawMessage `json:"activeConfig,omitempty"` - ActiveRevisionID string `json:"activeRevisionId,omitempty"` - RecipeDigest string `json:"recipeDigest,omitempty"` - ResolvedSchemaDigest string `json:"resolvedSchemaDigest,omitempty"` - SourceGeneration string `json:"sourceGeneration,omitempty"` - EmittedColumns []explorer.EmittedColumn `json:"emittedColumns,omitempty"` - Materializations []explorer.Materialization `json:"materializations,omitempty"` - Dataset explorer.DatasetMetadata `json:"dataset,omitempty"` - Publication explorer.PublicationMetadata `json:"publication,omitempty"` - Diagnostics []explorer.Diagnostic `json:"diagnostics,omitempty"` - PublicationState string `json:"publicationState,omitempty"` - ActiveURL string `json:"activeUrl"` - UpdatedBy string `json:"updatedBy,omitempty"` - UpdatedAt time.Time `json:"updatedAt"` -} - -func registerLegacyExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, explorers *explorer.Service, capabilities ExplorerV2LifecycleConfig) { - if app == nil || authorizer == nil || authorizeRead == nil || explorers == nil { - return - } - - app.Get("/api/v1/projects/:project/explorers", func(c fiber.Ctx) error { - project := explorerProjectParam(c) - if err := authorizeRead(c.Context(), principalFromFiber(c), project); err != nil { - return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") - } - values, err := listExplorerV2States(c.Context(), explorers, project) - if err != nil { - return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error()) - } - states := make([]explorer.ExplorerStateV1, 0, len(values)) - for _, value := range values { - states = append(states, stateV1FromExplorerV2State(value)) - } - return c.JSON(states) - }) - - app.Get("/api/v1/projects/:project/explorers/:explorerId", func(c fiber.Ctx) error { - project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) - if err := authorizeRead(c.Context(), principalFromFiber(c), project); err != nil { - return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") - } - value, err := getExplorerV2State(c.Context(), explorers, project, id) - if errors.Is(err, explorer.ErrNotFound) { - return explorerV2Error(c, http.StatusNotFound, "EXPLORER_NOT_FOUND", "Explorer not found") - } - if err != nil { - return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error()) - } - return c.JSON(stateV1FromExplorerV2State(value)) - }) - app.Get("/api/v1/projects/:project/explorers/:explorerId/authoring/catalog", func(c fiber.Ctx) error { - project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) - if err := authorizeRead(c.Context(), principalFromFiber(c), project); err != nil { - return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") - } - if capabilities.Catalog == nil { - return explorerV2Error(c, http.StatusServiceUnavailable, "CATALOG_UNAVAILABLE", "Explorer authoring catalog is not configured") - } - snapshot, err := capabilities.Catalog(c.Context(), project, id, "") - if err != nil { - return explorerV2Error(c, http.StatusServiceUnavailable, "CATALOG_UNAVAILABLE", err.Error()) - } - nodes := make([]fiber.Map, 0, len(snapshot.Catalog.Nodes)) - for _, node := range snapshot.Catalog.Nodes { - nodes = append(nodes, fiber.Map{"nodeId": node.ID, "label": node.ResourceType}) - } - selections := make([]fiber.Map, 0, len(snapshot.Catalog.Selections)) - for _, selection := range snapshot.Catalog.Selections { - selections = append(selections, fiber.Map{ - "selectionId": selection.ID, "nodeId": selection.NodeID, "fieldRef": selection.FieldRef, - "select": selection.Select, "logicalType": selection.LogicalType, - "filterable": selection.Filterable, "chartable": selection.Chartable, - }) - } - edges := make([]fiber.Map, 0, len(snapshot.Catalog.Edges)) - for _, edge := range snapshot.Catalog.Edges { - edges = append(edges, fiber.Map{"edgeId": edge.ID, "fromNodeId": edge.FromNodeID, "toNodeId": edge.ToNodeID, "label": edge.Label}) - } - return c.JSON(fiber.Map{ - "snapshotToken": snapshot.Token, "project": snapshot.Project, "explorerId": id, - "sourceGeneration": snapshot.Generation, "authorizationScopeDigest": snapshot.AuthorizationScopeDigest, - "resolvedSchemaDigest": snapshot.ResolvedSchemaDigest, "nodes": nodes, - "selections": selections, "routeEdges": edges, - "completeness": fiber.Map{"complete": snapshot.Complete, "truncated": snapshot.Truncated, "diagnostics": snapshot.Diagnostics}, - "diagnostics": snapshot.Diagnostics, - }) - }) - - app.Post("/api/v1/projects/:project/explorers", func(c fiber.Ctx) error { - project := explorerProjectParam(c) - if err := authorizeExplorerWrite(c, authorizer, project); err != nil { - return err - } - var request struct { - Name string `json:"name"` - Title string `json:"title"` - ExplorerID string `json:"explorerId"` - Source string `json:"source"` - From string `json:"from"` - Blank bool `json:"blank"` - } - if err := decodeStrict(c.Body(), &request); err != nil { - return explorerV2Error(c, http.StatusBadRequest, "MALFORMED_REQUEST", err.Error()) - } - name := strings.TrimSpace(request.Name) - if name == "" { - name = strings.TrimSpace(request.Title) - } - if name == "" { - name = strings.TrimSpace(request.ExplorerID) - } - id := explorer.StableExplorerID(name) - if id == "default" { - return explorerV2Error(c, http.StatusConflict, "EXPLORER_EXISTS", "the repository default already exists; edit its draft") - } - title := strings.TrimSpace(request.Title) - if title == "" { - title = name - } - var raw []byte - if request.Blank || strings.EqualFold(strings.TrimSpace(request.Source), "blank") || strings.EqualFold(strings.TrimSpace(request.From), "blank") { - raw = blankExplorerConfigV2(project, id, title) - } else { - base, err := explorers.RepositoryConfig(c.Context(), project) - if errors.Is(err, explorer.ErrNotFound) { - return explorerV2Error(c, http.StatusConflict, "REPOSITORY_CONFIG_REQUIRED", "deploy the repository default or request a blank Explorer") - } - if err != nil { - return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error()) - } - raw, err = forkRepositoryConfig(base.Config, project, id, title) - if err != nil { - return explorerV2Error(c, http.StatusUnprocessableEntity, "INVALID_REPOSITORY_CONFIG", err.Error()) - } - } - value, err := explorers.CreateInteractiveV2(c.Context(), project, id, raw, subjectFromFiber(c)) - if err != nil { - if errors.Is(err, explorer.ErrDraftConflict) { - return explorerV2Error(c, http.StatusConflict, "EXPLORER_EXISTS", "an Explorer with this name already exists") - } - return explorerV2Error(c, http.StatusUnprocessableEntity, "INVALID_EXPLORER", err.Error()) - } - state, err := getExplorerV2State(c.Context(), explorers, project, value.ExplorerID) - if err != nil { - return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error()) - } - return c.Status(http.StatusCreated).JSON(state) - }) - - app.Put("/api/v1/projects/:project/explorers/:explorerId/draft", func(c fiber.Ctx) error { - project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) - if err := authorizeExplorerWrite(c, authorizer, project); err != nil { - return err - } - var request struct { - Config json.RawMessage `json:"config"` - ExpectedDraftVersion *int64 `json:"expectedDraftVersion"` - ExpectedDraftDigest string `json:"expectedDraftDigest"` - } - if err := decodeStrict(c.Body(), &request); err != nil || request.ExpectedDraftVersion == nil { - if err == nil { - err = fmt.Errorf("expectedDraftVersion is required") - } - return explorerV2Error(c, http.StatusBadRequest, "MALFORMED_REQUEST", err.Error()) - } - cfg, _, canonical, _, err := explorer.CanonicalConfigV2(request.Config, project, id, explorer.ConfigManagementForID(id)) - if err != nil { - return explorerV2Error(c, http.StatusUnprocessableEntity, "INVALID_CONFIG", err.Error()) - } - var repairDiagnostics []explorer.Diagnostic - if owner, ownerErr := explorers.Get(c.Context(), project, id); ownerErr == nil { - if repaired, diagnostics, repairErr := explorer.RepairConfigV2Presentation(cfg, emittedColumnsByOutput(*owner)); repairErr != nil { - return explorerV2ErrorFromCause(c, http.StatusUnprocessableEntity, "INVALID_CONFIG", repairErr) - } else if len(diagnostics) > 0 { - repairDiagnostics = diagnostics - repairedRaw, marshalErr := json.Marshal(repaired) - if marshalErr != nil { - return explorerV2Error(c, http.StatusInternalServerError, "CONFIG_REPAIR_FAILED", marshalErr.Error()) - } - _, _, canonical, _, err = explorer.CanonicalConfigV2(repairedRaw, project, id, explorer.ConfigManagementForID(id)) - if err != nil { - return explorerV2Error(c, http.StatusUnprocessableEntity, "INVALID_CONFIG", err.Error()) - } - } - } - value, err := explorers.SaveDraftV2(c.Context(), project, id, canonical, *request.ExpectedDraftVersion, request.ExpectedDraftDigest, subjectFromFiber(c)) - if errors.Is(err, explorer.ErrDraftConflict) { - return draftConflictResponse(c, explorers, project, id) - } - if errors.Is(err, explorer.ErrNotFound) { - return explorerV2Error(c, http.StatusNotFound, "EXPLORER_NOT_FOUND", "Explorer not found") - } - if err != nil { - return explorerV2Error(c, http.StatusUnprocessableEntity, "DRAFT_SAVE_FAILED", err.Error()) - } - state := stateFromExplorer(value) - state.Diagnostics = append(state.Diagnostics, repairDiagnostics...) - return c.JSON(state) - }) - - app.Post("/api/v1/projects/:project/explorers/:explorerId/authoring/compile", func(c fiber.Ctx) error { - project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) - if err := authorizeExplorerWrite(c, authorizer, project); err != nil { - return err - } - var request struct { - Output string `json:"output"` - Config json.RawMessage `json:"config"` - SnapshotToken string `json:"snapshotToken"` - SelectedCandidateIDsByNode map[string][]string `json:"selectedCandidateIdsByNode"` - ExpectedDraftVersion *int64 `json:"expectedDraftVersion"` - } - if err := decodeStrict(c.Body(), &request); err != nil { - return explorerV2Error(c, http.StatusBadRequest, "MALFORMED_REQUEST", err.Error()) - } - result, digest, err := compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, RequestID: requestIDFromFiber(c), Config: request.Config, SnapshotToken: request.SnapshotToken, SelectedCandidateIDsByNode: request.SelectedCandidateIDsByNode, Output: request.Output}) - if err != nil { - return explorerV2ErrorFromCause(c, http.StatusUnprocessableEntity, "COMPILE_FAILED", err) - } - diagnostics := result.Diagnostics - if diagnostics == nil { - diagnostics = []explorer.Diagnostic{} - } - emittedColumns := result.EmittedColumns - if emittedColumns == nil { - emittedColumns = []explorer.EmittedColumn{} - } - return c.JSON(fiber.Map{"project": project, "explorerId": id, "config": json.RawMessage(result.Config), "draftDigest": digest, "snapshotToken": request.SnapshotToken, "recipeDigest": result.RecipeDigest, "resolvedSchemaDigest": result.ResolvedSchemaDigest, "sourceGeneration": result.SourceGeneration, "emittedColumns": emittedColumns, "diagnostics": diagnostics}) - }) - - app.Post("/api/v1/projects/:project/explorers/:explorerId/preview", func(c fiber.Ctx) error { - project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) - if err := authorizeRead(c.Context(), principalFromFiber(c), project); err != nil { - return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") - } - var request struct { - Config json.RawMessage `json:"config"` - Output string `json:"output"` - Limit int `json:"limit"` - DraftDigest string `json:"draftDigest"` - } - if err := decodeStrict(c.Body(), &request); err != nil { - return explorerV2Error(c, http.StatusBadRequest, "MALFORMED_REQUEST", err.Error()) - } - if request.Limit == 0 { - request.Limit = 25 - } - if request.Limit < 1 || request.Limit > 1000 { - return explorerV2Error(c, http.StatusBadRequest, "INVALID_LIMIT", "limit must be between 1 and 1000") - } - result, digest, err := compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, RequestID: requestIDFromFiber(c), Config: request.Config, Output: request.Output}) - if err != nil { - return previewFailure(c, digest, err) - } - if !bundleHasOutput(result.Bundle, request.Output) { - return previewFailure(c, digest, fmt.Errorf("unsupported output %q", request.Output)) - } - if capabilities.Preview == nil { - return previewFailure(c, digest, fmt.Errorf("preview executor is not configured")) - } - rows, err := capabilities.Preview(c.Context(), result.Bundle, recipe.RuntimeBindings{Project: projectid.Legacy(project), PreviewLimit: request.Limit, DatasetGeneration: result.SourceGeneration, OutputNames: []string{request.Output}}) - if err != nil { - return previewFailure(c, digest, err) - } - selected := rows[request.Output] - return c.JSON(fiber.Map{"project": project, "explorerId": id, "output": request.Output, "config": json.RawMessage(result.Config), "columns": columnsForOutput(result, request.Output), "rows": selected, "rowCount": len(selected), "digest": digest, "diagnostics": result.Diagnostics}) - }) - - app.Post("/api/v1/projects/:project/explorers/:explorerId/publish", func(c fiber.Ctx) error { - project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) - if err := authorizeExplorerWrite(c, authorizer, project); err != nil { - return err - } - var request struct { - ExpectedDraftVersion *int64 `json:"expectedDraftVersion"` - ExpectedDraftDigest string `json:"expectedDraftDigest"` - } - if err := decodeStrict(c.Body(), &request); err != nil { - return explorerV2Error(c, http.StatusBadRequest, "MALFORMED_REQUEST", err.Error()) - } - requestID, _ := c.Locals("request_id").(string) - publishInfo := func(event string, args ...any) { - if capabilities.Logger == nil { - return - } - base := []any{"request_id", requestID, "project", project, "explorer_id", id} - capabilities.Logger.Info(event, append(base, args...)...) - } - publishFailure := func(status int, code, message, phase string, details any) error { - if capabilities.Logger != nil { - capabilities.Logger.Error("Explorer publish failed", "request_id", requestID, "project", project, "explorer_id", id, "phase", phase, "code", code, "details", details) - } - return explorerV2ErrorWithDetails(c, status, code, message, publicExplorerPublishDetails(details)) - } - publishInfo("Explorer publish started") - owner, err := explorers.Get(c.Context(), project, id) - if errors.Is(err, explorer.ErrNotFound) { - return explorerV2Error(c, http.StatusNotFound, "EXPLORER_NOT_FOUND", "Explorer not found") - } - if err != nil { - return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error()) - } - result, digest, err := compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, RequestID: requestIDFromFiber(c), Config: owner.DraftConfig}) - if err != nil { - // A persisted canonical draft should compile. Retry against the - // latest draft once so a concurrent last-write-wins save or a - // transient catalog update does not become a user-facing 422. - if latest, readErr := explorers.Get(c.Context(), project, id); readErr == nil { - owner = latest - result, digest, err = compileExplorerV2(c.Context(), capabilities.Compile, ExplorerV2CompileRequest{Project: project, ExplorerID: id, RequestID: requestIDFromFiber(c), Config: owner.DraftConfig}) - } - if err != nil { - return publishFailure(http.StatusInternalServerError, "PUBLISH_PIPELINE_FAILED", "the current Explorer draft could not be compiled", "COMPILE", fiber.Map{"draftVersion": owner.DraftVersion, "draftDigest": owner.DraftDigest, "cause": err.Error()}) - } - } - publishInfo("Explorer publish compiled", "recipe_digest", result.RecipeDigest, "resolved_schema_digest", result.ResolvedSchemaDigest, "source_generation", result.SourceGeneration, "output_count", len(result.Bundle.Outputs)) - // Publish is the single user-facing visibility operation. Reuse each - // unchanged output and materialize only outputs whose compiled fingerprint - // is absent or different from the active dataset metadata. - repository, repositoryErr := explorers.RepositoryConfig(c.Context(), project) - var activeRelease activeExplorerDataset - var activeErr error - if repositoryErr != nil || repository == nil { - activeErr = &activeExplorerDatasetError{message: fmt.Sprintf("active repository dataset release is unavailable for project %q", project), details: activeDatasetCompatibility{MissingOutputs: missingDatasetOutputs(result.Bundle, "ACTIVE_RELEASE_UNAVAILABLE")}} - } else { - activeRelease = activeExplorerDatasetFromRepository(*repository) - if activeRelease.Generation == "" { - activeErr = &activeExplorerDatasetError{message: fmt.Sprintf("active repository dataset release for project %q has no generation", project), details: activeDatasetCompatibility{MissingOutputs: missingDatasetOutputs(result.Bundle, "ACTIVE_RELEASE_UNAVAILABLE")}} - } else if state := strings.ToUpper(strings.TrimSpace(activeRelease.Publication.State)); state != "" && state != "ACTIVE" && state != "READY" { - activeErr = &activeExplorerDatasetError{message: fmt.Sprintf("active repository dataset release for project %q is not active", project), details: activeDatasetCompatibility{MissingOutputs: missingDatasetOutputs(result.Bundle, "ACTIVE_RELEASE_UNAVAILABLE")}} - } - } - // Compilation, fingerprints, materialization, and release activation must - // all use one generation. Repository metadata describes the prior release - // and is only a reuse candidate; it must never override the generation the - // compiler resolved from the active catalog. - generation := strings.TrimSpace(result.SourceGeneration) - if generation == "" { - return publishFailure(http.StatusServiceUnavailable, "DATASET_BUILD_UNAVAILABLE", "publishing this Explorer requires a dataset generation", "RESOLVE_GENERATION", activeDatasetErrorDetails(activeErr, result.Bundle)) - } - if repositoryErr == nil && repository != nil && strings.TrimSpace(repository.SourceGeneration) != "" && strings.TrimSpace(repository.SourceGeneration) != generation { - publishInfo("Explorer dataset generation advanced", "previous_generation", strings.TrimSpace(repository.SourceGeneration), "generation", generation) - } - changedOutputs := result.Bundle.Outputs - if activeErr == nil { - changedOutputs = outputsNeedingMaterialization(result.Bundle, activeRelease, generation, result.OutputFingerprints) - } - publishInfo("Explorer publish output plan", "generation", generation, "changed_outputs", recipeOutputNames(changedOutputs), "reused_output_count", len(result.Bundle.Outputs)-len(changedOutputs)) - if len(changedOutputs) > 0 { - if capabilities.Materialize == nil || capabilities.ActivateRelease == nil { - return publishFailure(http.StatusServiceUnavailable, "DATASET_BUILD_UNAVAILABLE", "publishing this Explorer requires a dataset build that is not configured", "MATERIALIZE_UNAVAILABLE", activeDatasetErrorDetails(activeErr, result.Bundle)) - } - if capabilities.ValidateReleaseGeneration != nil { - if validateErr := capabilities.ValidateReleaseGeneration(c.Context(), projectid.Legacy(project), generation); validateErr != nil { - status, code, message := explorerReleaseFailure(validateErr, true) - return publishFailure(status, code, message, "VALIDATE_DATASET_RELEASE", fiber.Map{"generation": generation, "cause": validateErr.Error()}) - } - } - var executions []graphresolver.RecipeExecution - for _, output := range changedOutputs { - publishInfo("Explorer output materialization started", "output", output.Name) - execution, materializeErr := capabilities.Materialize(c.Context(), result.Bundle, recipe.RuntimeBindings{Project: projectid.Legacy(project), DatasetGeneration: generation, OutputNames: []string{output.Name}}) - if materializeErr != nil { - return publishFailure(http.StatusServiceUnavailable, "DATASET_BUILD_FAILED", "the dataset could not be built for this Explorer", "MATERIALIZE", fiber.Map{"generation": generation, "output": output.Name, "cause": materializeErr.Error(), "details": activeDatasetErrorDetails(activeErr, result.Bundle)}) - } - if verifyErr := verifyQueryableOutput(output.Name, generation, execution); verifyErr != nil { - return publishFailure(http.StatusServiceUnavailable, "DATASET_BUILD_FAILED", "the dataset build did not produce a queryable Explorer output", "VERIFY_MATERIALIZE", fiber.Map{"generation": generation, "output": output.Name, "cause": verifyErr.Error(), "details": activeDatasetErrorDetails(activeErr, result.Bundle)}) - } - publishInfo("Explorer output materialization complete", "output", output.Name, "execution_id", execution.ID) - executions = append(executions, execution) - } - publishInfo("Explorer dataset release activation started", "outputs", recipeOutputNames(changedOutputs)) - if err := activateExplorerReleaseWithRetry(c.Context(), capabilities.ActivateRelease, projectid.Legacy(project), generation, selectorsForOutputs(changedOutputs, result.Bundle)); err != nil { - status, code, message := explorerReleaseFailure(err, false) - return publishFailure(status, code, message, "ACTIVATE_DATASET_RELEASE", fiber.Map{"generation": generation, "cause": err.Error(), "outputs": recipeOutputNames(changedOutputs)}) - } - publishInfo("Explorer dataset release activation complete", "outputs", recipeOutputNames(changedOutputs)) - resolvedSchemaDigest := result.ResolvedSchemaDigest - if len(executions) > 0 && executions[len(executions)-1].ResolvedSchemaDigest != "" { - resolvedSchemaDigest = executions[len(executions)-1].ResolvedSchemaDigest - } - activeRelease = mergeMaterializedExplorerOutputs(result.Bundle, activeRelease, generation, resolvedSchemaDigest, result.OutputFingerprints, executions) - if repositoryErr == nil && repository != nil { - if err := persistActiveExplorerDataset(c.Context(), explorers, *repository, activeRelease); err != nil { - return publishFailure(http.StatusInternalServerError, "DATASET_METADATA_PERSIST_FAILED", "the dataset was built but its release metadata could not be persisted", "PERSIST_DATASET_METADATA", fiber.Map{"generation": generation, "cause": err.Error()}) - } - publishInfo("Explorer dataset metadata persisted", "outputs", recipeOutputNames(changedOutputs)) - } - } else if activeErr != nil { - return publishFailure(http.StatusServiceUnavailable, "DATASET_BUILD_UNAVAILABLE", "the active dataset release could not be resolved", "RESOLVE_ACTIVE_DATASET", activeDatasetErrorDetails(activeErr, result.Bundle)) - } - materializations, datasetMetadata, err := reuseActiveExplorerDataset(result.Bundle, activeRelease) - if err != nil { - return publishFailure(http.StatusInternalServerError, "DATASET_OUTPUT_UNAVAILABLE", "the active dataset metadata became inconsistent during publish", "REUSE_DATASET_METADATA", fiber.Map{"cause": err.Error()}) - } - compiled := explorer.Compilation{Bundle: result.Bundle, RecipeDigest: result.RecipeDigest, EmittedColumns: result.EmittedColumns} - sourceGeneration := activeRelease.Generation - resolvedSchemaDigest := activeRelease.SchemaDigest - if resolvedSchemaDigest == "" { - resolvedSchemaDigest = result.ResolvedSchemaDigest - } - publication := activeRelease.Publication - publication.State = string(explorer.RevisionReady) - publication.Generation = sourceGeneration - revision, err := explorers.InsertReadyRevisionV2WithMetadata(c.Context(), owner, result.Config, digest, compiled, resolvedSchemaDigest, sourceGeneration, subjectFromFiber(c), materializations, datasetMetadata, publication) - if err != nil { - return publishFailure(http.StatusInternalServerError, "REVISION_INSERT_FAILED", err.Error(), "INSERT_REVISION", fiber.Map{"cause": err.Error()}) - } - publishInfo("Explorer revision inserted", "revision_id", revision.ID, "reused_output_count", len(result.Bundle.Outputs)-len(changedOutputs)) - var activationErr error - if id == "default" { - activationErr = explorers.ActivateRepository(c.Context(), project, revision.ID) - } else { - activationErr = explorers.ActivateInteractive(c.Context(), project, id, revision.ID) - } - if activationErr != nil { - return publishFailure(http.StatusServiceUnavailable, "ACTIVATION_FAILED", "the Explorer revision could not be activated", "ACTIVATE_EXPLORER", fiber.Map{"cause": activationErr.Error()}) - } - state, err := getExplorerV2State(c.Context(), explorers, project, id) - if err != nil { - return publishFailure(http.StatusInternalServerError, "EXPLORER_READ_FAILED", err.Error(), "READ_PUBLISHED_STATE", fiber.Map{"cause": err.Error()}) - } - publishInfo("Explorer publish complete", "revision_id", revision.ID, "reused_output_count", len(result.Bundle.Outputs)-len(changedOutputs)) - return c.JSON(fiber.Map{"project": project, "explorerId": id, "publicationId": revision.ID, "draftVersion": owner.DraftVersion, "draftDigest": owner.DraftDigest, "activeUrl": state.ActiveURL, "state": state, "materializations": materializations, "diagnostics": result.Diagnostics}) - }) -} - -func selectorsForBundle(bundle recipe.Bundle) []dataset.DataframeSelector { - selectors := make([]dataset.DataframeSelector, 0, len(bundle.Outputs)) - for _, output := range bundle.Outputs { - selectors = append(selectors, dataset.DataframeSelector{Recipe: bundle.Name, TranslationVersion: bundle.TranslationVersion, Output: output.Name}) - } - return selectors -} - -func selectorsForOutputs(outputs []recipe.Output, bundle recipe.Bundle) []dataset.DataframeSelector { - selectors := make([]dataset.DataframeSelector, 0, len(outputs)) - for _, output := range outputs { - selectors = append(selectors, dataset.DataframeSelector{Recipe: bundle.Name, TranslationVersion: bundle.TranslationVersion, Output: output.Name}) - } - return selectors -} - -func recipeOutputNames(outputs []recipe.Output) []string { - names := make([]string, 0, len(outputs)) - for _, output := range outputs { - names = append(names, output.Name) - } - return names -} - -func outputsNeedingMaterialization(bundle recipe.Bundle, active activeExplorerDataset, generation string, fingerprints map[string]string) []recipe.Output { - if strings.TrimSpace(active.Generation) == "" || active.Generation != generation { - return append([]recipe.Output(nil), bundle.Outputs...) - } - result := make([]recipe.Output, 0) - for _, output := range bundle.Outputs { - var datasetOutput *explorer.DatasetOutput - for index := range active.Dataset.Outputs { - if active.Dataset.Outputs[index].Name == output.Name { - candidate := active.Dataset.Outputs[index] - datasetOutput = &candidate - break - } - } - var materialization *explorer.Materialization - for index := range active.Materializations { - if active.Materializations[index].Output == output.Name { - candidate := active.Materializations[index] - materialization = &candidate - break - } - } - fingerprint := strings.TrimSpace(fingerprints[output.Name]) - fingerprintRequired := len(fingerprints) > 0 - if datasetOutput == nil || materialization == nil || !datasetOutput.Queryable || - !selectorForOutputIsCanonical(datasetOutput.Selector, output.Name) || - !selectorForOutputIsCanonical(materialization.Selector, output.Name) || - *datasetOutput.Selector != *materialization.Selector || - (fingerprintRequired && (fingerprint == "" || (datasetOutput.Fingerprint != fingerprint && materialization.Fingerprint != fingerprint))) { - result = append(result, output) - } - } - return result -} - -func verifyQueryableOutput(output, generation string, execution graphresolver.RecipeExecution) error { - if strings.TrimSpace(execution.SourceGeneration) != strings.TrimSpace(generation) { - return fmt.Errorf("output %q was materialized for generation %q instead of %q", output, execution.SourceGeneration, generation) - } - executionState := strings.ToUpper(strings.TrimSpace(execution.State)) - if executionState != "PUBLISHED" && executionState != "READY" && executionState != "ACTIVE" { - return fmt.Errorf("output %q execution is not queryable (state %q)", output, execution.State) - } - for _, item := range execution.Outputs { - if item.Name == output { - state := strings.ToUpper(item.State) - if state == "PUBLISHED" || state == "READY" || state == "ACTIVE" { - return nil - } - return fmt.Errorf("output %q is not queryable (state %q)", output, item.State) - } - } - return fmt.Errorf("output %q was not returned by the materializer", output) -} - -func mergeMaterializedExplorerOutputs(bundle recipe.Bundle, active activeExplorerDataset, generation, schemaDigest string, fingerprints map[string]string, executions []graphresolver.RecipeExecution) activeExplorerDataset { - materializations := make(map[string]explorer.Materialization, len(active.Materializations)+len(executions)) - for _, item := range active.Materializations { - materializations[item.Output] = item - } - datasetOutputs := make(map[string]explorer.DatasetOutput, len(active.Dataset.Outputs)+len(executions)) - for _, item := range active.Dataset.Outputs { - datasetOutputs[item.Name] = item - } - lastExecutionID := active.Publication.ExecutionID - for _, execution := range executions { - lastExecutionID = execution.ID - for _, output := range execution.Outputs { - selector := explorerOutputSelector(bundle, output.Name) - fingerprint := fingerprints[output.Name] - materializations[output.Name] = explorer.Materialization{OutputID: output.Name, Output: output.Name, MaterializationID: execution.ID, Fingerprint: fingerprint, Selector: selector, Columns: append([]publication.PhysicalColumn(nil), output.Columns...)} - state := strings.ToUpper(output.State) - datasetOutputs[output.Name] = explorer.DatasetOutput{Name: output.Name, State: state, Queryable: state == "PUBLISHED" || state == "READY" || state == "ACTIVE", Fingerprint: fingerprint, Selector: selector, Columns: append([]publication.PhysicalColumn(nil), output.Columns...)} - } - } - mergedMaterials := make([]explorer.Materialization, 0, len(materializations)) - for _, item := range materializations { - mergedMaterials = append(mergedMaterials, item) - } - sort.Slice(mergedMaterials, func(i, j int) bool { return mergedMaterials[i].Output < mergedMaterials[j].Output }) - mergedOutputs := make([]explorer.DatasetOutput, 0, len(datasetOutputs)) - for _, item := range datasetOutputs { - mergedOutputs = append(mergedOutputs, item) - } - sort.Slice(mergedOutputs, func(i, j int) bool { return mergedOutputs[i].Name < mergedOutputs[j].Name }) - return activeExplorerDataset{ - Generation: generation, SchemaDigest: schemaDigest, - Materializations: mergedMaterials, - Dataset: explorer.DatasetMetadata{Generation: generation, SchemaDigest: schemaDigest, Outputs: mergedOutputs}, - Publication: explorer.PublicationMetadata{State: string(explorer.RevisionReady), Generation: generation, ExecutionID: lastExecutionID, UpdatedAt: time.Now().UTC()}, - } -} - -func activateExplorerReleaseWithRetry(ctx context.Context, activate ExplorerV2ReleaseActivator, project, generation string, selectors []dataset.DataframeSelector) error { - err := activate(ctx, project, generation, selectors) - if err != nil && errors.Is(err, dataset.ErrReleaseActivationConflict) { - return activate(ctx, project, generation, selectors) - } - return err -} - -func explorerReleaseFailure(err error, preflight bool) (int, string, string) { - switch { - case errors.Is(err, dataset.ErrSnapshotNotFound): - return http.StatusServiceUnavailable, "DATASET_GENERATION_UNAVAILABLE", "the active dataset generation is not ready for publishing" - case errors.Is(err, dataset.ErrReleaseRequirementsUnmet): - return http.StatusServiceUnavailable, "DATASET_GENERATION_NOT_READY", "the active dataset generation is still being prepared" - case errors.Is(err, dataset.ErrReleaseActivationConflict): - return http.StatusConflict, "DATASET_RELEASE_CONFLICT", "the active dataset changed while publishing; retry publish" - default: - if preflight { - return http.StatusServiceUnavailable, "DATASET_GENERATION_UNAVAILABLE", "the active dataset generation could not be validated" - } - return http.StatusServiceUnavailable, "DATASET_RELEASE_ACTIVATION_FAILED", "the dataset was built but could not be activated" - } -} - -type activeExplorerDataset struct { - Generation string - SchemaDigest string - Materializations []explorer.Materialization - Dataset explorer.DatasetMetadata - Publication explorer.PublicationMetadata -} - -type activeDatasetOutputDiagnostic struct { - Output string `json:"output"` - Path string `json:"path"` - Reason string `json:"reason"` -} - -type activeDatasetCompatibility struct { - Ready bool `json:"ready"` - ActiveGeneration string `json:"activeGeneration,omitempty"` - MissingOutputs []activeDatasetOutputDiagnostic `json:"missingOutputs,omitempty"` - AvailableOutputs []string `json:"availableOutputs,omitempty"` -} - -type activeExplorerDatasetError struct { - message string - details activeDatasetCompatibility -} - -func (e *activeExplorerDatasetError) Error() string { return e.message } - -func activeDatasetErrorDetails(err error, bundle recipe.Bundle) activeDatasetCompatibility { - var datasetErr *activeExplorerDatasetError - if errors.As(err, &datasetErr) { - return datasetErr.details - } - return activeDatasetCompatibility{MissingOutputs: missingDatasetOutputs(bundle, "ACTIVE_RELEASE_UNAVAILABLE")} -} - -func missingDatasetOutputs(bundle recipe.Bundle, reason string) []activeDatasetOutputDiagnostic { - missing := make([]activeDatasetOutputDiagnostic, 0, len(bundle.Outputs)) - for index, output := range bundle.Outputs { - missing = append(missing, activeDatasetOutputDiagnostic{Output: output.Name, Path: fmt.Sprintf("recipe.outputs[%d]", index), Reason: reason}) - } - return missing -} - -// resolveActiveExplorerDataset reads the canonical repository release record. -// Explorer revisions are configuration pointers, not dataset-release records; -// they are never used as a compatibility fallback here. -func resolveActiveExplorerDataset(ctx context.Context, service *explorer.Service, project string, bundle recipe.Bundle) (activeExplorerDataset, error) { - repository, err := service.RepositoryConfig(ctx, project) - if err != nil || repository == nil { - return activeExplorerDataset{}, &activeExplorerDatasetError{ - message: fmt.Sprintf("active repository dataset release is unavailable for project %q", project), - details: activeDatasetCompatibility{MissingOutputs: missingDatasetOutputs(bundle, "ACTIVE_RELEASE_UNAVAILABLE")}, - } - } - candidate := activeExplorerDatasetFromRepository(*repository) - if candidate.Generation == "" { - return activeExplorerDataset{}, &activeExplorerDatasetError{ - message: fmt.Sprintf("active repository dataset release for project %q has no generation", project), - details: activeDatasetCompatibility{MissingOutputs: missingDatasetOutputs(bundle, "ACTIVE_RELEASE_UNAVAILABLE")}, - } - } - compatibility := inspectActiveExplorerDataset(candidate, bundle) - if !compatibility.Ready { - return activeExplorerDataset{}, &activeExplorerDatasetError{ - message: fmt.Sprintf("active repository dataset release for project %q does not contain complete metadata for the requested Explorer outputs", project), - details: compatibility, - } - } - return candidate, nil -} - -func activeExplorerDatasetFromRepository(value explorer.RepositoryConfig) activeExplorerDataset { - return activeExplorerDataset{Generation: strings.TrimSpace(value.SourceGeneration), SchemaDigest: value.Dataset.SchemaDigest, Materializations: append([]explorer.Materialization(nil), value.Materializations...), Dataset: value.Dataset, Publication: value.Publication} -} - -func activeExplorerDatasetSupports(value activeExplorerDataset, bundle recipe.Bundle) bool { - return inspectActiveExplorerDataset(value, bundle).Ready -} - -func inspectActiveExplorerDataset(value activeExplorerDataset, bundle recipe.Bundle) activeDatasetCompatibility { - compatibility := activeDatasetCompatibility{Ready: true, ActiveGeneration: value.Generation} - for _, item := range value.Dataset.Outputs { - if item.Name != "" { - compatibility.AvailableOutputs = append(compatibility.AvailableOutputs, item.Name) - } - } - sort.Strings(compatibility.AvailableOutputs) - for index, output := range bundle.Outputs { - diagnostic := activeDatasetOutputDiagnostic{Output: output.Name, Path: fmt.Sprintf("recipe.outputs[%d]", index)} - var datasetOutput *explorer.DatasetOutput - for itemIndex := range value.Dataset.Outputs { - if value.Dataset.Outputs[itemIndex].Name == output.Name { - candidate := value.Dataset.Outputs[itemIndex] - datasetOutput = &candidate - break - } - } - if datasetOutput == nil { - diagnostic.Reason = "MISSING_DATASET_OUTPUT" - } else if !datasetOutput.Queryable && !isQueryableDatasetState(datasetOutput.State) { - diagnostic.Reason = "OUTPUT_NOT_QUERYABLE" - } else if !selectorForOutputIsCanonical(datasetOutput.Selector, output.Name) { - diagnostic.Reason = "MISSING_DATASET_SELECTOR" - } else { - var materialization *explorer.Materialization - for itemIndex := range value.Materializations { - if value.Materializations[itemIndex].Output == output.Name { - candidate := value.Materializations[itemIndex] - materialization = &candidate - break - } - } - if materialization == nil || materialization.MaterializationID == "" { - diagnostic.Reason = "MISSING_MATERIALIZATION" - } else if !selectorForOutputIsCanonical(materialization.Selector, output.Name) { - diagnostic.Reason = "MISSING_MATERIALIZATION_SELECTOR" - } else if *datasetOutput.Selector != *materialization.Selector { - diagnostic.Reason = "SELECTOR_MISMATCH" - } - } - if diagnostic.Reason != "" { - compatibility.Ready = false - compatibility.MissingOutputs = append(compatibility.MissingOutputs, diagnostic) - } - } - return compatibility -} - -func persistActiveExplorerDataset(ctx context.Context, service *explorer.Service, repository explorer.RepositoryConfig, active activeExplorerDataset) error { - materializations := mergeExplorerMaterializations(repository.Materializations, active.Materializations) - dataset := mergeExplorerDataset(repository.Dataset, active.Dataset, active.Generation, active.SchemaDigest) - repository.SourceGeneration = active.Generation - repository.Materializations = materializations - repository.Dataset = dataset - repository.Publication = active.Publication - if repository.ExecutionID == "" { - repository.ExecutionID = active.Publication.ExecutionID - } - _, err := service.SaveRepositoryConfig(ctx, repository) - return err -} - -func mergeExplorerMaterializations(existing, updates []explorer.Materialization) []explorer.Materialization { - byOutput := make(map[string]explorer.Materialization, len(existing)+len(updates)) - for _, value := range existing { - byOutput[value.Output] = value - } - for _, value := range updates { - byOutput[value.Output] = value - } - result := make([]explorer.Materialization, 0, len(byOutput)) - for _, value := range byOutput { - result = append(result, value) - } - sort.Slice(result, func(i, j int) bool { return result[i].Output < result[j].Output }) - return result -} - -func mergeExplorerDataset(existing, updates explorer.DatasetMetadata, generation, schemaDigest string) explorer.DatasetMetadata { - byOutput := make(map[string]explorer.DatasetOutput, len(existing.Outputs)+len(updates.Outputs)) - for _, value := range existing.Outputs { - byOutput[value.Name] = value - } - for _, value := range updates.Outputs { - byOutput[value.Name] = value - } - outputs := make([]explorer.DatasetOutput, 0, len(byOutput)) - for _, value := range byOutput { - outputs = append(outputs, value) - } - sort.Slice(outputs, func(i, j int) bool { return outputs[i].Name < outputs[j].Name }) - if generation == "" { - generation = existing.Generation - } - if schemaDigest == "" { - schemaDigest = existing.SchemaDigest - } - return explorer.DatasetMetadata{Generation: generation, SchemaDigest: schemaDigest, Outputs: outputs} -} - -func reuseActiveExplorerDataset(bundle recipe.Bundle, value activeExplorerDataset) ([]explorer.Materialization, explorer.DatasetMetadata, error) { - materializations := make([]explorer.Materialization, 0, len(bundle.Outputs)) - outputs := make([]explorer.DatasetOutput, 0, len(bundle.Outputs)) - for _, output := range bundle.Outputs { - var materialization *explorer.Materialization - for index := range value.Materializations { - if value.Materializations[index].Output == output.Name { - candidate := value.Materializations[index] - materialization = &candidate - break - } - } - var datasetOutput *explorer.DatasetOutput - for index := range value.Dataset.Outputs { - if value.Dataset.Outputs[index].Name == output.Name { - candidate := value.Dataset.Outputs[index] - datasetOutput = &candidate - break - } - } - if datasetOutput == nil || (!datasetOutput.Queryable && !isQueryableDatasetState(datasetOutput.State)) { - return nil, explorer.DatasetMetadata{}, fmt.Errorf("output %q is not queryable in the active dataset release", output.Name) - } - if materialization == nil || materialization.MaterializationID == "" || !selectorForOutputIsCanonical(materialization.Selector, output.Name) { - return nil, explorer.DatasetMetadata{}, fmt.Errorf("output %q has incomplete active dataframe materialization", output.Name) - } - if !selectorForOutputIsCanonical(datasetOutput.Selector, output.Name) { - return nil, explorer.DatasetMetadata{}, fmt.Errorf("output %q has no active dataframe selector", output.Name) - } - if *datasetOutput.Selector != *materialization.Selector { - return nil, explorer.DatasetMetadata{}, fmt.Errorf("output %q has mismatched active dataframe selectors", output.Name) - } - materialization.OutputID = output.Name - materialization.Output = output.Name - if len(materialization.Columns) == 0 { - materialization.Columns = append([]publication.PhysicalColumn(nil), datasetOutput.Columns...) - } - materializations = append(materializations, *materialization) - datasetOutput.Name = output.Name - datasetOutput.Columns = append([]publication.PhysicalColumn(nil), materialization.Columns...) - outputs = append(outputs, *datasetOutput) - } - dataset := explorer.DatasetMetadata{Generation: value.Generation, SchemaDigest: value.SchemaDigest, Outputs: outputs} - return materializations, dataset, nil -} - -func selectorForOutputIsCanonical(selector *dataset.DataframeSelector, output string) bool { - return selector != nil && selector.Valid() && selector.Output == output -} - -func isQueryableDatasetState(state string) bool { - switch strings.ToUpper(strings.TrimSpace(state)) { - case "PUBLISHED", "READY", "ACTIVE": - return true - default: - return false - } -} - -func decodeStrict(raw []byte, value any) error { - decoder := json.NewDecoder(strings.NewReader(string(raw))) - decoder.DisallowUnknownFields() - if err := decoder.Decode(value); err != nil { - return err - } - var trailing any - if err := decoder.Decode(&trailing); err == nil { - return fmt.Errorf("multiple JSON values") - } - return nil -} - -func principalFromFiber(c fiber.Ctx) *authscope.Principal { - principal, _ := c.Locals("principal").(*authscope.Principal) - return principal -} -func subjectFromFiber(c fiber.Ctx) string { - if principal := principalFromFiber(c); principal != nil { - return principal.Subject - } - return "" -} -func authorizeExplorerWrite(c fiber.Ctx, authorizer authscope.Authorizer, project string) error { - path := authscope.NormalizeAuthResourcePath(strings.TrimSpace(c.Query("auth_resource_path"))) - if err := authorizer.AuthorizeWrite(c.Context(), principalFromFiber(c), project, path); err != nil { - return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") - } - return nil -} - -func explorerV2Error(c fiber.Ctx, status int, code, message string) error { - return c.Status(status).JSON(fiber.Map{"error": fiber.Map{"code": code, "message": message}}) -} - -func explorerV2ErrorFromCause(c fiber.Ctx, status int, code string, cause error) error { - var repairErr *explorer.PresentationRepairError - if errors.As(cause, &repairErr) { - diagnostic := repairErr.Diagnostic - if diagnostic.RequestID == "" { - diagnostic.RequestID = requestIDFromFiber(c) - } - return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{ - "error": fiber.Map{"code": diagnostic.Code, "message": diagnostic.Message, "fieldPath": diagnostic.FieldPath, "details": diagnostic.Details, "requestId": diagnostic.RequestID}, - "diagnostics": []explorer.Diagnostic{diagnostic}, - }) - } - return explorerV2Error(c, status, code, cause.Error()) -} - -func explorerV2ErrorWithDetails(c fiber.Ctx, status int, code, message string, details any) error { - body := fiber.Map{"code": code, "message": message, "details": details} - if status == http.StatusServiceUnavailable || status == http.StatusConflict { - body["retryable"] = true - } - if requestID, _ := c.Locals("request_id").(string); requestID != "" { - body["requestId"] = requestID - } - return c.Status(status).JSON(fiber.Map{"error": body}) -} - -// publicExplorerPublishDetails keeps operational causes in structured logs -// while returning only stable, actionable fields to the Builder. In -// particular, raw AQL, SQL, and storage errors must not become UI copy. -func publicExplorerPublishDetails(details any) any { - values, ok := details.(fiber.Map) - if !ok { - return details - } - public := make(fiber.Map, len(values)) - for key, value := range values { - if key == "cause" || key == "retryable" { - continue - } - public[key] = value - } - return public -} - -func draftConflictResponse(c fiber.Ctx, explorers *explorer.Service, project, id string) error { - current, err := explorers.Get(c.Context(), project, id) - if err != nil { - return explorerV2Error(c, http.StatusConflict, "DRAFT_CONFLICT", "Explorer draft changed; refresh before saving") - } - return c.Status(http.StatusConflict).JSON(fiber.Map{"error": fiber.Map{"code": "DRAFT_CONFLICT", "message": "Explorer draft changed; refresh before saving", "currentVersion": current.DraftVersion, "currentDigest": current.DraftDigest, "updatedAt": current.UpdatedAt.UTC().Format(time.RFC3339Nano)}}) -} - -func verifyExpectedVersion(ctx context.Context, service *explorer.Service, project, id string, expected *int64) error { - if expected == nil { - return nil - } - current, err := service.Get(ctx, project, id) - if errors.Is(err, explorer.ErrNotFound) { - return &v2HTTPError{status: http.StatusNotFound, code: "EXPLORER_NOT_FOUND", message: "Explorer not found"} - } - if err != nil { - return err - } - if current.DraftVersion != *expected { - return &v2HTTPError{status: http.StatusConflict, code: "DRAFT_CONFLICT", message: "Explorer draft changed; refresh before compiling", current: current} - } - return nil -} - -func verifyExpectedDigest(ctx context.Context, service *explorer.Service, project, id, expected string) error { - current, err := service.Get(ctx, project, id) - if errors.Is(err, explorer.ErrNotFound) { - return &v2HTTPError{status: http.StatusNotFound, code: "EXPLORER_NOT_FOUND", message: "Explorer not found"} - } - if err != nil { - return err - } - if current.DraftDigest != expected { - return &v2HTTPError{status: http.StatusConflict, code: "DRAFT_CONFLICT", message: "Explorer draft changed; refresh before previewing", current: current} - } - return nil -} - -type v2HTTPError struct { - status int - code, message string - current *explorer.Explorer -} - -func (e *v2HTTPError) Error() string { return e.message } - -func compileExplorerV2(ctx context.Context, compiler ExplorerV2Compiler, request ExplorerV2CompileRequest) (ExplorerV2CompileResult, string, error) { - management := explorer.ConfigManagementForID(request.ExplorerID) - _, bundle, canonical, digest, err := explorer.CanonicalConfigV2(request.Config, request.Project, request.ExplorerID, management) - if err != nil { - return ExplorerV2CompileResult{}, digest, err - } - if compiler != nil { - result, err := compiler(ctx, request) - if err != nil { - return ExplorerV2CompileResult{}, digest, err - } - if len(result.Config) == 0 { - result.Config = canonical - } - if _, _, normalized, normalizedDigest, err := explorer.CanonicalConfigV2(result.Config, request.Project, request.ExplorerID, management); err != nil { - return ExplorerV2CompileResult{}, digest, err - } else { - result.Config = normalized - digest = normalizedDigest - } - for index := range result.Diagnostics { - if result.Diagnostics[index].RequestID == "" { - result.Diagnostics[index].RequestID = request.RequestID - } - } - if result.Bundle.Name == "" { - result.Bundle = bundle - } - if result.RecipeDigest == "" { - result.RecipeDigest, err = result.Bundle.Digest() - if err != nil { - return ExplorerV2CompileResult{}, digest, err - } - } - return result, digest, nil - } - return ExplorerV2CompileResult{Config: canonical, Bundle: bundle, RecipeDigest: mustBundleDigest(bundle)}, digest, nil -} - -func mustBundleDigest(bundle recipe.Bundle) string { digest, _ := bundle.Digest(); return digest } - -func previewFailure(c fiber.Ctx, digest string, err error) error { - var repairErr *explorer.PresentationRepairError - if errors.As(err, &repairErr) { - diagnostic := repairErr.Diagnostic - if diagnostic.RequestID == "" { - diagnostic.RequestID = requestIDFromFiber(c) - } - return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"outputColumns": []string{}, "rows": []map[string]any{}, "rowCount": 0, "digest": digest, "diagnostics": []explorer.Diagnostic{diagnostic}}) - } - return c.Status(http.StatusUnprocessableEntity).JSON(fiber.Map{"outputColumns": []string{}, "rows": []map[string]any{}, "rowCount": 0, "digest": digest, "diagnostics": []explorer.Diagnostic{{Severity: "ERROR", Code: "PREVIEW_FAILED", Message: err.Error()}}}) -} - -func bundleHasOutput(bundle recipe.Bundle, name string) bool { - if name == "" { - return len(bundle.Outputs) > 0 - } - for _, output := range bundle.Outputs { - if output.Name == name { - return true - } - } - return false -} - -func columnsForOutput(result ExplorerV2CompileResult, output string) []string { - var columns []string - for _, column := range result.EmittedColumns { - if column.OutputID == output { - columns = append(columns, column.PublicColumn) - } - } - if len(columns) > 0 { - return columns - } - for _, item := range result.Bundle.Outputs { - if item.Name != output { - continue - } - for _, field := range item.Fields { - columns = append(columns, field.Name) - } - } - return columns -} - -func emittedColumnsByOutput(value explorer.Explorer) map[string]map[string]bool { - columns := make(map[string]map[string]bool) - for _, emitted := range value.EmittedColumns { - if emitted.OutputID == "" || emitted.PublicColumn == "" { - continue - } - if columns[emitted.OutputID] == nil { - columns[emitted.OutputID] = make(map[string]bool) - } - columns[emitted.OutputID][emitted.PublicColumn] = true - } - if len(columns) != 0 { - return columns - } - for _, output := range value.Dataset.Outputs { - if output.Name == "" { - continue - } - if columns[output.Name] == nil { - columns[output.Name] = make(map[string]bool) - } - for _, column := range output.Columns { - if column.Name != "" { - columns[output.Name][column.Name] = true - } - } - } - return columns -} - -func verifyQueryableOutputs(bundle recipe.Bundle, execution graphresolver.RecipeExecution) error { - states := map[string]string{} - for _, output := range execution.Outputs { - states[output.Name] = strings.ToUpper(output.State) - } - for _, output := range bundle.Outputs { - state := states[output.Name] - if state != "PUBLISHED" && state != "READY" && state != "ACTIVE" { - return fmt.Errorf("output %q is not queryable (state %q)", output.Name, state) - } - } - return nil -} - -func executionMaterializations(bundle recipe.Bundle, execution graphresolver.RecipeExecution) []explorer.Materialization { - result := make([]explorer.Materialization, 0, len(execution.Outputs)) - for _, output := range execution.Outputs { - result = append(result, explorer.Materialization{OutputID: output.Name, Output: output.Name, MaterializationID: execution.ID, Selector: explorerOutputSelector(bundle, output.Name), Columns: append([]publication.PhysicalColumn(nil), output.Columns...)}) - } - return result -} - -func insertFailedV2Revision(ctx context.Context, service *explorer.Service, owner *explorer.Explorer, config []byte, digest, generation, actor string, diagnostics []explorer.Diagnostic) error { - _, err := service.InsertFailedRevisionV2(ctx, owner, config, digest, generation, actor, diagnostics) - return err -} - -func blankExplorerConfigV2(project, id, title string) []byte { - bundle := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "explorer_" + id, TranslationVersion: "interactive", Outputs: []recipe.Output{{Name: "DocumentReference", RootResourceType: "DocumentReference", RowGrain: "document_reference", Fields: []recipe.Field{{Name: "id", FieldRef: "DocumentReference.id", Expr: recipe.Expression{Select: "root.id"}}}}}} - recipeRaw, _ := json.Marshal(bundle) - cfg := explorer.ConfigV2{APIVersion: explorer.ConfigV2APIVersion, Kind: "ExplorerConfig", Project: project, Explorer: explorer.ConfigExplorer{ID: id, Title: title, Management: "interactive"}, Recipe: recipeRaw, Views: []explorer.ConfigView{{ID: "document-reference", Title: title, Output: "DocumentReference", Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "id", Label: "ID", Visible: true}}}}}} - raw, _ := json.Marshal(cfg) - return raw -} - -func forkRepositoryConfig(raw []byte, project, id, title string) ([]byte, error) { - cfg, bundle, err := explorer.DecodeDefaultConfigV2(raw, project) - if err != nil { - return nil, err - } - cfg.Explorer.ID, cfg.Explorer.Title, cfg.Explorer.Management = id, title, "interactive" - cfg.Views = make([]explorer.ConfigView, 0, len(bundle.Outputs)) - for _, output := range bundle.Outputs { - columns := make([]explorer.ConfigColumn, 0, len(output.Fields)) - for _, field := range output.Fields { - columns = append(columns, explorer.ConfigColumn{Column: field.Name, Label: field.Name, Visible: true}) - } - if len(columns) == 0 { - continue - } - cfg.Views = append(cfg.Views, explorer.ConfigView{ID: explorer.StableExplorerID(output.Name), Title: output.Name, Output: output.Name, Table: explorer.ConfigTable{Columns: columns}}) - } - if len(cfg.Views) == 0 { - return nil, fmt.Errorf("repository baseline has no executable output fields to seed a custom Explorer") - } - return json.Marshal(cfg) -} - -func getExplorerV2State(ctx context.Context, service *explorer.Service, project, id string) (*explorerV2State, error) { - value, err := service.Get(ctx, project, id) - if err == nil { - var repairDiagnostics []explorer.Diagnostic - if repaired, diagnostics, repairErr := repairExplorerDraftOnLoad(ctx, service, value); repairErr == nil { - value, repairDiagnostics = repaired, diagnostics - } - state := stateFromExplorer(value) - if value.ActiveRevisionID != "" { - if revision, revisionErr := service.Revision(ctx, value.ActiveRevisionID); revisionErr == nil { - state = mergeRevisionState(state, revision) - } - } - state.Diagnostics = append(state.Diagnostics, repairDiagnostics...) - state = repairActiveExplorerPresentation(state) - return state, nil - } - if id != "default" || !errors.Is(err, explorer.ErrNotFound) { - return nil, err - } - repository, repositoryErr := service.RepositoryConfig(ctx, project) - if repositoryErr != nil { - return nil, repositoryErr - } - digest := repository.ConfigDigest - if digest == "" { - _, _, _, digest, _ = explorer.CanonicalConfigV2(repository.Config, project, "default", "repository") - } - version := repository.DraftVersion - if version == 0 { - version = 1 - } - state := &explorerV2State{Project: project, ExplorerID: "default", Title: configV2Title(repository.Config), Management: explorer.ManagementRepository, BaselineConfig: repositoryBaselineConfig(repository.Config), DraftConfig: cloneRaw(repository.Config), DraftVersion: version, DraftDigest: digest, ActiveConfig: cloneRaw(repository.Config), ActiveRevisionID: repository.ActiveRevisionID, SourceGeneration: repository.SourceGeneration, Materializations: repository.Materializations, Dataset: repository.Dataset, Publication: repository.Publication, Diagnostics: repository.Diagnostics, PublicationState: repository.Publication.State, ActiveURL: explorerURL(project, "default"), UpdatedAt: repository.UpdatedAt} - return repairActiveExplorerPresentation(state), nil -} - -func repairExplorerDraftOnLoad(ctx context.Context, service *explorer.Service, value *explorer.Explorer) (*explorer.Explorer, []explorer.Diagnostic, error) { - if value == nil || len(value.DraftConfig) == 0 { - return value, nil, nil - } - available := emittedColumnsByOutput(*value) - if len(available) == 0 { - return value, nil, nil - } - cfg, _, _, _, err := explorer.CanonicalConfigV2(value.DraftConfig, value.Project, value.ExplorerID, explorer.ConfigManagementForID(value.ExplorerID)) - if err != nil { - return value, nil, nil - } - repaired, diagnostics, repairErr := explorer.RepairConfigV2Presentation(cfg, available) - if repairErr != nil || len(diagnostics) == 0 { - return value, nil, repairErr - } - raw, err := json.Marshal(repaired) - if err != nil { - return value, nil, err - } - _, _, canonical, _, err := explorer.CanonicalConfigV2(raw, value.Project, value.ExplorerID, explorer.ConfigManagementForID(value.ExplorerID)) - if err != nil { - return value, nil, err - } - saved, err := service.SaveDraftV2(ctx, value.Project, value.ExplorerID, canonical, value.DraftVersion, value.DraftDigest, "loom-presentation-repair") - if err != nil { - return value, nil, err - } - return saved, diagnostics, nil -} - -func repairActiveExplorerPresentation(state *explorerV2State) *explorerV2State { - if state == nil || len(state.ActiveConfig) == 0 { - return state - } - available := make(map[string]map[string]bool) - for _, emitted := range state.EmittedColumns { - if emitted.OutputID == "" || emitted.PublicColumn == "" { - continue - } - if available[emitted.OutputID] == nil { - available[emitted.OutputID] = make(map[string]bool) - } - available[emitted.OutputID][emitted.PublicColumn] = true - } - if len(available) == 0 { - for _, output := range state.Dataset.Outputs { - if output.Name == "" { - continue - } - if available[output.Name] == nil { - available[output.Name] = make(map[string]bool) - } - for _, column := range output.Columns { - if column.Name != "" { - available[output.Name][column.Name] = true - } - } - } - } - if len(available) == 0 { - return state - } - cfg, _, _, _, err := explorer.CanonicalConfigV2(state.ActiveConfig, state.Project, state.ExplorerID, explorer.ConfigManagementForID(state.ExplorerID)) - if err != nil { - return state - } - repaired, diagnostics, repairErr := explorer.RepairConfigV2Presentation(cfg, available) - if repairErr != nil { - var presentationErr *explorer.PresentationRepairError - if errors.As(repairErr, &presentationErr) { - state.Diagnostics = append(state.Diagnostics, presentationErr.Diagnostic) - } - return state - } - if len(diagnostics) == 0 { - return state - } - raw, err := json.Marshal(repaired) - if err != nil { - return state - } - state.ActiveConfig = raw - state.Diagnostics = append(state.Diagnostics, diagnostics...) - return state -} - -func listExplorerV2States(ctx context.Context, service *explorer.Service, project string) ([]*explorerV2State, error) { - ids := map[string]bool{"default": true} - values, err := service.List(ctx, project) - if err != nil { - return nil, err - } - for _, value := range values { - ids[value.ExplorerID] = true - } - configs, configErr := service.ListConfigs(ctx, project) - if configErr == nil { - for _, value := range configs { - // RepositoryConfig rows are compatibility/readiness records. Custom - // identities are owned by loom_explorers; accepting arbitrary legacy - // config IDs here recreates the orphan-row 500 failure mode. - if value.ExplorerID == "default" { - ids["default"] = true - } - } - } - ordered := make([]string, 0, len(ids)) - for id := range ids { - ordered = append(ordered, id) - } - sort.Slice(ordered, func(i, j int) bool { - if ordered[i] == "default" { - return true - } - if ordered[j] == "default" { - return false - } - return ordered[i] < ordered[j] - }) - result := make([]*explorerV2State, 0, len(ordered)) - for _, id := range ordered { - state, err := getExplorerV2State(ctx, service, project, id) - if errors.Is(err, explorer.ErrNotFound) && id == "default" { - continue - } - if err != nil { - return nil, err - } - result = append(result, state) - } - return result, nil -} - -func stateFromExplorer(value *explorer.Explorer) *explorerV2State { - project := projectid.Canonical(value.Project) - if value.ManagementMode == explorer.ManagementRepository { - return &explorerV2State{Project: project, ExplorerID: value.ExplorerID, Title: value.Title, Management: value.ManagementMode, BaselineConfig: repositoryBaselineConfig(value.DraftConfig), DraftConfig: cloneRaw(value.DraftConfig), DraftVersion: value.DraftVersion, DraftDigest: value.DraftDigest, ActiveConfig: cloneRaw(value.ActiveConfig), ActiveRevisionID: value.ActiveRevisionID, RecipeDigest: value.RecipeDigest, ResolvedSchemaDigest: value.ResolvedSchemaDigest, SourceGeneration: value.SourceGeneration, EmittedColumns: append([]explorer.EmittedColumn(nil), value.EmittedColumns...), Materializations: append([]explorer.Materialization(nil), value.Materializations...), Dataset: value.Dataset, Publication: value.Publication, Diagnostics: append([]explorer.Diagnostic(nil), value.Diagnostics...), PublicationState: value.Publication.State, ActiveURL: explorerURL(project, value.ExplorerID), UpdatedBy: value.UpdatedBy, UpdatedAt: value.UpdatedAt} - } - return &explorerV2State{Project: project, ExplorerID: value.ExplorerID, Title: value.Title, Management: value.ManagementMode, DraftConfig: cloneRaw(value.DraftConfig), DraftVersion: value.DraftVersion, DraftDigest: value.DraftDigest, ActiveConfig: cloneRaw(value.ActiveConfig), ActiveRevisionID: value.ActiveRevisionID, RecipeDigest: value.RecipeDigest, ResolvedSchemaDigest: value.ResolvedSchemaDigest, SourceGeneration: value.SourceGeneration, EmittedColumns: append([]explorer.EmittedColumn(nil), value.EmittedColumns...), Materializations: append([]explorer.Materialization(nil), value.Materializations...), Dataset: value.Dataset, Publication: value.Publication, Diagnostics: append([]explorer.Diagnostic(nil), value.Diagnostics...), PublicationState: publicationState(value.ActiveRevisionID), ActiveURL: explorerURL(project, value.ExplorerID), UpdatedBy: value.UpdatedBy, UpdatedAt: value.UpdatedAt} -} - -func mergeRevisionState(state *explorerV2State, revision *explorer.Revision) *explorerV2State { - state.ActiveConfig = cloneRaw(revision.Config) - state.ActiveAuthoringBundle = cloneOptionalRaw(revision.AuthoringBundle) - state.ActiveIntentDigest = revision.IntentDigest - state.RecipeDigest, state.ResolvedSchemaDigest, state.SourceGeneration = revision.RecipeDigest, revision.ResolvedSchemaDigest, revision.SourceGeneration - state.EmittedColumns, state.Diagnostics = append([]explorer.EmittedColumn(nil), revision.EmittedColumns...), append([]explorer.Diagnostic(nil), revision.Diagnostics...) - state.Materializations, state.Dataset = explorer.WithDataframeSelectors(revision.Recipe, revision.Materializations, revision.Dataset) - state.Publication = revision.Publication - state.Publication.State, state.Publication.RevisionID = string(revision.Status), revision.ID - state.PublicationState = string(revision.Status) - return state -} -func publicationState(id string) string { - if id == "" { - return "" - } - return string(explorer.RevisionActive) -} -func explorerURL(project, id string) string { - return "/api/v1/projects/" + url.PathEscape(project) + "/explorers/" + url.PathEscape(id) -} -func cloneRaw(raw json.RawMessage) json.RawMessage { - if len(raw) == 0 { - return json.RawMessage("null") - } - return append(json.RawMessage(nil), raw...) -} - -func cloneOptionalRaw(raw json.RawMessage) json.RawMessage { - if len(raw) == 0 || strings.TrimSpace(string(raw)) == "" || strings.TrimSpace(string(raw)) == "null" { - return nil - } - return append(json.RawMessage(nil), raw...) -} - -func stateV1FromExplorerV2State(state *explorerV2State) explorer.ExplorerStateV1 { - result := explorer.ExplorerStateV1{ - APIVersion: explorer.ExplorerStateV1APIVersion, - Kind: explorer.ExplorerStateV1Kind, - Project: state.Project, - ExplorerID: state.ExplorerID, - Title: state.Title, - Management: state.Management, - ActiveURL: state.ActiveURL, - UpdatedBy: state.UpdatedBy, - UpdatedAt: state.UpdatedAt, - } - result.Draft = explorer.ExplorerStateV1Draft{ - Bundle: nil, - Version: state.DraftVersion, - Digest: state.DraftDigest, - IntentDigest: "", - ReceiptID: "", - } - result.Active = explorer.ExplorerStateV1Active{ - Bundle: canonicalAuthoringBundle(state.ActiveAuthoringBundle), - RevisionID: state.ActiveRevisionID, - IntentDigest: state.ActiveIntentDigest, - Status: state.Publication.State, - } - result.Generated = explorer.ExplorerStateV1Generated{ - RecipeDigest: state.RecipeDigest, - ResolvedSchemaDigest: state.ResolvedSchemaDigest, - SourceGeneration: state.SourceGeneration, - EmittedColumns: append([]explorer.EmittedColumn(nil), state.EmittedColumns...), - Materializations: append([]explorer.Materialization(nil), state.Materializations...), - Dataset: state.Dataset, - Publication: state.Publication, - Diagnostics: append([]explorer.Diagnostic(nil), state.Diagnostics...), - } - result.Runtime = runtimeV1FromExplorerV2State(state) - return result -} - -type runtimeProjectionState struct { - ActiveConfig json.RawMessage - SourceGeneration string - ResolvedSchemaDigest string - EmittedColumns []explorer.EmittedColumn - Materializations []explorer.Materialization - Dataset explorer.DatasetMetadata - Publication explorer.PublicationMetadata - Diagnostics []explorer.Diagnostic -} - -func runtimeV1FromPublishedRevision(revision *explorer.Revision) *explorer.ExplorerRuntimeV1 { - if revision == nil { - return nil - } - return runtimeV1FromProjection(runtimeProjectionState{ - ActiveConfig: revision.Config, - SourceGeneration: revision.SourceGeneration, - ResolvedSchemaDigest: revision.ResolvedSchemaDigest, - EmittedColumns: revision.EmittedColumns, - Materializations: revision.Materializations, - Dataset: revision.Dataset, - Publication: revision.Publication, - Diagnostics: revision.Diagnostics, - }) -} - -// runtimeV1FromExplorerV2State is retained only for legacy lifecycle tests and -// migration helpers. Registered runtime reads use runtimeV1FromPublishedRevision. -func runtimeV1FromExplorerV2State(legacy *explorerV2State) *explorer.ExplorerRuntimeV1 { - if legacy == nil { - return nil - } - return runtimeV1FromProjection(runtimeProjectionState{ - ActiveConfig: legacy.ActiveConfig, - SourceGeneration: legacy.SourceGeneration, - ResolvedSchemaDigest: legacy.ResolvedSchemaDigest, - EmittedColumns: legacy.EmittedColumns, - Materializations: legacy.Materializations, - Dataset: legacy.Dataset, - Publication: legacy.Publication, - Diagnostics: legacy.Diagnostics, - }) -} - -func runtimeV1FromProjection(state runtimeProjectionState) *explorer.ExplorerRuntimeV1 { - if len(state.ActiveConfig) == 0 { - return nil - } - var config explorer.ConfigV2 - if err := json.Unmarshal(state.ActiveConfig, &config); err != nil || len(config.Views) == 0 { - return nil - } - recipeLabels := explorerRecipeColumnLabels(config.Recipe) - - datasetOutputs := make(map[string]explorer.DatasetOutput, len(state.Dataset.Outputs)) - physicalColumns := make(map[string]map[string]publication.PhysicalColumn, len(state.Dataset.Outputs)) - for _, output := range state.Dataset.Outputs { - datasetOutputs[output.Name] = output - physicalColumns[output.Name] = make(map[string]publication.PhysicalColumn, len(output.Columns)) - for _, column := range output.Columns { - physicalColumns[output.Name][column.Name] = column - } - } - materializations := make(map[string]explorer.Materialization, len(state.Materializations)) - for _, materialization := range state.Materializations { - outputID := firstNonEmpty(materialization.OutputID, materialization.Output) - materializations[outputID] = materialization - if physicalColumns[outputID] == nil { - physicalColumns[outputID] = make(map[string]publication.PhysicalColumn, len(materialization.Columns)) - } - for _, column := range materialization.Columns { - physicalColumns[outputID][column.Name] = column - } - } - emittedColumns := make(map[string]map[string]explorer.EmittedColumn) - for _, emitted := range state.EmittedColumns { - if emitted.OutputID == "" || emitted.PublicColumn == "" { - continue - } - if emittedColumns[emitted.OutputID] == nil { - emittedColumns[emitted.OutputID] = make(map[string]explorer.EmittedColumn) - } - emittedColumns[emitted.OutputID][emitted.PublicColumn] = emitted - } - // Authoring emissions use stable logical names (c_), while the - // publication layer may qualify those names for the physical dataframe - // schema (for example patient_c_). Resolve that boundary from the - // authoritative published column list instead of asking the renderer to - // guess physical names. A suffix match is accepted only when it is - // unambiguous for the output. - publicToPhysical := make(map[string]map[string]string) - for outputID, emitted := range emittedColumns { - physical := physicalColumns[outputID] - if len(physical) == 0 { - continue - } - aliases := make(map[string]string) - for publicName, emission := range emitted { - logicalNames := []string{publicName} - // Authoring revisions compiled before PublicColumn was aligned with - // the lowered recipe field used an emission-derived hash here. The - // persisted candidate/occurrence identity still lets us recover the - // actual logical field name without rewriting durable state. - if emission.CandidateID != "" && emission.OccurrenceID != "" { - legacyLogicalName := generatedFieldName(emission.CandidateID, emission.OccurrenceID) - if legacyLogicalName != publicName { - logicalNames = append(logicalNames, legacyLogicalName) - } - } - matches := make([]string, 0, 1) - for physicalName := range physical { - for _, logicalName := range logicalNames { - if physicalName == logicalName || strings.HasSuffix(physicalName, "_"+logicalName) { - matches = append(matches, physicalName) - break - } - } - } - if len(matches) == 1 { - aliases[publicName] = matches[0] - } - } - if len(aliases) > 0 { - publicToPhysical[outputID] = aliases - } - } - - runtime := &explorer.ExplorerRuntimeV1{ - Generation: firstNonEmpty(state.Dataset.Generation, state.SourceGeneration, state.Publication.Generation), - Publication: state.Publication, - Schema: explorer.ExplorerRuntimeSchemaV1{Digest: firstNonEmpty(state.Dataset.SchemaDigest, state.ResolvedSchemaDigest), Version: explorer.ConfigV2APIVersion}, - Outputs: make([]explorer.ExplorerRuntimeOutputV1, 0, len(config.Views)), - SharedFilters: map[string][]explorer.ExplorerRuntimeBindingV1{}, - Diagnostics: append(make([]explorer.Diagnostic, 0, len(state.Diagnostics)), state.Diagnostics...), - } - emissionByOutputColumn := make(map[string]map[string]string) - // Seed the authoritative output/column identity map before walking views. - // Shared filters are allowed to target a valid emitted column that is not - // repeated in a table, filter, chart, or fixed-filter presentation binding. - // Keeping this map complete prevents those bindings from disappearing from - // the renderer projection. - for outputID, columns := range physicalColumns { - if emissionByOutputColumn[outputID] == nil { - emissionByOutputColumn[outputID] = map[string]string{} - } - for name := range columns { - emitted := emittedColumns[outputID][name] - if emitted.EmissionID == "" { - for publicName, physicalName := range publicToPhysical[outputID] { - if physicalName == name { - emitted = emittedColumns[outputID][publicName] - break - } - } - } - emissionID := emitted.EmissionID - if emissionID == "" { - emissionID = explorer.OpaqueID("em_", outputID+"\x00"+name) - } - emissionByOutputColumn[outputID][name] = emissionID - } - } - for _, view := range config.Views { - physicalNameFor := func(name string) string { - if aliases := publicToPhysical[view.Output]; aliases != nil { - if physicalName := aliases[name]; physicalName != "" { - return physicalName - } - } - return name - } - selector := (*dataset.DataframeSelector)(nil) - if output, ok := datasetOutputs[view.Output]; ok && output.Selector != nil { - copy := *output.Selector - selector = © - } else if materialization, ok := materializations[view.Output]; ok && materialization.Selector != nil { - copy := *materialization.Selector - selector = © - } - if selector == nil || selector.Validate() != nil { - return nil - } - - columnsByName := map[string]explorer.ExplorerRuntimeColumnV1{} - ensureColumn := func(name string) (explorer.ExplorerRuntimeColumnV1, bool) { - physicalName := physicalNameFor(name) - if column, ok := columnsByName[physicalName]; ok { - return column, true - } - physical, ok := physicalColumns[view.Output][physicalName] - if !ok { - // A compiled authoring emission is intent metadata. It is not - // queryable until the active materialization publishes the same - // physical column. Do not leak such a column into the runtime - // packet: the dataframe API correctly rejects it otherwise. - return explorer.ExplorerRuntimeColumnV1{}, false - } - emitted := emittedColumns[view.Output][name] - if emitted.PublicColumn == "" { - emitted = emittedColumns[view.Output][physicalName] - } - emissionID := emitted.EmissionID - if emissionID == "" { - emissionID = explorer.OpaqueID("em_", view.Output+"\x00"+name) - } - logicalType := firstNonEmpty(emitted.LogicalType, physical.LogicalType, physical.ClickHouse, "string") - filterable := emitted.Filterable - chartable := emitted.Chartable - if emitted.PublicColumn == "" { - filterable = !physical.Repeated - chartable = !physical.Repeated - } - label := recipeLabels[view.Output][name] - column := explorer.ExplorerRuntimeColumnV1{ - EmissionID: emissionID, Name: physicalName, Label: firstNonEmpty(label, physicalName), LogicalType: logicalType, - Repeated: physical.Repeated, Filterable: filterable, Sortable: !physical.Repeated, - Chartable: chartable, Aggregatable: filterable, - } - columnsByName[physicalName] = column - if emissionByOutputColumn[view.Output] == nil { - emissionByOutputColumn[view.Output] = map[string]string{} - } - emissionByOutputColumn[view.Output][physicalName] = emissionID - return column, true - } - - orderedNames := make([]string, 0, len(physicalColumns[view.Output])+len(emittedColumns[view.Output])) - seenNames := map[string]bool{} - appendName := func(name string) { - logicalName := name - physicalName := physicalNameFor(name) - if physicalName == "" || seenNames[physicalName] { - return - } - if _, ok := ensureColumn(logicalName); !ok { - return - } - seenNames[physicalName] = true - orderedNames = append(orderedNames, physicalName) - } - for _, binding := range view.Table.Columns { - appendName(binding.Column) - } - remainingNames := make([]string, 0, len(physicalColumns[view.Output])+len(emittedColumns[view.Output])) - for name := range physicalColumns[view.Output] { - if !seenNames[name] { - remainingNames = append(remainingNames, name) - } - } - for name := range emittedColumns[view.Output] { - if !seenNames[name] { - remainingNames = append(remainingNames, name) - } - } - sort.Strings(remainingNames) - for _, name := range remainingNames { - appendName(name) - } - - table := explorer.ExplorerRuntimeTableV1{Columns: make([]explorer.ExplorerRuntimeTableColumnV1, 0, len(view.Table.Columns))} - for index, binding := range view.Table.Columns { - column, ok := ensureColumn(binding.Column) - if !ok { - continue - } - label := binding.Label - if label == "" || label == binding.Column || label == physicalNameFor(binding.Column) { - label = recipeLabels[view.Output][binding.Column] - } - column.Label = firstNonEmpty(label, column.Label, binding.Column) - column.Visible = binding.Visible - column.Order = index - columnsByName[physicalNameFor(binding.Column)] = column - table.Columns = append(table.Columns, explorer.ExplorerRuntimeTableColumnV1{EmissionID: column.EmissionID, Visible: binding.Visible}) - } - filters := make([]explorer.ExplorerRuntimeBindingV1, 0, len(view.Filters)) - for _, binding := range view.Filters { - column, ok := ensureColumn(binding.Column) - if !ok { - continue - } - filters = append(filters, explorer.ExplorerRuntimeBindingV1{EmissionID: column.EmissionID, OutputID: view.Output, Label: firstNonEmpty(binding.Label, column.Label)}) - } - charts := make([]explorer.ExplorerRuntimeBindingV1, 0, len(view.Charts)) - for _, binding := range view.Charts { - column, ok := ensureColumn(binding.Column) - if !ok { - continue - } - charts = append(charts, explorer.ExplorerRuntimeBindingV1{EmissionID: column.EmissionID, OutputID: view.Output, Type: binding.Type, Title: binding.Title}) - } - fixedFilters := make(map[string][]string, len(view.FixedFilters)) - for columnName, values := range view.FixedFilters { - column, ok := ensureColumn(columnName) - if !ok { - continue - } - fixedFilters[column.EmissionID] = append([]string(nil), values...) - } - columns := make([]explorer.ExplorerRuntimeColumnV1, 0, len(orderedNames)) - for index, name := range orderedNames { - column := columnsByName[name] - if index >= len(view.Table.Columns) { - column.Order = index - } - columns = append(columns, column) - } - // A migrated legacy view can legitimately have no surviving presentation - // bindings (for example when its old field names no longer match the - // published physical schema). Keep the renderer usable in that case by - // projecting every published column into the table. Explicit table - // bindings still win, including an intentionally hidden table. - if len(view.Table.Columns) == 0 { - table.Columns = make([]explorer.ExplorerRuntimeTableColumnV1, 0, len(columns)) - order := 0 - for index := range columns { - if runtimeColumnIsInternal(columns[index].Name) { - continue - } - columns[index].Visible = true - columns[index].Order = order - table.Columns = append(table.Columns, explorer.ExplorerRuntimeTableColumnV1{EmissionID: columns[index].EmissionID, Visible: true}) - order++ - } - } - output := explorer.ExplorerRuntimeOutputV1{ - OutputID: view.Output, Name: firstNonEmpty(view.ID, view.Output), Title: view.Title, - RowLabel: firstNonEmpty(view.RowLabel, view.Title), Selector: *selector, Columns: columns, - Table: table, Filters: filters, Charts: charts, FixedFilters: fixedFilters, - } - if materialization, ok := materializations[view.Output]; ok { - copy := materialization - output.Materialization = © - } - runtime.Outputs = append(runtime.Outputs, output) - } - for name, filters := range config.SharedFilters { - bindings := make([]explorer.ExplorerRuntimeBindingV1, 0, len(filters)) - for _, filter := range filters { - columnName := filter.Column - if aliases := publicToPhysical[filter.Output]; aliases != nil { - if physicalName := aliases[columnName]; physicalName != "" { - columnName = physicalName - } - } - emissionID := emissionByOutputColumn[filter.Output][columnName] - if emissionID == "" { - continue - } - bindings = append(bindings, explorer.ExplorerRuntimeBindingV1{EmissionID: emissionID, OutputID: filter.Output}) - } - if len(bindings) > 0 { - runtime.SharedFilters[name] = bindings - } - } - return runtime -} - -func runtimeColumnIsInternal(name string) bool { - return name == "auth_resource_path" || strings.HasPrefix(name, "__loom_") -} - -func explorerRecipeColumnLabels(raw json.RawMessage) map[string]map[string]string { - labels := map[string]map[string]string{} - var bundle recipe.Bundle - if len(raw) == 0 || json.Unmarshal(raw, &bundle) != nil { - return labels - } - var collectFields func(string, []recipe.Field, []recipe.Traversal) - collectFields = func(output string, fields []recipe.Field, traversals []recipe.Traversal) { - if labels[output] == nil { - labels[output] = map[string]string{} - } - for _, field := range fields { - if field.Name == "" || field.FieldRef == "" { - continue - } - labels[output][field.Name] = humanizeExplorerFieldRef(field.FieldRef) - } - for _, traversal := range traversals { - collectFields(output, traversal.Fields, traversal.Traversals) - } - } - for _, output := range bundle.Outputs { - collectFields(output.Name, output.Fields, output.Traversals) - } - return labels -} - -func humanizeExplorerFieldRef(fieldRef string) string { - value := strings.TrimSpace(fieldRef) - if index := strings.IndexByte(value, '.'); index >= 0 && index+1 < len(value) { - value = value[index+1:] - } - var words []string - var current strings.Builder - flush := func() { - if current.Len() == 0 { - return - } - word := current.String() - lower := strings.ToLower(word) - switch lower { - case "id", "url", "uri", "uuid": - word = strings.ToUpper(lower) - default: - word = strings.ToUpper(word[:1]) + word[1:] - } - words = append(words, word) - current.Reset() - } - for index, char := range value { - if char == '.' || char == '_' || char == '-' || char == '[' || char == ']' { - flush() - continue - } - if index > 0 && char >= 'A' && char <= 'Z' && current.Len() > 0 { - flush() - } - current.WriteRune(char) - } - flush() - if len(words) == 0 { - return fieldRef - } - return strings.Join(words, " ") -} - -func canonicalAuthoringBundle(raw json.RawMessage) json.RawMessage { - if len(raw) == 0 { - return nil - } - bundle, err := explorer.DecodeAuthoringBundleV1ForMigration(raw) - if err != nil { - return nil - } - canonical, err := bundle.CanonicalJSON() - if err != nil { - return nil - } - return canonical -} - -func repositoryBaselineConfig(raw json.RawMessage) json.RawMessage { - var cfg explorer.ConfigV2 - if err := json.Unmarshal(raw, &cfg); err != nil { - return cloneRaw(raw) - } - cfg.Views = nil - cfg.SharedFilters = nil - cfg.FileActions = explorer.FileActions{} - baseline, err := json.Marshal(cfg) - if err != nil { - return cloneRaw(raw) - } - return baseline -} - -func configV2Title(raw json.RawMessage) string { - var cfg explorer.ConfigV2 - if err := json.Unmarshal(raw, &cfg); err != nil { - return "Default" - } - return cfg.Explorer.Title -} - -func stateErrorResponse(c fiber.Ctx, err error) error { - var httpErr *v2HTTPError - if errors.As(err, &httpErr) { - if httpErr.current != nil { - return c.Status(httpErr.status).JSON(fiber.Map{"error": fiber.Map{"code": httpErr.code, "message": httpErr.message, "currentVersion": httpErr.current.DraftVersion, "currentDigest": httpErr.current.DraftDigest, "updatedAt": httpErr.current.UpdatedAt.UTC().Format(time.RFC3339Nano)}}) - } - return explorerV2Error(c, httpErr.status, httpErr.code, httpErr.message) - } - return explorerV2Error(c, http.StatusInternalServerError, "EXPLORER_FAILED", err.Error()) -} diff --git a/internal/server/explorer_v2_lifecycle_test.go b/internal/server/explorer_v2_lifecycle_test.go deleted file mode 100644 index 032d6160..00000000 --- a/internal/server/explorer_v2_lifecycle_test.go +++ /dev/null @@ -1,877 +0,0 @@ -package server - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "io" - "net/http" - "net/http/httptest" - "strings" - "testing" - - graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" - "github.com/calypr/loom/internal/authscope" - "github.com/calypr/loom/internal/dataframe/publication" - "github.com/calypr/loom/internal/dataframe/recipe" - "github.com/calypr/loom/internal/dataset" - "github.com/calypr/loom/internal/explorer" - "github.com/gofiber/fiber/v3" -) - -func TestExplorerV2RESTLifecycle(t *testing.T) { - t.Skip("legacy ExplorerConfigV2 authoring routes removed by Builder cutover") - store := explorer.NewMemoryStore() - service, err := explorer.NewService(store) - if err != nil { - t.Fatal(err) - } - repository := baselineExplorerConfigV2("project-a", "Default") - var repositoryConfig explorer.ConfigV2 - if err := json.Unmarshal(repository, &repositoryConfig); err != nil { - t.Fatal(err) - } - repositoryConfig.Explorer.Management = "repository" - repositoryConfig.Views = []explorer.ConfigView{{ - ID: "document-reference", Title: "Documents", Output: "DocumentReference", - Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "id", Label: "ID", Visible: true}}}, - Filters: []explorer.ConfigFilter{{Column: "id", Label: "Identifier"}}, - Charts: []explorer.ConfigChart{{Column: "id", Type: "bar", Title: "Identifiers"}}, - FixedFilters: map[string][]string{"id": {"dr-1"}}, - }} - repositoryConfig.SharedFilters = map[string][]explorer.SharedFilter{"identifier": {{Output: "DocumentReference", Column: "id"}}} - repository, err = json.Marshal(repositoryConfig) - if err != nil { - t.Fatal(err) - } - repositorySelector := dataset.DataframeSelector{Recipe: "repository", TranslationVersion: "interactive", Output: "DocumentReference"} - repositoryMaterialization := explorer.Materialization{OutputID: "DocumentReference", Output: "DocumentReference", MaterializationID: "execution-a", Selector: &repositorySelector, Columns: []publication.PhysicalColumn{{Name: "id", LogicalType: "String"}}} - if _, err := service.SaveRepositoryConfig(context.Background(), explorer.RepositoryConfig{Project: "project-a", Config: repository, SourceGeneration: "generation-a", ExecutionID: "execution-a", Materializations: []explorer.Materialization{repositoryMaterialization}, Dataset: explorer.DatasetMetadata{Generation: "generation-a", Outputs: []explorer.DatasetOutput{{Name: "DocumentReference", State: "PUBLISHED", Queryable: true, Selector: &repositorySelector, Columns: repositoryMaterialization.Columns}}}, Publication: explorer.PublicationMetadata{State: "ACTIVE", Generation: "generation-a", ExecutionID: "execution-a"}}); err != nil { - t.Fatal(err) - } - repositoryBundle := testV2Bundle("repository") - bundle := testV2Bundle("explorer-custom") - compile := func(_ context.Context, request ExplorerV2CompileRequest) (ExplorerV2CompileResult, error) { - compiledBundle := bundle - if request.ExplorerID == "default" { - compiledBundle = repositoryBundle - } - digest, _ := compiledBundle.Digest() - return ExplorerV2CompileResult{Config: request.Config, Bundle: compiledBundle, RecipeDigest: digest, SourceGeneration: "generation-a", EmittedColumns: []explorer.EmittedColumn{{OutputID: "DocumentReference", PublicColumn: "id", SelectionID: "id", LogicalType: "string"}}}, nil - } - preview := func(_ context.Context, _ recipe.Bundle, _ recipe.RuntimeBindings) (map[string][]map[string]any, error) { - return map[string][]map[string]any{"DocumentReference": {{"id": "dr-1"}}}, nil - } - materializeFails := false - materialize := func(_ context.Context, _ recipe.Bundle, _ recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { - if materializeFails { - return graphresolver.RecipeExecution{}, errors.New("backend unavailable") - } - return graphresolver.RecipeExecution{ID: "execution-a", SourceGeneration: "generation-a", State: "PUBLISHED", Outputs: []graphresolver.RecipeExecutionOutput{{Name: "DocumentReference", State: "PUBLISHED"}}}, nil - } - var releaseActivations [][]dataset.DataframeSelector - releaseFails := false - activateRelease := func(_ context.Context, project, generation string, selectors []dataset.DataframeSelector) error { - if project != "project-a" || generation != "generation-a" { - t.Fatalf("release identity = %s/%s", project, generation) - } - if releaseFails { - return errors.New("release conflict") - } - releaseActivations = append(releaseActivations, append([]dataset.DataframeSelector(nil), selectors...)) - return nil - } - catalog := func(_ context.Context, project, _ string, _ string) (explorer.CatalogSnapshot, error) { - return explorer.NewCatalogSnapshot(project, "generation-a", "scope-a", explorer.Catalog{ - Nodes: []explorer.CatalogNode{{ID: "node-document-reference", ResourceType: "DocumentReference"}}, - Selections: map[string]explorer.CatalogSelection{ - "selection-id": {ID: "selection-id", NodeID: "node-document-reference", FieldRef: "DocumentReference.id", Select: "id", LogicalType: "string", Filterable: true}, - }, - }, true, false, nil) - } - app := fiber.New() - RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{Compile: compile, Catalog: catalog, Preview: preview, Materialize: materialize, ActivateRelease: activateRelease}) - - catalogResponse := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom-explorer/authoring/catalog", "") - if catalogResponse.StatusCode != http.StatusOK || !strings.Contains(catalogResponse.Body, `"snapshotToken":"sha256:`) || !strings.Contains(catalogResponse.Body, `"selectionId":"selection-id"`) { - t.Fatalf("catalog status=%d body=%s", catalogResponse.StatusCode, catalogResponse.Body) - } - - response := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers", `{"name":"Custom Explorer"}`) - if response.StatusCode != http.StatusCreated { - t.Fatalf("create status=%d body=%s", response.StatusCode, response.Body) - } - var created explorerV2State - decodeBody(t, response.Body, &created) - if created.ExplorerID != "custom-explorer" || created.Management != explorer.ManagementInteractive || created.DraftVersion != 1 { - t.Fatalf("created state=%#v", created) - } - - list := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers", "") - if list.StatusCode != http.StatusOK || !strings.Contains(list.Body, `"explorerId":"default"`) || !strings.Contains(list.Body, `"explorerId":"custom-explorer"`) { - t.Fatalf("list status=%d body=%s", list.StatusCode, list.Body) - } - var listed []explorer.ExplorerStateV1 - decodeBody(t, list.Body, &listed) - if len(listed) != 2 || listed[0].APIVersion != explorer.ExplorerStateV1APIVersion || listed[0].Kind != explorer.ExplorerStateV1Kind || strings.Contains(list.Body, `"draftConfig"`) || strings.Contains(list.Body, `"activeConfig"`) { - t.Fatalf("list state V1 mismatch: %#v body=%s", listed, list.Body) - } - var listedObjects []map[string]json.RawMessage - decodeBody(t, list.Body, &listedObjects) - for _, object := range listedObjects { - for _, key := range []string{"draftBundle", "draftVersion", "materializations", "publicationState", "draftConfig", "activeConfig"} { - if _, exists := object[key]; exists { - t.Fatalf("legacy top-level state field %q leaked from list response: %s", key, list.Body) - } - } - } - defaultResponse := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/default", "") - if defaultResponse.StatusCode != http.StatusOK { - t.Fatalf("default status=%d body=%s", defaultResponse.StatusCode, defaultResponse.Body) - } - var defaultState explorer.ExplorerStateV1 - decodeBody(t, defaultResponse.Body, &defaultState) - if defaultState.APIVersion != explorer.ExplorerStateV1APIVersion || defaultState.Kind != explorer.ExplorerStateV1Kind || defaultState.Title != "Default" || strings.Contains(defaultResponse.Body, `"draftConfig"`) || strings.Contains(defaultResponse.Body, `"activeConfig"`) { - t.Fatalf("default state V1 mismatch: %#v body=%s", defaultState, defaultResponse.Body) - } - if defaultState.Runtime == nil || len(defaultState.Runtime.Outputs) != 1 { - t.Fatalf("default runtime projection missing: %#v body=%s", defaultState.Runtime, defaultResponse.Body) - } - runtimeOutput := defaultState.Runtime.Outputs[0] - if runtimeOutput.OutputID != "DocumentReference" || runtimeOutput.Selector != repositorySelector || len(runtimeOutput.Columns) != 1 || runtimeOutput.Columns[0].Name != "id" || runtimeOutput.Columns[0].EmissionID == "" { - t.Fatalf("default runtime output mismatch: %#v", runtimeOutput) - } - if len(runtimeOutput.Table.Columns) != 1 || len(runtimeOutput.Filters) != 1 || len(runtimeOutput.Charts) != 1 || len(runtimeOutput.FixedFilters) != 1 || len(defaultState.Runtime.SharedFilters["identifier"]) != 1 { - t.Fatalf("default runtime presentation mismatch: %#v", defaultState.Runtime) - } - var defaultObject map[string]json.RawMessage - decodeBody(t, defaultResponse.Body, &defaultObject) - for _, key := range []string{"draftBundle", "draftVersion", "materializations", "publicationState", "draftConfig", "activeConfig"} { - if _, exists := defaultObject[key]; exists { - t.Fatalf("legacy top-level state field %q leaked from detail response: %s", key, defaultResponse.Body) - } - } - var defaultConfig explorer.ConfigV2 - decodeBody(t, string(repositoryBaselineConfig(repository)), &defaultConfig) - if len(defaultConfig.Views) != 0 { - t.Fatalf("default baseline contains views: %#v", defaultConfig.Views) - } - var activeDefaultConfig explorer.ConfigV2 - decodeBody(t, string(repository), &activeDefaultConfig) - if len(activeDefaultConfig.Views) != 1 || activeDefaultConfig.Views[0].Output != "DocumentReference" { - t.Fatalf("default active config lost presentation: %#v", activeDefaultConfig.Views) - } - var defaultDraft map[string]any - if err := json.Unmarshal(repository, &defaultDraft); err != nil { - t.Fatal(err) - } - defaultDraft["explorer"].(map[string]any)["title"] = "Edited Default" - defaultDraftBytes, _ := json.Marshal(defaultDraft) - defaultDraftRequest, _ := json.Marshal(map[string]any{"config": json.RawMessage(defaultDraftBytes), "expectedDraftVersion": defaultState.Draft.Version, "expectedDraftDigest": defaultState.Draft.Digest}) - defaultWrite := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/default/draft", string(defaultDraftRequest)) - if defaultWrite.StatusCode != http.StatusOK { - t.Fatalf("default draft write status=%d body=%s", defaultWrite.StatusCode, defaultWrite.Body) - } - var updatedDefault explorerV2State - decodeBody(t, defaultWrite.Body, &updatedDefault) - if updatedDefault.DraftVersion != defaultState.Draft.Version+1 || updatedDefault.DraftDigest == defaultState.Draft.Digest { - t.Fatalf("default draft state=%#v", updatedDefault) - } - defaultCompileRequest, _ := json.Marshal(map[string]any{"output": "DocumentReference", "config": json.RawMessage(updatedDefault.DraftConfig), "expectedDraftVersion": updatedDefault.DraftVersion}) - defaultCompiled := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/default/authoring/compile", string(defaultCompileRequest)) - if defaultCompiled.StatusCode != http.StatusOK { - t.Fatalf("default compile status=%d body=%s", defaultCompiled.StatusCode, defaultCompiled.Body) - } - defaultPublishRequest := `{"expectedDraftVersion":` + fmt.Sprint(updatedDefault.DraftVersion) + `,"expectedDraftDigest":"` + updatedDefault.DraftDigest + `"}` - defaultPublished := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/default/publish", defaultPublishRequest) - if defaultPublished.StatusCode != http.StatusOK || !strings.Contains(defaultPublished.Body, `"publicationId"`) { - t.Fatalf("default publish status=%d body=%s", defaultPublished.StatusCode, defaultPublished.Body) - } - if len(releaseActivations) != 0 { - t.Fatalf("configuration publish unexpectedly activated a dataset release: %#v", releaseActivations) - } - defaultAfterPublish := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/default", "") - var activeDefaultState explorer.ExplorerStateV1 - decodeBody(t, defaultAfterPublish.Body, &activeDefaultState) - defaultOwner, err := service.Get(context.Background(), "project-a", "default") - if defaultAfterPublish.StatusCode != http.StatusOK || activeDefaultState.Active.RevisionID == "" || string(defaultOwner.ActiveConfig) != string(defaultOwner.DraftConfig) { - t.Fatalf("default active state=%#v", activeDefaultState) - } - var draft map[string]any - if err := json.Unmarshal(created.DraftConfig, &draft); err != nil { - t.Fatal(err) - } - if len(draft["views"].([]any)) == 0 { - t.Fatalf("custom fork did not receive presentation views: %s", created.DraftConfig) - } - draftExplorer := draft["explorer"].(map[string]any) - draftExplorer["title"] = "Edited" - draftBytes, _ := json.Marshal(draft) - draftRequest, _ := json.Marshal(map[string]any{"config": json.RawMessage(draftBytes), "expectedDraftVersion": created.DraftVersion, "expectedDraftDigest": created.DraftDigest}) - saved := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/custom-explorer/draft", string(draftRequest)) - if saved.StatusCode != http.StatusOK { - t.Fatalf("draft status=%d body=%s", saved.StatusCode, saved.Body) - } - var updated explorerV2State - decodeBody(t, saved.Body, &updated) - if updated.DraftVersion != 2 || updated.DraftDigest == created.DraftDigest { - t.Fatalf("saved state=%#v", updated) - } - stale := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/custom-explorer/draft", string(draftRequest)) - if stale.StatusCode != http.StatusOK || !strings.Contains(stale.Body, `"draftVersion":3`) { - t.Fatalf("last-write-wins status=%d body=%s", stale.StatusCode, stale.Body) - } - - compileRequest, _ := json.Marshal(map[string]any{"output": "DocumentReference", "config": json.RawMessage(updated.DraftConfig), "expectedDraftVersion": updated.DraftVersion}) - compiled := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom-explorer/authoring/compile", string(compileRequest)) - if compiled.StatusCode != http.StatusOK || !strings.Contains(compiled.Body, `"recipeDigest"`) || !strings.Contains(compiled.Body, `"diagnostics":[]`) { - t.Fatalf("compile status=%d body=%s", compiled.StatusCode, compiled.Body) - } - - previewRequest, _ := json.Marshal(map[string]any{"config": json.RawMessage(updated.DraftConfig), "output": "DocumentReference", "limit": 25, "draftDigest": updated.DraftDigest}) - previewResponse := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom-explorer/preview", string(previewRequest)) - if previewResponse.StatusCode != http.StatusOK || !strings.Contains(previewResponse.Body, `"rowCount":1`) { - t.Fatalf("preview status=%d body=%s", previewResponse.StatusCode, previewResponse.Body) - } - beforePublish, err := service.ActiveRevision(context.Background(), "project-a", "custom-explorer") - if err != explorer.ErrNotFound { - t.Fatalf("active revision before publish=%v, want ErrNotFound", beforePublish) - } - - publishRequest := `{"expectedDraftVersion":2,"expectedDraftDigest":"` + updated.DraftDigest + `"}` - published := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom-explorer/publish", publishRequest) - if published.StatusCode != http.StatusOK || !strings.Contains(published.Body, `"publicationId"`) || !strings.Contains(published.Body, `"activeUrl"`) { - t.Fatalf("publish status=%d body=%s", published.StatusCode, published.Body) - } - if len(releaseActivations) != 0 { - t.Fatalf("custom configuration publish unexpectedly activated a dataset release: %#v", releaseActivations) - } - stateResponse := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom-explorer", "") - var active explorer.ExplorerStateV1 - decodeBody(t, stateResponse.Body, &active) - activeOwner, err := service.Get(context.Background(), "project-a", "custom-explorer") - if stateResponse.StatusCode != http.StatusOK || active.Active.RevisionID == "" || string(activeOwner.ActiveConfig) != string(activeOwner.DraftConfig) { - t.Fatalf("active state=%#v", active) - } - if len(active.Generated.Materializations) != 1 || active.Generated.Materializations[0].Selector == nil || active.Generated.Materializations[0].Selector.Recipe != "repository" { - t.Fatalf("configuration publish did not reuse the active dataset selector: %#v", active.Generated.Materializations) - } - priorActiveRevision := active.Active.RevisionID - releaseFails = true - draftExplorer["title"] = "Failed release draft" - draftBytes, _ = json.Marshal(draft) - draftRequest, _ = json.Marshal(map[string]any{"config": json.RawMessage(draftBytes), "expectedDraftVersion": active.Draft.Version, "expectedDraftDigest": active.Draft.Digest}) - failedReleaseDraft := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/custom-explorer/draft", string(draftRequest)) - if failedReleaseDraft.StatusCode != http.StatusOK { - t.Fatalf("failed release draft save status=%d body=%s", failedReleaseDraft.StatusCode, failedReleaseDraft.Body) - } - var failedReleaseState explorerV2State - decodeBody(t, failedReleaseDraft.Body, &failedReleaseState) - failedReleasePublish := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom-explorer/publish", `{"expectedDraftVersion":`+fmt.Sprint(failedReleaseState.DraftVersion)+`,"expectedDraftDigest":"`+failedReleaseState.DraftDigest+`"}`) - if failedReleasePublish.StatusCode != http.StatusOK { - t.Fatalf("configuration publish should not depend on release activation status=%d body=%s", failedReleasePublish.StatusCode, failedReleasePublish.Body) - } - unchangedAfterReleaseFailure := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom-explorer", "") - var releaseUnchanged explorer.ExplorerStateV1 - decodeBody(t, unchangedAfterReleaseFailure.Body, &releaseUnchanged) - if releaseUnchanged.Active.RevisionID == priorActiveRevision { - t.Fatalf("configuration publish did not activate independently of release state: %#v", releaseUnchanged) - } - - releaseFails = false - materializeFails = true - draftExplorer["title"] = "Failed publication draft" - draftBytes, _ = json.Marshal(draft) - draftRequest, _ = json.Marshal(map[string]any{"config": json.RawMessage(draftBytes), "expectedDraftVersion": failedReleaseState.DraftVersion, "expectedDraftDigest": failedReleaseState.DraftDigest}) - failedDraft := requestJSON(t, app, http.MethodPut, "/api/v1/projects/project-a/explorers/custom-explorer/draft", string(draftRequest)) - if failedDraft.StatusCode != http.StatusOK { - t.Fatalf("failed publication draft save status=%d body=%s", failedDraft.StatusCode, failedDraft.Body) - } - var failedDraftState explorerV2State - decodeBody(t, failedDraft.Body, &failedDraftState) - failedPublish := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom-explorer/publish", `{"expectedDraftVersion":`+fmt.Sprint(failedDraftState.DraftVersion)+`,"expectedDraftDigest":"`+failedDraftState.DraftDigest+`"}`) - if failedPublish.StatusCode != http.StatusOK { - t.Fatalf("configuration publish should not call materialization status=%d body=%s", failedPublish.StatusCode, failedPublish.Body) - } - unchangedResponse := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/custom-explorer", "") - var unchanged explorer.ExplorerStateV1 - decodeBody(t, unchangedResponse.Body, &unchanged) - if unchanged.Active.RevisionID == releaseUnchanged.Active.RevisionID { - t.Fatalf("materializer availability affected configuration activation: %#v", unchanged) - } -} - -func TestExplorerV2StateRepairsPersistedStalePresentation(t *testing.T) { - ctx := context.Background() - service, err := explorer.NewService(explorer.NewMemoryStore()) - if err != nil { - t.Fatal(err) - } - bundle := testV2Bundle("repair") - recipeRaw, err := json.Marshal(bundle) - if err != nil { - t.Fatal(err) - } - cfg := explorer.ConfigV2{ - APIVersion: explorer.ConfigV2APIVersion, - Kind: "ExplorerConfig", - Project: "project-a", - Explorer: explorer.ConfigExplorer{ID: "custom", Title: "Custom", Management: "interactive"}, - Recipe: recipeRaw, - Views: []explorer.ConfigView{{ - ID: "main", Title: "Main", Output: "DocumentReference", - Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "id"}, {Column: "category_coding_code"}}}, - }}, - } - raw, err := json.Marshal(cfg) - if err != nil { - t.Fatal(err) - } - owner, err := service.CreateInteractiveV2(ctx, "project-a", "custom", raw, "author") - if err != nil { - t.Fatal(err) - } - recipeDigest, err := bundle.Digest() - if err != nil { - t.Fatal(err) - } - revision, err := service.InsertReadyRevisionV2WithMetadata(ctx, owner, raw, "sha256:config", explorer.Compilation{ - Bundle: bundle, RecipeDigest: recipeDigest, - EmittedColumns: []explorer.EmittedColumn{{OutputID: "DocumentReference", PublicColumn: "id", SelectionID: "id", LogicalType: "string"}}, - }, "schema", "generation-a", "author", nil, explorer.DatasetMetadata{}, explorer.PublicationMetadata{State: string(explorer.RevisionReady), Generation: "generation-a"}) - if err != nil { - t.Fatal(err) - } - if err := service.ActivateInteractive(ctx, "project-a", "custom", revision.ID); err != nil { - t.Fatal(err) - } - state, err := getExplorerV2State(ctx, service, "project-a", "custom") - if err != nil { - t.Fatal(err) - } - var repaired explorer.ConfigV2 - if err := json.Unmarshal(state.DraftConfig, &repaired); err != nil { - t.Fatal(err) - } - if len(repaired.Views) != 1 || len(repaired.Views[0].Table.Columns) != 1 || repaired.Views[0].Table.Columns[0].Column != "id" { - t.Fatalf("draft presentation was not repaired: %#v", repaired.Views) - } - persisted, err := service.Get(ctx, "project-a", "custom") - if err != nil { - t.Fatal(err) - } - if strings.Contains(string(persisted.DraftConfig), "category_coding_code") { - t.Fatalf("repaired draft was not persisted: %s", persisted.DraftConfig) - } -} - -func TestActiveExplorerDatasetRequiresCanonicalReleaseMetadata(t *testing.T) { - bundle := testV2Bundle("explorer-custom") - candidate := activeExplorerDataset{ - Generation: "generation-a", - Dataset: explorer.DatasetMetadata{Outputs: []explorer.DatasetOutput{{Name: "DocumentReference", State: "PUBLISHED", Queryable: true}}}, - Materializations: []explorer.Materialization{{Output: "DocumentReference", MaterializationID: "execution-a"}}, - } - if activeExplorerDatasetSupports(candidate, bundle) { - t.Fatal("incomplete release metadata was accepted without canonical selectors") - } -} - -func TestOutputsNeedingMaterializationReusesUnchangedOutputs(t *testing.T) { - bundle := recipe.Bundle{Outputs: []recipe.Output{{Name: "Patient"}, {Name: "Specimen"}}} - patientSelector := dataset.DataframeSelector{Recipe: "explorer", TranslationVersion: "v1", Output: "Patient"} - specimenSelector := dataset.DataframeSelector{Recipe: "explorer", TranslationVersion: "v1", Output: "Specimen"} - active := activeExplorerDataset{ - Generation: "generation-a", - Dataset: explorer.DatasetMetadata{Generation: "generation-a", Outputs: []explorer.DatasetOutput{ - {Name: "Patient", State: "PUBLISHED", Queryable: true, Fingerprint: "patient-v1", Selector: &patientSelector}, - {Name: "Specimen", State: "PUBLISHED", Queryable: true, Fingerprint: "specimen-v1", Selector: &specimenSelector}, - }}, - Materializations: []explorer.Materialization{ - {Output: "Patient", MaterializationID: "execution-patient", Fingerprint: "patient-v1", Selector: &patientSelector}, - {Output: "Specimen", MaterializationID: "execution-specimen", Fingerprint: "specimen-v1", Selector: &specimenSelector}, - }, - } - changed := outputsNeedingMaterialization(bundle, active, "generation-a", map[string]string{"Patient": "patient-v1", "Specimen": "specimen-v2"}) - if len(changed) != 1 || changed[0].Name != "Specimen" { - t.Fatalf("changed outputs = %#v, want only Specimen", changed) - } -} - -func TestPublishBuildsMissingDatasetOutput(t *testing.T) { - t.Skip("legacy ExplorerConfigV2 publish route removed by Builder cutover") - store := explorer.NewMemoryStore() - service, err := explorer.NewService(store) - if err != nil { - t.Fatal(err) - } - repository := baselineExplorerConfigV2("project-a", "Default") - repositorySelector := dataset.DataframeSelector{Recipe: "repository", TranslationVersion: "interactive", Output: "DocumentReference"} - repositoryMaterialization := explorer.Materialization{OutputID: "DocumentReference", Output: "DocumentReference", MaterializationID: "execution-a", Selector: &repositorySelector, Columns: []publication.PhysicalColumn{{Name: "id", LogicalType: "String"}}} - if _, err := service.SaveRepositoryConfig(context.Background(), explorer.RepositoryConfig{ - Project: "project-a", Config: repository, SourceGeneration: "generation-a", ExecutionID: "execution-a", - Materializations: []explorer.Materialization{repositoryMaterialization}, - Dataset: explorer.DatasetMetadata{Generation: "generation-a", Outputs: []explorer.DatasetOutput{{Name: "DocumentReference", State: "PUBLISHED", Queryable: true, Selector: &repositorySelector, Columns: repositoryMaterialization.Columns}}}, - Publication: explorer.PublicationMetadata{State: "ACTIVE", Generation: "generation-a", ExecutionID: "execution-a"}, - }); err != nil { - t.Fatal(err) - } - missingBundle := testV2Bundle("explorer-custom") - missingBundle.Outputs[0].Name = "SubstanceDefinition" - missingBundle.Outputs[0].RootResourceType = "SubstanceDefinition" - missingBundle.Outputs[0].RowGrain = "substance_definition" - compile := func(_ context.Context, request ExplorerV2CompileRequest) (ExplorerV2CompileResult, error) { - digest, _ := missingBundle.Digest() - return ExplorerV2CompileResult{Config: request.Config, Bundle: missingBundle, RecipeDigest: digest, SourceGeneration: "generation-a", ResolvedSchemaDigest: "schema-a"}, nil - } - materializeCalls := 0 - var materializedOutputNames [][]string - materialize := func(_ context.Context, bundle recipe.Bundle, bindings recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { - materializeCalls++ - materializedOutputNames = append(materializedOutputNames, append([]string(nil), bindings.OutputNames...)) - outputs := make([]graphresolver.RecipeExecutionOutput, 0, len(bundle.Outputs)) - for _, output := range bundle.Outputs { - outputs = append(outputs, graphresolver.RecipeExecutionOutput{Name: output.Name, State: "PUBLISHED", Columns: []publication.PhysicalColumn{{Name: "id", LogicalType: "String"}}}) - } - return graphresolver.RecipeExecution{ID: "execution-substance", SourceGeneration: "generation-a", ResolvedSchemaDigest: "schema-substance", State: "PUBLISHED", Outputs: outputs}, nil - } - var releaseActivations [][]dataset.DataframeSelector - activateRelease := func(_ context.Context, project, generation string, selectors []dataset.DataframeSelector) error { - if project != "project-a" || generation != "generation-a" { - t.Fatalf("release identity = %s/%s", project, generation) - } - releaseActivations = append(releaseActivations, append([]dataset.DataframeSelector(nil), selectors...)) - return nil - } - app := fiber.New() - RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{Compile: compile, Materialize: materialize, ActivateRelease: activateRelease}) - created := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers", `{"name":"Needs Load","blank":true}`) - if created.StatusCode != http.StatusCreated { - t.Fatalf("create status=%d body=%s", created.StatusCode, created.Body) - } - published := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/needs-load/publish", `{}`) - if published.StatusCode != http.StatusOK || !strings.Contains(published.Body, `"publicationId"`) { - t.Fatalf("publish status=%d body=%s", published.StatusCode, published.Body) - } - if materializeCalls != 1 || len(releaseActivations) != 1 || len(releaseActivations[0]) != 1 || releaseActivations[0][0].Output != "SubstanceDefinition" { - t.Fatalf("build lifecycle calls=%d releases=%#v", materializeCalls, releaseActivations) - } - if len(materializedOutputNames) != 1 || len(materializedOutputNames[0]) != 1 || materializedOutputNames[0][0] != "SubstanceDefinition" { - t.Fatalf("materialized output selection = %#v", materializedOutputNames) - } - active, err := service.ActiveRevision(context.Background(), "project-a", "needs-load") - if err != nil { - t.Fatal(err) - } - if len(active.Materializations) != 1 || active.Materializations[0].Output != "SubstanceDefinition" || active.Materializations[0].Selector == nil { - t.Fatalf("active materializations=%#v", active.Materializations) - } - updatedRepository, err := service.RepositoryConfig(context.Background(), "project-a") - if err != nil { - t.Fatal(err) - } - if len(updatedRepository.Dataset.Outputs) != 2 || len(updatedRepository.Materializations) != 2 { - t.Fatalf("merged repository dataset=%#v materializations=%#v", updatedRepository.Dataset, updatedRepository.Materializations) - } -} - -func TestPublishUsesCompiledGenerationInsteadOfStaleRepositoryGeneration(t *testing.T) { - t.Skip("legacy ExplorerConfigV2 publish route removed by Builder cutover") - store := explorer.NewMemoryStore() - service, err := explorer.NewService(store) - if err != nil { - t.Fatal(err) - } - repository := baselineExplorerConfigV2("project-a", "Default") - oldSelector := dataset.DataframeSelector{Recipe: "repository", TranslationVersion: "interactive", Output: "DocumentReference"} - oldMaterialization := explorer.Materialization{OutputID: "DocumentReference", Output: "DocumentReference", MaterializationID: "execution-old", Selector: &oldSelector} - if _, err := service.SaveRepositoryConfig(context.Background(), explorer.RepositoryConfig{ - Project: "project-a", Config: repository, SourceGeneration: "generation-old", ExecutionID: "execution-old", - Materializations: []explorer.Materialization{oldMaterialization}, - Dataset: explorer.DatasetMetadata{Generation: "generation-old", Outputs: []explorer.DatasetOutput{{Name: "DocumentReference", State: "PUBLISHED", Queryable: true, Selector: &oldSelector}}}, - Publication: explorer.PublicationMetadata{State: "ACTIVE", Generation: "generation-old", ExecutionID: "execution-old"}, - }); err != nil { - t.Fatal(err) - } - bundle := testV2Bundle("explorer-custom") - compile := func(_ context.Context, request ExplorerV2CompileRequest) (ExplorerV2CompileResult, error) { - digest, _ := bundle.Digest() - return ExplorerV2CompileResult{Config: request.Config, Bundle: bundle, RecipeDigest: digest, SourceGeneration: "generation-new", ResolvedSchemaDigest: "schema-new", OutputFingerprints: map[string]string{"DocumentReference": "fingerprint-new"}}, nil - } - validatedGeneration := "" - validateGeneration := func(_ context.Context, project, generation string) error { - if project != "project-a" { - t.Fatalf("validated project = %q", project) - } - validatedGeneration = generation - return nil - } - materializedGeneration := "" - materialize := func(_ context.Context, _ recipe.Bundle, bindings recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { - materializedGeneration = bindings.DatasetGeneration - return graphresolver.RecipeExecution{ID: "execution-new", SourceGeneration: bindings.DatasetGeneration, ResolvedSchemaDigest: "schema-new", State: "PUBLISHED", Outputs: []graphresolver.RecipeExecutionOutput{{Name: "DocumentReference", State: "PUBLISHED"}}}, nil - } - activatedGeneration := "" - activateRelease := func(_ context.Context, project, generation string, _ []dataset.DataframeSelector) error { - if project != "project-a" { - t.Fatalf("activated project = %q", project) - } - activatedGeneration = generation - return nil - } - app := fiber.New() - RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{ - Compile: compile, Materialize: materialize, ValidateReleaseGeneration: validateGeneration, ActivateRelease: activateRelease, - }) - created := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers", `{"name":"Current Generation","blank":true}`) - if created.StatusCode != http.StatusCreated { - t.Fatalf("create status=%d body=%s", created.StatusCode, created.Body) - } - published := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/current-generation/publish", `{}`) - if published.StatusCode != http.StatusOK { - t.Fatalf("publish status=%d body=%s", published.StatusCode, published.Body) - } - if validatedGeneration != "generation-new" || materializedGeneration != "generation-new" || activatedGeneration != "generation-new" { - t.Fatalf("publish generations validate=%q materialize=%q activate=%q", validatedGeneration, materializedGeneration, activatedGeneration) - } - updated, err := service.RepositoryConfig(context.Background(), "project-a") - if err != nil { - t.Fatal(err) - } - if updated.SourceGeneration != "generation-new" || updated.Dataset.Generation != "generation-new" || updated.Publication.Generation != "generation-new" { - t.Fatalf("updated repository generation = %#v", updated) - } -} - -func TestPublishPreflightsGenerationBeforeMaterialization(t *testing.T) { - t.Skip("legacy ExplorerConfigV2 publish route removed by Builder cutover") - store := explorer.NewMemoryStore() - service, err := explorer.NewService(store) - if err != nil { - t.Fatal(err) - } - bundle := testV2Bundle("explorer-custom") - compile := func(_ context.Context, request ExplorerV2CompileRequest) (ExplorerV2CompileResult, error) { - digest, _ := bundle.Digest() - return ExplorerV2CompileResult{Config: request.Config, Bundle: bundle, RecipeDigest: digest, SourceGeneration: "generation-missing"}, nil - } - materializeCalls := 0 - materialize := func(context.Context, recipe.Bundle, recipe.RuntimeBindings) (graphresolver.RecipeExecution, error) { - materializeCalls++ - return graphresolver.RecipeExecution{}, nil - } - app := fiber.New() - RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{ - Compile: compile, Materialize: materialize, - ValidateReleaseGeneration: func(context.Context, string, string) error { return dataset.ErrSnapshotNotFound }, - ActivateRelease: func(context.Context, string, string, []dataset.DataframeSelector) error { return nil }, - }) - created := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers", `{"name":"Missing Generation","blank":true}`) - if created.StatusCode != http.StatusCreated { - t.Fatalf("create status=%d body=%s", created.StatusCode, created.Body) - } - published := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/missing-generation/publish", `{}`) - if published.StatusCode != http.StatusServiceUnavailable || !strings.Contains(published.Body, `"code":"DATASET_GENERATION_UNAVAILABLE"`) || !strings.Contains(published.Body, `"retryable":true`) { - t.Fatalf("publish status=%d body=%s", published.StatusCode, published.Body) - } - if materializeCalls != 0 { - t.Fatalf("materializer called %d times after failed generation preflight", materializeCalls) - } -} - -func TestExplorerPublishErrorHidesBackendCause(t *testing.T) { - app := fiber.New() - app.Get("/", func(c fiber.Ctx) error { - c.Locals("request_id", "request-a") - return explorerV2ErrorWithDetails(c, http.StatusServiceUnavailable, "DATASET_BUILD_FAILED", "the dataset could not be built", publicExplorerPublishDetails(fiber.Map{ - "generation": "generation-a", - "output": "Patient", - "cause": "secret backend query and credentials", - })) - }) - response := requestJSON(t, app, http.MethodGet, "/", "") - if response.StatusCode != http.StatusServiceUnavailable || !strings.Contains(response.Body, `"retryable":true`) || !strings.Contains(response.Body, `"requestId":"request-a"`) { - t.Fatalf("publish error status=%d body=%s", response.StatusCode, response.Body) - } - if strings.Contains(response.Body, "secret backend") || !strings.Contains(response.Body, `"output":"Patient"`) { - t.Fatalf("publish error leaked backend cause or lost public context: %s", response.Body) - } -} - -func TestRepositoryStateExposesPublishedPacketAndPresentationFreeBaseline(t *testing.T) { - store := explorer.NewMemoryStore() - service, err := explorer.NewService(store) - if err != nil { - t.Fatal(err) - } - raw := baselineExplorerConfigV2("project-a", "Default") - var cfg explorer.ConfigV2 - if err := json.Unmarshal(raw, &cfg); err != nil { - t.Fatal(err) - } - cfg.Views = []explorer.ConfigView{{ID: "document-reference", Title: "Documents", Output: "DocumentReference", Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "id", Visible: true}}}}} - raw, err = json.Marshal(cfg) - if err != nil { - t.Fatal(err) - } - bundle := testV2Bundle("repository") - owner, revision, err := service.UpsertRepositoryV2(context.Background(), raw, "commit-a", "generation-a", "etl", explorer.Compilation{Bundle: bundle, RecipeDigest: "sha256:recipe"}, "sha256:schema", nil, explorer.DatasetMetadata{}, explorer.PublicationMetadata{}) - if err != nil { - t.Fatal(err) - } - if owner.ActiveRevisionID != "" { - t.Fatalf("owner was active before activation: %#v", owner) - } - if err := service.ActivateRepository(context.Background(), "project-a", revision.ID); err != nil { - t.Fatal(err) - } - state, err := getExplorerV2State(context.Background(), service, "project-a", "default") - if err != nil { - t.Fatal(err) - } - var baseline, active explorer.ConfigV2 - decodeBody(t, string(state.BaselineConfig), &baseline) - decodeBody(t, string(state.ActiveConfig), &active) - if len(baseline.Views) != 0 || len(active.Views) != 1 || active.Views[0].Output != "DocumentReference" || len(state.DraftConfig) == 0 { - t.Fatalf("repository state did not separate lifecycle configs: baseline=%#v active=%#v state=%#v", baseline.Views, active.Views, state) - } -} - -func TestRuntimeProjectionOmitsUnpublishedEmissions(t *testing.T) { - selector := dataset.DataframeSelector{Recipe: "recipe", TranslationVersion: "v1", Output: "Patient"} - config, err := json.Marshal(explorer.ConfigV2{ - APIVersion: explorer.ConfigV2APIVersion, - Kind: "ExplorerConfig", - Project: "project-a", - Explorer: explorer.ConfigExplorer{ID: "default", Title: "Patients", Management: "repository"}, - Views: []explorer.ConfigView{{ - ID: "patients", Title: "Patients", Output: "Patient", - Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "c_id", Visible: true}, {Column: "c_missing", Visible: true}}}, - Filters: []explorer.ConfigFilter{{Column: "c_missing"}}, - FixedFilters: map[string][]string{"c_missing": {"x"}}, - }}, - SharedFilters: map[string][]explorer.SharedFilter{"missing": {{Output: "Patient", Column: "c_missing"}}}, - }) - if err != nil { - t.Fatal(err) - } - state := &explorerV2State{ - Project: "project-a", - ExplorerID: "default", - ActiveConfig: config, - Dataset: explorer.DatasetMetadata{Outputs: []explorer.DatasetOutput{{ - Name: "Patient", Selector: &selector, - Columns: []publication.PhysicalColumn{{Name: "c_id", LogicalType: "String"}}, - }}}, - EmittedColumns: []explorer.EmittedColumn{ - {EmissionID: "em_id", OutputID: "Patient", PublicColumn: "c_id", LogicalType: "string"}, - {EmissionID: "em_missing", OutputID: "Patient", PublicColumn: "c_missing", LogicalType: "string"}, - }, - } - runtime := runtimeV1FromExplorerV2State(state) - if runtime == nil || len(runtime.Outputs) != 1 { - t.Fatalf("runtime=%#v", runtime) - } - output := runtime.Outputs[0] - if len(output.Columns) != 1 || output.Columns[0].EmissionID != "em_id" { - t.Fatalf("unpublished column leaked into runtime columns: %#v", output.Columns) - } - if len(output.Table.Columns) != 1 || output.Table.Columns[0].EmissionID != "em_id" || len(output.Filters) != 0 || len(output.FixedFilters) != 0 { - t.Fatalf("unpublished presentation binding leaked into runtime: %#v", output) - } - if len(runtime.SharedFilters) != 0 { - t.Fatalf("unpublished shared filter leaked into runtime: %#v", runtime.SharedFilters) - } -} - -func TestRuntimeProjectionDefaultsPublishedColumnsWhenPresentationIsEmpty(t *testing.T) { - selector := dataset.DataframeSelector{Recipe: "recipe", TranslationVersion: "authoring-v1", Output: "Patient"} - config := explorer.ConfigV2{ - APIVersion: explorer.ConfigV2APIVersion, - Kind: "ExplorerConfig", - Project: "project-a", - Explorer: explorer.ConfigExplorer{ID: "default", Title: "Patients", Management: "repository"}, - Views: []explorer.ConfigView{{ - ID: "patients", Title: "Patients", Output: "Patient", - // An empty table is what a stale legacy presentation can leave - // behind after the published physical names change. - Table: explorer.ConfigTable{}, - }}, - } - state := &explorerV2State{ - ActiveConfig: mustJSON(config), - Dataset: explorer.DatasetMetadata{Outputs: []explorer.DatasetOutput{{ - Name: "Patient", Selector: &selector, - Columns: []publication.PhysicalColumn{{Name: "patient_c_id", LogicalType: "String"}, {Name: "patient_c_name", LogicalType: "String"}}, - }}}, - EmittedColumns: []explorer.EmittedColumn{ - {EmissionID: "em_id", OutputID: "Patient", PublicColumn: "c_id", LogicalType: "string"}, - {EmissionID: "em_name", OutputID: "Patient", PublicColumn: "c_name", LogicalType: "string"}, - }, - } - runtime := runtimeV1FromExplorerV2State(state) - if runtime == nil || len(runtime.Outputs) != 1 { - t.Fatalf("runtime=%#v", runtime) - } - output := runtime.Outputs[0] - if len(output.Table.Columns) != 2 || !output.Table.Columns[0].Visible || !output.Table.Columns[1].Visible { - t.Fatalf("default table bindings=%#v", output.Table) - } - if len(output.Columns) != 2 || !output.Columns[0].Visible || !output.Columns[1].Visible { - t.Fatalf("default runtime columns=%#v", output.Columns) - } -} - -func TestRuntimeProjectionResolvesQualifiedPublishedColumns(t *testing.T) { - selector := dataset.DataframeSelector{Recipe: "explorer_project_default", TranslationVersion: "authoring-v1", Output: "Patient"} - config := explorer.ConfigV2{ - APIVersion: explorer.ConfigV2APIVersion, - Kind: "ExplorerConfig", - Project: "project-a", - Explorer: explorer.ConfigExplorer{ID: "default", Title: "Patients", Management: "repository"}, - Views: []explorer.ConfigView{{ - ID: "patients", Title: "Patients", Output: "Patient", - Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "c_id", Label: "Patient ID", Visible: true}}}, - }}, - SharedFilters: map[string][]explorer.SharedFilter{"patient": {{Output: "Patient", Column: "c_id"}}}, - } - state := &explorerV2State{ - ActiveConfig: mustJSON(config), - Dataset: explorer.DatasetMetadata{Outputs: []explorer.DatasetOutput{{ - Name: "Patient", Selector: &selector, - Columns: []publication.PhysicalColumn{{Name: "patient_c_id", LogicalType: "String"}}, - }}}, - EmittedColumns: []explorer.EmittedColumn{{ - EmissionID: "em_id", OutputID: "Patient", PublicColumn: "c_id", LogicalType: "string", - }}, - } - runtime := runtimeV1FromExplorerV2State(state) - if runtime == nil || len(runtime.Outputs) != 1 { - t.Fatalf("runtime=%#v", runtime) - } - output := runtime.Outputs[0] - if len(output.Columns) != 1 || output.Columns[0].Name != "patient_c_id" { - t.Fatalf("runtime columns=%#v", output.Columns) - } - if len(output.Table.Columns) != 1 || output.Table.Columns[0].EmissionID != "em_id" { - t.Fatalf("runtime table=%#v", output.Table) - } - if got := runtime.SharedFilters["patient"]; len(got) != 1 || got[0].EmissionID != "em_id" { - t.Fatalf("runtime shared filters=%#v", runtime.SharedFilters) - } -} - -func TestRuntimeProjectionUsesRecipeFieldRefWhenLabelIsGeneratedColumn(t *testing.T) { - selector := dataset.DataframeSelector{Recipe: "explorer_project_default", TranslationVersion: "authoring-v1", Output: "documentreference"} - logicalName := generatedFieldName("s_title", "base") - bundle := recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "explorer_project_default", TranslationVersion: "authoring-v1", Outputs: []recipe.Output{{ - Name: "documentreference", RootResourceType: "DocumentReference", RowGrain: "file", - Fields: []recipe.Field{{Name: logicalName, FieldRef: "DocumentReference.content.attachment.title", Expr: recipe.Expression{Select: "root.content.attachment.title"}}}, - }}} - config := explorer.ConfigV2{ - APIVersion: explorer.ConfigV2APIVersion, - Kind: "ExplorerConfig", - Project: "project-a", - Explorer: explorer.ConfigExplorer{ID: "default", Title: "Documents", Management: "repository"}, - Recipe: mustJSON(bundle), - Views: []explorer.ConfigView{{ - ID: "documents", Title: "Documents", Output: "documentreference", - Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: logicalName, Label: logicalName, Visible: true}}}, - }}, - } - state := &explorerV2State{ - ActiveConfig: mustJSON(config), - Dataset: explorer.DatasetMetadata{Outputs: []explorer.DatasetOutput{{ - Name: "documentreference", Selector: &selector, - Columns: []publication.PhysicalColumn{{Name: "documentreference_" + logicalName, LogicalType: "String"}}, - }}}, - EmittedColumns: []explorer.EmittedColumn{{EmissionID: "em_title", OutputID: "documentreference", PublicColumn: logicalName, LogicalType: "string"}}, - } - runtime := runtimeV1FromExplorerV2State(state) - if runtime == nil || len(runtime.Outputs) != 1 || len(runtime.Outputs[0].Columns) != 1 { - t.Fatalf("runtime=%#v", runtime) - } - if got := runtime.Outputs[0].Columns[0].Label; got != "Content Attachment Title" { - t.Fatalf("runtime label=%q", got) - } -} - -func TestRuntimeProjectionRepairsLegacyAuthoringColumnIdentity(t *testing.T) { - selector := dataset.DataframeSelector{Recipe: "explorer_project_default", TranslationVersion: "authoring-v1", Output: "patient"} - logicalName := generatedFieldName("s_patient_id", "base") - config := explorer.ConfigV2{ - APIVersion: explorer.ConfigV2APIVersion, - Kind: "ExplorerConfig", - Project: "project-a", - Explorer: explorer.ConfigExplorer{ID: "default", Title: "Patients", Management: "repository"}, - Views: []explorer.ConfigView{{ - ID: "patients", Title: "Patients", Output: "patient", - Table: explorer.ConfigTable{Columns: []explorer.ConfigColumn{{Column: "c_old_emission_hash", Label: "Patient ID", Visible: true}}}, - }}, - } - state := &explorerV2State{ - ActiveConfig: mustJSON(config), - Dataset: explorer.DatasetMetadata{Outputs: []explorer.DatasetOutput{{ - Name: "patient", Selector: &selector, - Columns: []publication.PhysicalColumn{{Name: "patient_" + logicalName, LogicalType: "String"}}, - }}}, - EmittedColumns: []explorer.EmittedColumn{{ - EmissionID: "em_patient_id", OutputID: "patient", PublicColumn: "c_old_emission_hash", - CandidateID: "s_patient_id", OccurrenceID: "base", LogicalType: "string", - }}, - } - runtime := runtimeV1FromExplorerV2State(state) - if runtime == nil || len(runtime.Outputs) != 1 { - t.Fatalf("runtime=%#v", runtime) - } - output := runtime.Outputs[0] - if len(output.Columns) != 1 || output.Columns[0].Name != "patient_"+logicalName || output.Columns[0].EmissionID != "em_patient_id" { - t.Fatalf("runtime columns=%#v", output.Columns) - } - if len(output.Table.Columns) != 1 || output.Table.Columns[0].EmissionID != "em_patient_id" || !output.Table.Columns[0].Visible { - t.Fatalf("runtime table=%#v", output.Table) - } -} - -func testV2Bundle(name string) recipe.Bundle { - return recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: name, TranslationVersion: "interactive", Outputs: []recipe.Output{{Name: "DocumentReference", RootResourceType: "DocumentReference", RowGrain: "document_reference", Fields: []recipe.Field{{Name: "id", FieldRef: "DocumentReference.id", Expr: recipe.Expression{Select: "root.id"}}}}}} -} - -func baselineExplorerConfigV2(project, title string) []byte { - bundle := testV2Bundle("repository") - recipeRaw, _ := json.Marshal(bundle) - cfg := explorer.ConfigV2{APIVersion: explorer.ConfigV2APIVersion, Kind: "ExplorerConfig", Project: project, Explorer: explorer.ConfigExplorer{ID: "default", Title: title, Management: "repository"}, Recipe: recipeRaw} - raw, _ := json.Marshal(cfg) - return raw -} - -type testHTTPResponse struct { - StatusCode int - Body string -} - -func requestJSON(t *testing.T, app *fiber.App, method, path, body string) testHTTPResponse { - t.Helper() - request := httptest.NewRequest(method, path, strings.NewReader(body)) - if body != "" { - request.Header.Set("Content-Type", "application/json") - } - response, err := app.Test(request) - if err != nil { - t.Fatal(err) - } - defer response.Body.Close() - raw, err := io.ReadAll(response.Body) - if err != nil { - t.Fatal(err) - } - return testHTTPResponse{StatusCode: response.StatusCode, Body: string(raw)} -} - -func decodeBody(t *testing.T, body string, value any) { - t.Helper() - if err := json.Unmarshal([]byte(body), value); err != nil { - t.Fatalf("decode %s: %v", body, err) - } -} diff --git a/internal/server/explorer_wiring.go b/internal/server/explorer_wiring.go deleted file mode 100644 index 590d96b0..00000000 --- a/internal/server/explorer_wiring.go +++ /dev/null @@ -1,123 +0,0 @@ -package server - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "fmt" - "sort" - "strings" - "unicode" - - "github.com/calypr/loom/internal/authscope" - "github.com/calypr/loom/internal/catalog" - "github.com/calypr/loom/internal/dataset" - "github.com/calypr/loom/internal/explorer" - fhirschema "github.com/calypr/loom/internal/fhir/schema" - "github.com/calypr/loom/internal/projectid" -) - -// explorerCatalogReader assembles the complete catalog before exposing any -// opaque identifier. A failed dependency returns an explicitly incomplete -// snapshot; callers must never confuse an empty response with a usable one. -func explorerCatalogReader(discoverFields func(context.Context, catalog.PopulatedFieldOptions) ([]catalog.PopulatedField, error), discoverReferences func(context.Context, catalog.PopulatedReferenceOptions) ([]catalog.PopulatedReference, error), scopes *authscope.ScopeResolver, manifests dataset.ActiveResolver) func(context.Context, string, string, string) (explorer.CatalogSnapshot, error) { - return func(ctx context.Context, project, _ string, requestedGeneration string) (explorer.CatalogSnapshot, error) { - project = projectid.Canonical(project) - storageProject := projectid.Legacy(project) - principal, _ := authscope.PrincipalFromContext(ctx) - if err := authscope.AuthorizeProject(principal, project, scopes != nil); err != nil { - return explorer.CatalogSnapshot{}, err - } - generation := requestedGeneration - schemaDigest := "" - if generation == "" && manifests != nil { - manifest, err := dataset.ResolveActive(ctx, manifests, storageProject) - if err != nil { - return incompleteExplorerCatalog(project, generation, "", err) - } - generation, schemaDigest = manifest.Dataset.Generation, manifest.SchemaIdentity.SchemaSHA256 - } - scope := authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted} - if scopes != nil { - resolved, err := scopes.ResolveReadScopeForGeneration(ctx, principal, storageProject, generation, nil) - if err != nil { - return incompleteExplorerCatalog(project, generation, schemaDigest, err) - } - scope = resolved - } - unrestricted := scope.Unrestricted() - options := catalog.PopulatedFieldOptions{Project: storageProject, DatasetGeneration: generation, AuthResourcePaths: append([]string(nil), scope.AuthResourcePaths...), AuthResourcePathsUnrestricted: &unrestricted} - fields, err := discoverFields(ctx, options) - if err != nil { - return incompleteExplorerCatalog(project, generation, schemaDigest, err) - } - references, err := discoverReferences(ctx, catalog.PopulatedReferenceOptions{Project: storageProject, DatasetGeneration: generation, AuthResourcePaths: append([]string(nil), scope.AuthResourcePaths...), AuthResourcePathsUnrestricted: &unrestricted, Mode: catalog.TraversalModeBuilder}) - if err != nil { - return incompleteExplorerCatalog(project, generation, schemaDigest, err) - } - assembled := explorer.Catalog{Selections: map[string]explorer.CatalogSelection{}} - nodes := map[string]explorer.CatalogNode{} - for _, field := range fields { - resourceType := canonicalExplorerCatalogResourceType(field.ResourceType) - if resourceType == "" || isLoomMetadataField(field.Path) { - continue - } - nodeID := explorer.OpaqueID("n_", resourceType) - nodes[nodeID] = explorer.CatalogNode{ID: nodeID, ResourceType: resourceType} - selectionID := explorer.OpaqueID("s_", resourceType+"\x00"+field.Path) - assembled.Selections[selectionID] = explorer.CatalogSelection{ID: selectionID, NodeID: nodeID, FieldRef: explorerFieldRef(resourceType, field.Path), Select: field.Path, LogicalType: field.Kind, Filterable: field.Kind != "object" && field.Kind != "array", Chartable: field.Kind != "object" && field.Kind != "array"} - } - for _, reference := range references { - fromType := canonicalExplorerCatalogResourceType(reference.FromType) - toType := canonicalExplorerCatalogResourceType(reference.ToType) - if fromType == "" || toType == "" { - continue - } - from, to := explorer.OpaqueID("n_", fromType), explorer.OpaqueID("n_", toType) - nodes[from] = explorer.CatalogNode{ID: from, ResourceType: fromType} - nodes[to] = explorer.CatalogNode{ID: to, ResourceType: toType} - assembled.Edges = append(assembled.Edges, explorer.CatalogEdge{ID: explorer.OpaqueID("e_", fromType+"\x00"+reference.Label+"\x00"+toType), FromNodeID: from, ToNodeID: to, Label: reference.Label}) - } - for _, node := range nodes { - assembled.Nodes = append(assembled.Nodes, node) - } - sort.Slice(assembled.Nodes, func(i, j int) bool { return assembled.Nodes[i].ID < assembled.Nodes[j].ID }) - sort.Slice(assembled.Edges, func(i, j int) bool { return assembled.Edges[i].ID < assembled.Edges[j].ID }) - snapshot, err := explorer.NewCatalogSnapshotWithSchema(project, generation, explorerScopeDigest(scope), schemaDigest, assembled, true, false, nil) - if err != nil { - return explorer.CatalogSnapshot{}, err - } - return snapshot, nil - } -} - -func canonicalExplorerCatalogResourceType(resourceType string) string { - if canonical, ok := fhirschema.ConcreteResourceType(resourceType); ok { - return canonical - } - return "" -} - -func incompleteExplorerCatalog(project, generation, schemaDigest string, cause error) (explorer.CatalogSnapshot, error) { - snapshot, err := explorer.NewCatalogSnapshotWithSchema(project, generation, "unavailable", schemaDigest, explorer.Catalog{Selections: map[string]explorer.CatalogSelection{}}, false, false, []explorer.Diagnostic{{Severity: "ERROR", Code: "CATALOG_UNAVAILABLE", Message: cause.Error(), Retryable: true}}) - return snapshot, err -} - -func explorerScopeDigest(scope authscope.ReadScope) string { - paths := append([]string(nil), scope.AuthResourcePaths...) - sort.Strings(paths) - sum := sha256.Sum256([]byte(string(scope.Mode) + "\x00" + strings.Join(paths, "\x00"))) - return hex.EncodeToString(sum[:]) -} - -func explorerFieldRef(resourceType, path string) string { - var builder strings.Builder - for _, r := range strings.ToLower(path) { - if unicode.IsLetter(r) || unicode.IsDigit(r) { - builder.WriteRune(r) - } else if builder.Len() > 0 { - builder.WriteByte('_') - } - } - return fmt.Sprintf("%s.%s", resourceType, strings.Trim(builder.String(), "_")) -} diff --git a/internal/server/federation_status_test.go b/internal/server/federation_status_test.go index efb41749..846abc80 100644 --- a/internal/server/federation_status_test.go +++ b/internal/server/federation_status_test.go @@ -15,6 +15,54 @@ type statusExecutionCatalog struct { executions []publication.BundleExecution } +type statusReleaseStore struct { + records map[string]dataset.ProjectRelease + active map[string]dataset.ActiveRelease +} + +func newStatusReleaseStore() *statusReleaseStore { + return &statusReleaseStore{records: make(map[string]dataset.ProjectRelease), active: make(map[string]dataset.ActiveRelease)} +} + +func (s *statusReleaseStore) SaveRelease(_ context.Context, release dataset.ProjectRelease) (dataset.ProjectRelease, error) { + s.records[release.Project+"\x00"+release.ID] = release + return release, nil +} + +func (s *statusReleaseStore) ReadRelease(_ context.Context, project, releaseID string) (dataset.ProjectRelease, error) { + release, ok := s.records[project+"\x00"+releaseID] + if !ok { + return dataset.ProjectRelease{}, dataset.ErrReleaseNotFound + } + return release, nil +} + +func (s *statusReleaseStore) ReadActiveRelease(_ context.Context, project string) (dataset.ActiveRelease, error) { + release, ok := s.active[project] + if !ok { + return dataset.ActiveRelease{}, dataset.ErrNoActiveRelease + } + return release, nil +} + +func (s *statusReleaseStore) CompareAndSwapActivateRelease(_ context.Context, release dataset.ProjectRelease, expected int64) (dataset.ActiveRelease, error) { + current := s.active[release.Project] + if current.Revision != expected { + return dataset.ActiveRelease{}, dataset.ErrReleaseActivationConflict + } + active := dataset.ActiveRelease{Release: release, Revision: expected + 1} + s.active[release.Project] = active + return active, nil +} + +func (s *statusReleaseStore) ListReleaseProjects(context.Context) ([]string, error) { + projects := make([]string, 0, len(s.active)) + for project := range s.active { + projects = append(projects, project) + } + return projects, nil +} + func (c statusExecutionCatalog) ListExecutions(_ context.Context, state publication.BundleState, before time.Time) ([]publication.BundleExecution, error) { result := make([]publication.BundleExecution, 0) for _, execution := range c.executions { @@ -29,7 +77,7 @@ func TestReleaseProjectStatusResolverDistinguishesReleaseAndAttemptStates(t *tes ctx := context.Background() now := time.Now().UTC() selector := dataset.DataframeSelector{Recipe: "core", TranslationVersion: "v1", Output: "Patient"} - store := dataset.NewMemoryLifecycleStore() + store := newStatusReleaseStore() release := dataset.ProjectRelease{ID: "release-1", Project: "current", Generation: "g1", GitCommit: "g1", Publications: []dataset.ReleasePublication{{Selector: selector, ExecutionID: "published-1", Generation: "g1", VerifiedAt: now}}} if _, err := store.SaveRelease(ctx, release); err != nil { t.Fatal(err) diff --git a/internal/server/http_test_helpers_test.go b/internal/server/http_test_helpers_test.go new file mode 100644 index 00000000..29ca10f2 --- /dev/null +++ b/internal/server/http_test_helpers_test.go @@ -0,0 +1,277 @@ +package server + +import ( + "context" + "encoding/json" + "io" + "net/http/httptest" + "strings" + "sync" + "testing" + "time" + + "github.com/calypr/loom/internal/dataframe/recipe/exec" + "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/explorer/authoringv2" + "github.com/calypr/loom/internal/explorer/capability" + "github.com/calypr/loom/internal/explorer/capabilitystore" + "github.com/gofiber/fiber/v3" +) + +type compilerTestRegistry struct{} + +type testCapabilityStore struct { + byToken map[string]capability.Snapshot + byIdentity map[capability.SnapshotIdentity]string +} + +func newTestCapabilityStore() *testCapabilityStore { + return &testCapabilityStore{byToken: make(map[string]capability.Snapshot), byIdentity: make(map[capability.SnapshotIdentity]string)} +} + +func (s *testCapabilityStore) Put(_ context.Context, snapshot capability.Snapshot) (*capability.Snapshot, error) { + stored := snapshot.Clone() + s.byToken[stored.Token] = stored + s.byIdentity[stored.Identity] = stored.Token + result := stored.Clone() + return &result, nil +} + +func (s *testCapabilityStore) GetByToken(_ context.Context, token string) (*capability.Snapshot, error) { + stored, ok := s.byToken[token] + if !ok { + return nil, capabilitystore.ErrNotFound + } + result := stored.Clone() + return &result, nil +} + +func (s *testCapabilityStore) GetByIdentity(_ context.Context, identity capability.SnapshotIdentity) (*capability.Snapshot, error) { + token, ok := s.byIdentity[identity] + if !ok { + return nil, capabilitystore.ErrNotFound + } + return s.GetByToken(context.Background(), token) +} + +func (compilerTestRegistry) LoadRecipe(context.Context, string) (exec.Entry, error) { + return exec.Entry{}, nil +} + +type testHTTPResponse struct { + StatusCode int + Body string +} + +func requestJSON(t *testing.T, app *fiber.App, method, path, body string) testHTTPResponse { + t.Helper() + request := httptest.NewRequest(method, path, strings.NewReader(body)) + if body != "" { + request.Header.Set("Content-Type", "application/json") + } + response, err := app.Test(request) + if err != nil { + t.Fatal(err) + } + defer response.Body.Close() + raw, err := io.ReadAll(response.Body) + if err != nil { + t.Fatal(err) + } + return testHTTPResponse{StatusCode: response.StatusCode, Body: string(raw)} +} + +type testExplorerStore struct { + explorer.Store + mu sync.Mutex + configs map[string]explorer.RepositoryConfig + explorers map[string]explorer.Explorer + receipts map[string]explorer.CompilationReceipt + revisions map[string]explorer.Revision +} + +func newTestExplorerStore() *testExplorerStore { + return &testExplorerStore{configs: map[string]explorer.RepositoryConfig{}, explorers: map[string]explorer.Explorer{}, receipts: map[string]explorer.CompilationReceipt{}, revisions: map[string]explorer.Revision{}} +} + +func testExplorerKey(project, id string) string { return project + "\x00" + id } + +func (s *testExplorerStore) GetRepositoryConfig(_ context.Context, project string) (*explorer.RepositoryConfig, error) { + s.mu.Lock() + defer s.mu.Unlock() + value, ok := s.configs[project] + if !ok { + return nil, explorer.ErrNotFound + } + return &value, nil +} + +func (s *testExplorerStore) SaveRepositoryConfig(_ context.Context, value explorer.RepositoryConfig) (*explorer.RepositoryConfig, error) { + s.mu.Lock() + defer s.mu.Unlock() + value.ExplorerID, value.Management = "default", explorer.ManagementRepository + s.configs[value.Project] = value + return &value, nil +} + +func (s *testExplorerStore) List(_ context.Context, project string) ([]explorer.Explorer, error) { + s.mu.Lock() + defer s.mu.Unlock() + values := []explorer.Explorer{} + for _, value := range s.explorers { + if value.Project == project { + values = append(values, value) + } + } + return values, nil +} + +func (s *testExplorerStore) Get(_ context.Context, project, id string) (*explorer.Explorer, error) { + s.mu.Lock() + defer s.mu.Unlock() + value, ok := s.explorers[testExplorerKey(project, id)] + if !ok { + return nil, explorer.ErrNotFound + } + return &value, nil +} + +func (s *testExplorerStore) CreateInteractive(_ context.Context, value explorer.Explorer) (*explorer.Explorer, error) { + return s.create(value) +} + +func (s *testExplorerStore) CreateRepository(_ context.Context, value explorer.Explorer) (*explorer.Explorer, error) { + return s.create(value) +} + +func (s *testExplorerStore) create(value explorer.Explorer) (*explorer.Explorer, error) { + s.mu.Lock() + defer s.mu.Unlock() + key := testExplorerKey(value.Project, value.ExplorerID) + if _, exists := s.explorers[key]; exists { + return nil, explorer.ErrDraftConflict + } + s.explorers[key] = value + return &value, nil +} + +func (s *testExplorerStore) SaveDraft(_ context.Context, value explorer.Explorer, expected int64, expectedDigest ...string) (*explorer.Explorer, error) { + s.mu.Lock() + defer s.mu.Unlock() + key := testExplorerKey(value.Project, value.ExplorerID) + prior, exists := s.explorers[key] + if !exists { + return nil, explorer.ErrNotFound + } + if prior.DraftVersion != expected || (len(expectedDigest) > 0 && expectedDigest[0] != "" && prior.DraftDigest != expectedDigest[0]) { + return nil, explorer.ErrDraftConflict + } + value.DraftVersion++ + s.explorers[key] = value + return &value, nil +} + +func (s *testExplorerStore) InsertCompilationReceipt(_ context.Context, value explorer.CompilationReceipt) (*explorer.CompilationReceipt, error) { + s.mu.Lock() + defer s.mu.Unlock() + if existing, ok := s.receipts[value.ID]; ok { + return &existing, nil + } + s.receipts[value.ID] = value + return &value, nil +} + +func (s *testExplorerStore) GetCompilationReceipt(_ context.Context, id string) (*explorer.CompilationReceipt, error) { + s.mu.Lock() + defer s.mu.Unlock() + value, ok := s.receipts[id] + if !ok { + return nil, explorer.ErrNotFound + } + return &value, nil +} + +func (s *testExplorerStore) GetCompilationReceiptForExplorer(ctx context.Context, project, explorerID, id string) (*explorer.CompilationReceipt, error) { + value, err := s.GetCompilationReceipt(ctx, id) + if err != nil || value.Project != project || value.ExplorerID != explorerID { + return nil, explorer.ErrNotFound + } + return value, nil +} + +func (s *testExplorerStore) GetCompilationReceiptByCompilationKey(_ context.Context, project, explorerID, key string) (*explorer.CompilationReceipt, error) { + s.mu.Lock() + defer s.mu.Unlock() + for _, value := range s.receipts { + if value.Project == project && value.ExplorerID == explorerID && value.CompilationKey == key { + copy := value + return ©, nil + } + } + return nil, explorer.ErrNotFound +} + +func (s *testExplorerStore) InsertRevision(_ context.Context, value explorer.Revision) (*explorer.Revision, error) { + s.mu.Lock() + defer s.mu.Unlock() + if existing, ok := s.revisions[value.ID]; ok { + return &existing, nil + } + s.revisions[value.ID] = value + return &value, nil +} + +func (s *testExplorerStore) GetRevision(_ context.Context, id string) (*explorer.Revision, error) { + s.mu.Lock() + defer s.mu.Unlock() + value, ok := s.revisions[id] + if !ok { + return nil, explorer.ErrNotFound + } + return &value, nil +} + +func (s *testExplorerStore) TransitionRevision(_ context.Context, id string, status explorer.RevisionStatus, diagnostics []explorer.Diagnostic) (*explorer.Revision, error) { + s.mu.Lock() + defer s.mu.Unlock() + value, ok := s.revisions[id] + if !ok { + return nil, explorer.ErrNotFound + } + value.Status, value.Diagnostics = status, append([]explorer.Diagnostic(nil), diagnostics...) + s.revisions[id] = value + return &value, nil +} + +func (s *testExplorerStore) ActivateRepositoryGeneration(_ context.Context, project, _ string, revisionID string) error { + s.mu.Lock() + defer s.mu.Unlock() + return s.activateLocked(project, "default", revisionID) +} + +func (s *testExplorerStore) activateLocked(project, explorerID, revisionID string) error { + revision, ok := s.revisions[revisionID] + if !ok { + return explorer.ErrNotFound + } + key := testExplorerKey(project, explorerID) + owner, ok := s.explorers[key] + if !ok { + return explorer.ErrNotFound + } + owner.ActiveRevisionID, owner.ActiveConfig = revision.ID, append([]byte(nil), revision.Config...) + owner.RecipeDigest, owner.ResolvedSchemaDigest, owner.SourceGeneration = revision.RecipeDigest, revision.ResolvedSchemaDigest, revision.SourceGeneration + owner.Materializations, owner.Dataset, owner.Publication = revision.Materializations, revision.Dataset, revision.Publication + owner.UpdatedAt = time.Now().UTC() + s.explorers[key] = owner + revision.Status = explorer.RevisionActive + s.revisions[revisionID] = revision + return nil +} + +func baselineExplorerWorkspaceV2() []byte { + visible, order := true, 0 + workspace := authoringv2.Workspace{APIVersion: authoringv2.APIVersion, Kind: authoringv2.WorkspaceKind, Explorer: authoringv2.ExplorerMetadata{Title: "Patients"}, Documents: []authoringv2.Document{{Kind: authoringv2.Kind, Output: authoringv2.Output{ID: "patients", Title: "Patients", RowLabel: "Patients"}, RootResourceType: "Patient", Route: authoringv2.RouteNode{OccurrenceID: "base", ResourceType: "Patient"}, Columns: []authoringv2.Column{{Column: "c_patient", Label: "Patient ID", LogicalType: "string", OccurrenceID: "base", Source: authoringv2.ColumnSource{Kind: authoringv2.SourceField, FieldPath: "id", ProjectionMode: "FIRST"}, Table: &authoringv2.TablePresentation{Visible: &visible, Order: &order}}}}}, Tabs: []authoringv2.Tab{{ID: "patients-tab", Title: "Patients", OutputID: "patients", Order: 0, Visible: true}}} + raw, _ := json.Marshal(workspace) + return raw +} diff --git a/internal/server/options.go b/internal/server/options.go index b7cce536..d561f8c5 100644 --- a/internal/server/options.go +++ b/internal/server/options.go @@ -34,12 +34,6 @@ type ServerConfig struct { SnapshotRetention time.Duration `yaml:"snapshot_retention"` PublicationWorkerLease time.Duration `yaml:"publication_worker_lease"` PublicationMaxAttempts int `yaml:"publication_max_attempts"` - MigrateExplorerAuthoring bool `yaml:"-"` - MigrationProject string `yaml:"-"` - MigrationExplorerID string `yaml:"-"` - MigrationConfigPath string `yaml:"-"` - MigrationMappingPath string `yaml:"-"` - MigrationAuditOnly bool `yaml:"-"` } type ClickHouseConfig struct { @@ -99,12 +93,6 @@ func parseServerOptions(args []string, handling flag.ErrorHandling) (Config, err dataframerRecipe string recipeBatchRows int recipeBatchBytes int - migrateAuthoring bool - migrationProject string - migrationExplorer string - migrationConfig string - migrationMapping string - migrationAuditOnly bool ) fs := flag.NewFlagSet("arango-fhir-server", handling) fs.StringVar(&configPath, "config", "", "YAML server configuration file") @@ -120,12 +108,6 @@ func parseServerOptions(args []string, handling flag.ErrorHandling) (Config, err fs.StringVar(&dataframerRecipe, "dataframer-recipe", "", "dataframer recipe JSON file (required when ClickHouse is enabled)") fs.IntVar(&recipeBatchRows, "recipe-batch-rows", 1000, "maximum recipe materialization rows per ClickHouse batch") fs.IntVar(&recipeBatchBytes, "recipe-batch-bytes", 4<<20, "maximum recipe materialization bytes per ClickHouse batch") - fs.BoolVar(&migrateAuthoring, "migrate-explorer-authoring", false, "run the one-shot legacy Explorer authoring migration and exit") - fs.StringVar(&migrationProject, "migration-project", "HTAN_INT-BForePC", "project for the one-shot Explorer authoring migration") - fs.StringVar(&migrationExplorer, "migration-explorer", "default", "Explorer identity for the one-shot authoring migration") - fs.StringVar(&migrationConfig, "migration-config", "", "legacy ExplorerConfigV2 JSON to import when the Explorer has no active config") - fs.StringVar(&migrationMapping, "migration-mapping", "", "frontend Builder mapping JSON containing the translated authoring bundle") - fs.BoolVar(&migrationAuditOnly, "migration-audit-only", false, "validate and report the Explorer authoring migration without materializing or activating it") if err := fs.Parse(args); err != nil { return Config{}, err } @@ -143,12 +125,6 @@ func parseServerOptions(args []string, handling flag.ErrorHandling) (Config, err cfg.Server.AllowUnauthenticated = true cfg.Auth.AllowUnauthenticated = true } - cfg.Server.MigrateExplorerAuthoring = migrateAuthoring - cfg.Server.MigrationProject = migrationProject - cfg.Server.MigrationExplorerID = migrationExplorer - cfg.Server.MigrationConfigPath = migrationConfig - cfg.Server.MigrationMappingPath = migrationMapping - cfg.Server.MigrationAuditOnly = migrationAuditOnly if err := cfg.Validate(); err != nil { return Config{}, fmt.Errorf("invalid server config: %w", err) } @@ -170,12 +146,6 @@ func parseServerOptions(args []string, handling flag.ErrorHandling) (Config, err cfg.Server.Dataframer.Recipe = dataframerRecipe cfg.Server.RecipeBatchRows = recipeBatchRows cfg.Server.RecipeBatchBytes = recipeBatchBytes - cfg.Server.MigrateExplorerAuthoring = migrateAuthoring - cfg.Server.MigrationProject = migrationProject - cfg.Server.MigrationExplorerID = migrationExplorer - cfg.Server.MigrationConfigPath = migrationConfig - cfg.Server.MigrationMappingPath = migrationMapping - cfg.Server.MigrationAuditOnly = migrationAuditOnly if noAuth { cfg.Server.AllowUnauthenticated = true cfg.Auth.AllowUnauthenticated = true diff --git a/internal/server/release_verifier_test.go b/internal/server/release_verifier_test.go index 45fcf449..b3f58e4c 100644 --- a/internal/server/release_verifier_test.go +++ b/internal/server/release_verifier_test.go @@ -7,14 +7,8 @@ import ( "github.com/calypr/loom/internal/dataframe/publication" "github.com/calypr/loom/internal/dataset" - arangostore "github.com/calypr/loom/internal/store/arango" ) -type releaseQueryFixture struct { - row map[string]any - binds map[string]interface{} -} - type exactExecutionFixture struct { project, generation string selector dataset.DataframeSelector @@ -27,14 +21,6 @@ func (f *exactExecutionFixture) FindExecutionBySelector(_ context.Context, proje return f.execution, f.output, nil } -func (f *releaseQueryFixture) QueryRows(_ context.Context, _ string, _ int, binds map[string]interface{}, visit arangostore.RowVisitor) error { - f.binds = binds - if f.row != nil { - return visit(f.row) - } - return nil -} - func TestPublicationVerificationUsesExactSelectorAndQueryableEvidence(t *testing.T) { verifiedAt := time.Date(2026, 8, 6, 12, 0, 0, 0, time.UTC) selector := dataset.DataframeSelector{Recipe: "core", TranslationVersion: "v1", Output: "Patient"} diff --git a/internal/server/server.go b/internal/server/server.go index 4053b4c2..7952ce28 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -37,7 +37,6 @@ import ( publicationarango "github.com/calypr/loom/internal/dataset/arango" "github.com/calypr/loom/internal/explorer" explorerarango "github.com/calypr/loom/internal/explorer/arango" - "github.com/calypr/loom/internal/explorer/authoringv2" "github.com/calypr/loom/internal/explorer/capability" explorercompilation "github.com/calypr/loom/internal/explorer/compilation" "github.com/calypr/loom/internal/ingest" @@ -308,13 +307,6 @@ func run(ctx context.Context, serverConfig Config) error { return fmt.Errorf("create Explorer service: %w", err) } explorerMaterializer := explorerBundleMaterializer(recipeEngine, bundleTarget, publishedRegistry, degradation, logger, serverConfig.Server.RecipeBatchRows, serverConfig.Server.RecipeBatchBytes) - explorerCatalog := explorerV2CatalogReader(func(ctx context.Context, project, _ string, requestedGeneration string) (explorer.CatalogSnapshot, error) { - snapshot, resolveErr := capabilityResolver.Resolve(ctx, project, requestedGeneration) - if resolveErr != nil { - return incompleteExplorerCatalog(projectid.Canonical(project), requestedGeneration, "", resolveErr) - } - return legacyCatalogSnapshot(snapshot), nil - }) resolver := graphresolver.NewResolver(graphresolver.ResolverConfig{ DataframeQuery: queryapi.Config{ DiscoverReferences: discoverReferences, @@ -371,12 +363,7 @@ func run(ctx context.Context, serverConfig Config) error { } else if len(deletedGenerations) != 0 { logger.Info("snapshot retention cleanup complete", "deleted_generations", len(deletedGenerations)) } - authoringCompile := func(ctx context.Context, request ExplorerAuthoringV1CompileRequest) (ExplorerAuthoringV1CompileResult, error) { - request.RequestID = firstNonEmpty(request.RequestID, "loom-authoring-migration") - return compileExplorerAuthoringV1(ctx, recipeEngine, explorerCatalog, request) - } - // CompileReceipt is the native V2 path. V1 remains below only for the - // startup migration of already-stored legacy documents. + // CompileReceipt is the native V2 path. compileReceipt := func(ctx context.Context, request ExplorerV2ReceiptCompileRequest) (*explorer.CompilationReceipt, error) { started := time.Now() authorized := request.Authorized.Clone() @@ -394,9 +381,6 @@ func run(ctx context.Context, serverConfig Config) error { return nil, capability.ErrStaleSnapshot } workspace := request.Workspace - if workspace.APIVersion == "" && request.Document.Kind != "" { - workspace = authoringv2.Workspace{APIVersion: authoringv2.APIVersion, Kind: authoringv2.WorkspaceKind, Documents: []authoringv2.Document{request.Document}, Tabs: []authoringv2.Tab{{ID: request.Document.Output.ID, Title: request.Document.Output.Title, OutputID: request.Document.Output.ID, Order: 0, Visible: true}}} - } intentDigest, err := workspace.Digest() if err != nil { return nil, err @@ -472,9 +456,7 @@ func run(ctx context.Context, serverConfig Config) error { return stored, nil } lifecycleConfig := ExplorerV2LifecycleConfig{ - Compile: explorerV2Compiler(recipeEngine, explorerCatalog), CompileReceipt: compileReceipt, - Catalog: explorerCatalog, Capability: func(ctx context.Context, project, _ string, generation string) (capability.Snapshot, error) { return capabilityResolver.Resolve(ctx, project, generation) }, @@ -506,45 +488,6 @@ func run(ctx context.Context, serverConfig Config) error { MaterializeReceipt: explorerReceiptMaterializer(recipeEngine, bundleTarget, publishedRegistry, degradation, logger, serverConfig.Server.RecipeBatchRows, serverConfig.Server.RecipeBatchBytes), ValidateReleaseGeneration: validateExplorerReleaseGeneration, ActivateRelease: activateExplorerRelease, - AuthoringCompile: authoringCompile, - } - if serverConfig.Server.MigrateExplorerAuthoring { - legacyConfig, configErr := optionalMigrationInput(serverConfig.Server.MigrationConfigPath, "legacy Explorer config") - if configErr != nil { - return configErr - } - legacyMapping, mappingErr := optionalMigrationInput(serverConfig.Server.MigrationMappingPath, "frontend authoring mapping") - if mappingErr != nil { - return mappingErr - } - migrationResolver, resolverErr := newExplorerCapabilityResolver(catalogStore, nil, activeManifestResolver, capabilitySnapshots) - if resolverErr != nil { - return fmt.Errorf("create Explorer migration capability resolver: %w", resolverErr) - } - migrationCatalog := explorerV2CatalogReader(func(ctx context.Context, project, _ string, requestedGeneration string) (explorer.CatalogSnapshot, error) { - snapshot, resolveErr := migrationResolver.Resolve(ctx, project, requestedGeneration) - if resolveErr != nil { - return incompleteExplorerCatalog(projectid.Canonical(project), requestedGeneration, "", resolveErr) - } - return legacyCatalogSnapshot(snapshot), nil - }) - migrationConfig := lifecycleConfig - migrationConfig.Catalog = migrationCatalog - migrationConfig.AuthoringCompile = func(ctx context.Context, request ExplorerAuthoringV1CompileRequest) (ExplorerAuthoringV1CompileResult, error) { - request.RequestID = firstNonEmpty(request.RequestID, "loom-authoring-migration") - return compileExplorerAuthoringV1(ctx, recipeEngine, migrationCatalog, request) - } - report, migrationErr := MigrateLegacyExplorerAuthoring(ctx, explorerService, migrationConfig, ExplorerAuthoringMigrationOptions{ - Project: serverConfig.Server.MigrationProject, ExplorerID: serverConfig.Server.MigrationExplorerID, - Actor: "loom-authoring-migration", RequestID: "loom-authoring-migration-" + serverConfig.Server.MigrationProject, - LegacyConfig: legacyConfig, LegacyMapping: legacyMapping, AuditOnly: serverConfig.Server.MigrationAuditOnly, - }) - if migrationErr != nil { - logger.Error("Explorer authoring migration failed", "report", report, "error", migrationErr) - return fmt.Errorf("Explorer authoring migration failed: %w", migrationErr) - } - logger.Info("Explorer authoring migration complete", "report", report) - return nil } server, err := httpapi.NewHTTPServer(httpapi.HTTPConfig{Authenticator: authenticator, Authorizer: authorizer, Logger: logger, CoreReadyCheck: func(ctx context.Context) error { @@ -603,17 +546,3 @@ func run(ctx context.Context, serverConfig Config) error { } return nil } - -func optionalMigrationInput(path, description string) ([]byte, error) { - if strings.TrimSpace(path) == "" { - return nil, nil - } - raw, err := os.ReadFile(path) - if err != nil { - return nil, fmt.Errorf("read %s %q: %w", description, path, err) - } - if len(strings.TrimSpace(string(raw))) == 0 { - return nil, fmt.Errorf("read %s %q: file is empty", description, path) - } - return raw, nil -} diff --git a/internal/server/wiring_test.go b/internal/server/wiring_test.go index a6c2ee7f..d7736809 100644 --- a/internal/server/wiring_test.go +++ b/internal/server/wiring_test.go @@ -44,14 +44,3 @@ func TestRecipeScopeDigestDistinguishesRestrictedEmptyScope(t *testing.T) { t.Fatal("restricted-empty and unrestricted bindings shared a scope digest") } } - -func TestCanonicalExplorerCatalogResourceTypeCanonicalizesFHIRCase(t *testing.T) { - if got := canonicalExplorerCatalogResourceType(" specimen "); got != "Specimen" { - t.Fatalf("canonical resource type = %q, want Specimen", got) - } - for _, invalid := range []string{"CustomResource", "PractitionerQualification", "qualification", "issuer", "Resource"} { - if got := canonicalExplorerCatalogResourceType(invalid); got != "" { - t.Fatalf("non-resource type %q was exposed as %q", invalid, got) - } - } -} From 16a4fc7b009db7430957f22ea08a2d1cfd08a653 Mon Sep 17 00:00:00 2001 From: matthewpeterkort Date: Fri, 28 Aug 2026 10:37:17 -0700 Subject: [PATCH 10/15] fix 409 bug --- internal/explorer/authoringv2/types.go | 116 +++++++++++++++++- .../explorer/authoringv2/workspace_test.go | 41 +++++++ .../explorer/compilation/semantic_compile.go | 8 ++ internal/explorer/compilation/translate.go | 13 +- internal/explorer/compilation_receipt.go | 2 +- .../server/explorer_authoring_v2_routes.go | 7 +- internal/server/explorer_receipt_contract.go | 18 +++ .../server/explorer_receipt_contract_test.go | 45 ++++++- internal/server/server.go | 13 +- 9 files changed, 249 insertions(+), 14 deletions(-) diff --git a/internal/explorer/authoringv2/types.go b/internal/explorer/authoringv2/types.go index aa2363fa..213a39f0 100644 --- a/internal/explorer/authoringv2/types.go +++ b/internal/explorer/authoringv2/types.go @@ -732,8 +732,8 @@ func (w Workspace) CanonicalJSON() ([]byte, error) { if err := w.Validate(); err != nil { return nil, err } - n := w - n.Documents = append([]Document(nil), w.Documents...) + n := w.NormalizePresentationOrders() + n.Documents = append([]Document(nil), n.Documents...) for i := range n.Documents { n.Documents[i].APIVersion = "" n.Documents[i].Selections = append([]Selection(nil), n.Documents[i].Selections...) @@ -762,6 +762,118 @@ func (w Workspace) CanonicalJSON() ([]byte, error) { return json.Marshal(n) } +// NormalizePresentationOrders gives every table column one unambiguous, +// contiguous presentation position. Authored order is the primary key and the +// stable public column identity breaks ties. The normalized order also becomes +// the recipe projection order, so presentation and execution cannot disagree. +// +// Duplicate presentation positions are valid mutable Builder input. Freezing +// them here keeps equivalent requests from depending on frontend collection or +// map iteration order and makes the normalized workspace safe to persist and +// return to the Builder. +func (w Workspace) NormalizePresentationOrders() Workspace { + n := w + n.Documents = append([]Document(nil), w.Documents...) + for documentIndex := range n.Documents { + document := &n.Documents[documentIndex] + columns := append([]Column(nil), document.Columns...) + for columnIndex := range columns { + column := &columns[columnIndex] + if column.Table != nil { + table := *column.Table + column.Table = &table + } + if column.Filter != nil { + filter := *column.Filter + column.Filter = &filter + } + if column.Chart != nil { + chart := *column.Chart + column.Chart = &chart + } + } + sort.SliceStable(columns, func(i, j int) bool { + left, right := columns[i], columns[j] + leftClass, leftOrder := presentationOrder(left) + rightClass, rightOrder := presentationOrder(right) + if leftClass != rightClass { + return leftClass < rightClass + } + if leftOrder != rightOrder { + return leftOrder < rightOrder + } + return left.Column < right.Column + }) + tableOrder := 0 + for columnIndex := range columns { + if columns[columnIndex].Table == nil { + continue + } + value := tableOrder + columns[columnIndex].Table.Order = &value + tableOrder++ + } + normalizeFilterOrders(columns) + normalizeChartOrders(columns) + document.Columns = columns + } + return n +} + +func normalizeFilterOrders(columns []Column) { + indexes := make([]int, 0, len(columns)) + for index := range columns { + if columns[index].Filter != nil { + indexes = append(indexes, index) + } + } + sort.SliceStable(indexes, func(i, j int) bool { + left, right := columns[indexes[i]], columns[indexes[j]] + return auxiliaryPresentationLess(left.Filter.Order, left.Column, right.Filter.Order, right.Column) + }) + for order, index := range indexes { + value := order + columns[index].Filter.Order = &value + } +} + +func normalizeChartOrders(columns []Column) { + indexes := make([]int, 0, len(columns)) + for index := range columns { + if columns[index].Chart != nil { + indexes = append(indexes, index) + } + } + sort.SliceStable(indexes, func(i, j int) bool { + left, right := columns[indexes[i]], columns[indexes[j]] + return auxiliaryPresentationLess(left.Chart.Order, left.Column, right.Chart.Order, right.Column) + }) + for order, index := range indexes { + value := order + columns[index].Chart.Order = &value + } +} + +func auxiliaryPresentationLess(leftOrder *int, leftColumn string, rightOrder *int, rightColumn string) bool { + if (leftOrder == nil) != (rightOrder == nil) { + return leftOrder != nil + } + if leftOrder != nil && *leftOrder != *rightOrder { + return *leftOrder < *rightOrder + } + return leftColumn < rightColumn +} + +func presentationOrder(column Column) (class, order int) { + if column.Table == nil { + return 2, 0 + } + if column.Table.Order == nil { + return 1, 0 + } + return 0, *column.Table.Order +} + func (w Workspace) Digest() (string, error) { raw, err := w.CanonicalJSON() if err != nil { diff --git a/internal/explorer/authoringv2/workspace_test.go b/internal/explorer/authoringv2/workspace_test.go index d224b577..3545bf8c 100644 --- a/internal/explorer/authoringv2/workspace_test.go +++ b/internal/explorer/authoringv2/workspace_test.go @@ -1,6 +1,7 @@ package authoringv2 import ( + "encoding/json" "fmt" "strings" "testing" @@ -10,6 +11,46 @@ func workspaceDocument(id string) Document { return Document{Kind: Kind, Output: Output{ID: id, Title: id}, RootNodeID: "patient", RouteSteps: []RouteStep{}, Selections: []Selection{{CandidateID: "patient-id", OccurrenceID: RootOccurrenceID, ProjectionMode: "SCALAR"}}, Presentation: map[string]Presentation{}} } +func TestWorkspaceCanonicalizesDuplicateTableOrdersByStableColumnIdentity(t *testing.T) { + visible, duplicateOrder := true, 4 + column := func(name string) Column { + return Column{Column: name, Label: name, OccurrenceID: RootOccurrenceID, Source: ColumnSource{Kind: SourceProjectID}, Table: &TablePresentation{Visible: &visible, Order: &duplicateOrder}, Filter: &FilterPresentation{Order: &duplicateOrder}, Chart: &ChartPresentation{Type: "bar", Order: &duplicateOrder}} + } + workspace := Workspace{ + APIVersion: APIVersion, Kind: WorkspaceKind, Explorer: ExplorerMetadata{Title: "Stable"}, + Documents: []Document{{Kind: Kind, Output: Output{ID: "out", Title: "Out"}, RootResourceType: "Patient", Route: RouteNode{OccurrenceID: RootOccurrenceID, ResourceType: "Patient"}, Columns: []Column{column("zeta"), column("alpha"), column("middle")}}}, + Tabs: []Tab{{ID: "tab", Title: "Out", OutputID: "out", Order: 0, Visible: true}}, + } + reversed := workspace + reversed.Documents = append([]Document(nil), workspace.Documents...) + reversed.Documents[0].Columns = []Column{column("middle"), column("zeta"), column("alpha")} + + first, err := workspace.CanonicalJSON() + if err != nil { + t.Fatal(err) + } + second, err := reversed.CanonicalJSON() + if err != nil { + t.Fatal(err) + } + if string(first) != string(second) { + t.Fatalf("canonical workspaces differ:\n%s\n%s", first, second) + } + var normalized Workspace + if err := json.Unmarshal(first, &normalized); err != nil { + t.Fatal(err) + } + columns := normalized.Documents[0].Columns + for index, want := range []string{"alpha", "middle", "zeta"} { + if columns[index].Column != want || columns[index].Table == nil || columns[index].Table.Order == nil || *columns[index].Table.Order != index || columns[index].Filter == nil || columns[index].Filter.Order == nil || *columns[index].Filter.Order != index || columns[index].Chart == nil || columns[index].Chart.Order == nil || *columns[index].Chart.Order != index { + t.Fatalf("column[%d]=%#v, want %q at normalized order %d", index, columns[index], want, index) + } + } + if *workspace.Documents[0].Columns[0].Table.Order != duplicateOrder || *workspace.Documents[0].Columns[0].Filter.Order != duplicateOrder || *workspace.Documents[0].Columns[0].Chart.Order != duplicateOrder { + t.Fatal("normalization mutated the caller's workspace") + } +} + func fiveTableWorkspace() Workspace { w := Workspace{APIVersion: APIVersion, Kind: WorkspaceKind, Documents: []Document{}, Tabs: []Tab{}} for i := 0; i < 5; i++ { diff --git a/internal/explorer/compilation/semantic_compile.go b/internal/explorer/compilation/semantic_compile.go index 02a8a889..c1823bec 100644 --- a/internal/explorer/compilation/semantic_compile.go +++ b/internal/explorer/compilation/semantic_compile.go @@ -110,9 +110,17 @@ func compileSemanticDocument(ctx context.Context, project, explorerID string, do presented := PresentationColumn{EmissionID: emissionID, PublicColumn: column.Column, Label: column.Label, Visible: visible, Order: orderValue, Pinned: pinned} if column.Filter != nil { presented.FilterLabel = firstNonEmpty(column.Filter.Label, column.Label) + presented.FilterOrder = index + if column.Filter.Order != nil { + presented.FilterOrder = *column.Filter.Order + } } if column.Chart != nil { presented.ChartType, presented.ChartTitle = column.Chart.Type, column.Chart.Title + presented.ChartOrder = index + if column.Chart.Order != nil { + presented.ChartOrder = *column.Chart.Order + } } presentation.Columns = append(presentation.Columns, presented) contract.Columns = append(contract.Columns, OutputColumn{Column: column.Column, Label: column.Label, LogicalType: logicalType, Filterable: filterable, Chartable: chartable}) diff --git a/internal/explorer/compilation/translate.go b/internal/explorer/compilation/translate.go index 8ae772a6..70e616ca 100644 --- a/internal/explorer/compilation/translate.go +++ b/internal/explorer/compilation/translate.go @@ -20,7 +20,7 @@ import ( "github.com/calypr/loom/internal/explorer/capability" ) -const TranslationVersion = "authoring-v2-native-3" +const TranslationVersion = "authoring-v2-native-4" // Error is a structured translation failure. Stage, Code, Path, and Details // are intentionally transport-neutral so an HTTP adapter can map it to its @@ -94,8 +94,10 @@ type PresentationColumn struct { Order int `json:"order"` Pinned bool `json:"pinned"` FilterLabel string `json:"filterLabel,omitempty"` + FilterOrder int `json:"filterOrder,omitempty"` ChartType string `json:"chartType,omitempty"` ChartTitle string `json:"chartTitle,omitempty"` + ChartOrder int `json:"chartOrder,omitempty"` } type OutputColumn = explorer.PublicOutputColumn @@ -126,6 +128,7 @@ func CompileWorkspace(ctx context.Context, project, explorerID string, workspace if err := (authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, Workspace: &workspace, Catalog: wire}).Validate(); err != nil { return WorkspaceResult{}, fail("intent", "INVALID_AUTHORING_INTENT", "$.workspace", err.Error(), nil, err) } + workspace = workspace.NormalizePresentationOrders() result := WorkspaceResult{Workspace: workspace, Bundle: recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Name: "explorer_" + safeName(project) + "_" + safeName(explorerID), TranslationVersion: TranslationVersion}, EmittedColumns: []EmittedColumn{}, IdentityMappings: []IdentityMapping{}, Presentations: []PresentationConfig{}, OutputContracts: []OutputContract{}} for i, document := range workspace.Documents { compiled, err := Compile(ctx, project, explorerID, document, snapshot) @@ -576,9 +579,17 @@ func makePresentation(d authoringv2.Document, emitted []EmittedColumn, snapshot } if p.Filter != nil { column.FilterLabel = p.Filter.Label + column.FilterOrder = i + if p.Filter.Order != nil { + column.FilterOrder = *p.Filter.Order + } } if p.Chart != nil { column.ChartType, column.ChartTitle = p.Chart.Type, p.Chart.Title + column.ChartOrder = i + if p.Chart.Order != nil { + column.ChartOrder = *p.Chart.Order + } } result.Columns = append(result.Columns, column) } diff --git a/internal/explorer/compilation_receipt.go b/internal/explorer/compilation_receipt.go index 39d09326..5a4bd233 100644 --- a/internal/explorer/compilation_receipt.go +++ b/internal/explorer/compilation_receipt.go @@ -23,7 +23,7 @@ const ( CompilationReceiptFormatVersion = 2 // CompilationReceiptCompilerContractVersion changes when compilation // semantics change in a way that can alter a resolved receipt. - CompilationReceiptCompilerContractVersion = "loom.explorer.compiler/v6" + CompilationReceiptCompilerContractVersion = "loom.explorer.compiler/v7" // Short aliases make the current contract convenient for repositories and // callers that do not need to distinguish the receipt prefix. diff --git a/internal/server/explorer_authoring_v2_routes.go b/internal/server/explorer_authoring_v2_routes.go index b6e36fc5..f6761332 100644 --- a/internal/server/explorer_authoring_v2_routes.go +++ b/internal/server/explorer_authoring_v2_routes.go @@ -575,6 +575,11 @@ func applyAuthorizedScope(bindings *recipe.RuntimeBindings, authorized Authorize } func v2ReceiptResponse(receipt *explorer.CompilationReceipt, workspace authoringv2.Workspace) explorerv2api.CompileResponse { + if receipt != nil && len(receipt.NormalizedBundle) != 0 { + if normalized, err := authoringv2.DecodeWorkspace(receipt.NormalizedBundle); err == nil { + workspace = normalized + } + } outputs := make([]explorerv2api.ReceiptOutput, 0, len(workspace.Documents)) for _, document := range workspace.Documents { rowGrain := "" @@ -602,7 +607,7 @@ func v2ReceiptResponse(receipt *explorer.CompilationReceipt, workspace authoring Kind: explorerv2api.ExplorerBuilderReceipt, ReceiptId: receipt.ID, SnapshotToken: receipt.SnapshotToken, Generation: receipt.SourceGeneration, IntentDigest: receipt.IntentDigest, - CompilerVersion: "explorer-authoring-v2", Builder: workspace, + CompilerVersion: explorer.CurrentCompilerContractVersion + "+" + explorercompilation.TranslationVersion, Builder: workspace, Outputs: outputs, Diagnostics: []explorerv2api.Diagnostic{}, } } diff --git a/internal/server/explorer_receipt_contract.go b/internal/server/explorer_receipt_contract.go index 49371d0e..c7685485 100644 --- a/internal/server/explorer_receipt_contract.go +++ b/internal/server/explorer_receipt_contract.go @@ -57,9 +57,27 @@ func compiledExplorerWorkspaceConfigV2(project, explorerID string, compiled expl cellRenderer = authored.Table.CellRenderer } view.Table.Columns = append(view.Table.Columns, explorer.ConfigColumn{Column: column.PublicColumn, Label: column.Label, Visible: column.Visible, Pinned: column.Pinned, CellRenderer: cellRenderer}) + } + filterColumns := append([]explorercompilation.PresentationColumn(nil), presentation.Columns...) + sort.SliceStable(filterColumns, func(i, j int) bool { + if filterColumns[i].FilterOrder != filterColumns[j].FilterOrder { + return filterColumns[i].FilterOrder < filterColumns[j].FilterOrder + } + return filterColumns[i].EmissionID < filterColumns[j].EmissionID + }) + for _, column := range filterColumns { if column.FilterLabel != "" { view.Filters = append(view.Filters, explorer.ConfigFilter{Column: column.PublicColumn, Label: column.FilterLabel}) } + } + chartColumns := append([]explorercompilation.PresentationColumn(nil), presentation.Columns...) + sort.SliceStable(chartColumns, func(i, j int) bool { + if chartColumns[i].ChartOrder != chartColumns[j].ChartOrder { + return chartColumns[i].ChartOrder < chartColumns[j].ChartOrder + } + return chartColumns[i].EmissionID < chartColumns[j].EmissionID + }) + for _, column := range chartColumns { if column.ChartType != "" { view.Charts = append(view.Charts, explorer.ConfigChart{Column: column.PublicColumn, Type: column.ChartType, Title: column.ChartTitle}) } diff --git a/internal/server/explorer_receipt_contract_test.go b/internal/server/explorer_receipt_contract_test.go index ae76b7d0..fb3bf97c 100644 --- a/internal/server/explorer_receipt_contract_test.go +++ b/internal/server/explorer_receipt_contract_test.go @@ -77,6 +77,44 @@ func TestCompileValidatedReceiptResolutionChecksAllOutputsForScopedPreview(t *te } } +func TestCompiledExplorerWorkspaceConfigUsesIndependentStablePresentationOrders(t *testing.T) { + compiled := explorercompilation.WorkspaceResult{ + Workspace: authoringv2.Workspace{ + APIVersion: authoringv2.APIVersion, Kind: authoringv2.WorkspaceKind, + Explorer: authoringv2.ExplorerMetadata{Title: "Stable"}, + Documents: []authoringv2.Document{{Kind: authoringv2.Kind, Output: authoringv2.Output{ID: "out", Title: "Out"}}}, + Tabs: []authoringv2.Tab{{ID: "tab", Title: "Out", OutputID: "out", Order: 0, Visible: true}}, + }, + Bundle: recipe.Bundle{RecipeSchemaVersion: recipe.CurrentSchemaVersion, Outputs: []recipe.Output{{Name: "out"}}}, + EmittedColumns: []explorercompilation.EmittedColumn{ + {EmissionID: "column_b", OutputID: "out", PublicColumn: "column_b"}, + {EmissionID: "column_a", OutputID: "out", PublicColumn: "column_a"}, + }, + Presentations: []explorercompilation.PresentationConfig{{OutputID: "out", Columns: []explorercompilation.PresentationColumn{ + {EmissionID: "column_b", PublicColumn: "column_b", Label: "B", Visible: true, Order: 0, FilterLabel: "B", FilterOrder: 0, ChartType: "bar", ChartOrder: 0}, + {EmissionID: "column_a", PublicColumn: "column_a", Label: "A", Visible: true, Order: 0, FilterLabel: "A", FilterOrder: 0, ChartType: "line", ChartOrder: 1}, + }}}, + } + raw, err := compiledExplorerWorkspaceConfigV2("project-a", "explorer-a", compiled) + if err != nil { + t.Fatal(err) + } + var config explorer.ConfigV2 + if err := json.Unmarshal(raw, &config); err != nil { + t.Fatal(err) + } + view := config.Views[0] + if view.Table.Columns[0].Column != "column_a" || view.Table.Columns[1].Column != "column_b" { + t.Fatalf("table order=%#v", view.Table.Columns) + } + if view.Filters[0].Column != "column_a" || view.Filters[1].Column != "column_b" { + t.Fatalf("filter order=%#v", view.Filters) + } + if view.Charts[0].Column != "column_b" || view.Charts[1].Column != "column_a" { + t.Fatalf("chart order=%#v", view.Charts) + } +} + func TestNativeV2RouteUsesAuthorizedPersistedReceipt(t *testing.T) { snapshot := testAuthoringV2CapabilitySnapshot() scope := authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted} @@ -136,11 +174,16 @@ func TestNativeV2RouteUsesAuthorizedPersistedReceipt(t *testing.T) { t.Fatalf("compile mutated active or draft state: %#v", ownerAfterCompile) } var result struct { - ReceiptID string `json:"receiptId"` + ReceiptID string `json:"receiptId"` + CompilerVersion string `json:"compilerVersion"` } if err := json.Unmarshal([]byte(compiled.Body), &result); err != nil { t.Fatal(err) } + wantCompilerVersion := explorer.CurrentCompilerContractVersion + "+" + explorercompilation.TranslationVersion + if result.CompilerVersion != wantCompilerVersion { + t.Fatalf("compilerVersion=%q, want %q", result.CompilerVersion, wantCompilerVersion) + } preview := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/preview", `{"receiptId":"`+result.ReceiptID+`","outputId":"patients","limit":5}`) if preview.StatusCode != http.StatusOK { t.Fatalf("preview status=%d body=%s", preview.StatusCode, preview.Body) diff --git a/internal/server/server.go b/internal/server/server.go index 7952ce28..3263f4d9 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -380,7 +380,7 @@ func run(ctx context.Context, serverConfig Config) error { if err := validateAuthorizedReadScope(authorized.Scope, snapshot.Identity.AuthorizationScopeDigest); err != nil { return nil, capability.ErrStaleSnapshot } - workspace := request.Workspace + workspace := request.Workspace.NormalizePresentationOrders() intentDigest, err := workspace.Digest() if err != nil { return nil, err @@ -389,13 +389,6 @@ func run(ctx context.Context, serverConfig Config) error { if err != nil { return nil, err } - preflight := explorer.CompilationReceipt{ReceiptFormatVersion: explorer.CurrentReceiptFormatVersion, CompilerContractVersion: explorer.CurrentCompilerContractVersion, Project: projectid.Canonical(request.Project), ExplorerID: request.ExplorerID, IntentDigest: intentDigest, SnapshotToken: request.SnapshotToken, AuthorizationScopeDigest: snapshot.Identity.AuthorizationScopeDigest, CapabilitySchemaDigest: snapshot.Identity.SchemaDigest, SourceGeneration: snapshot.Identity.Generation, NormalizedBundle: normalized} - if key, keyErr := explorer.CompilationKey(preflight); keyErr == nil { - if prior, lookupErr := explorerService.CompilationReceiptByCompilationKey(ctx, request.Project, request.ExplorerID, key); lookupErr == nil && prior != nil && prior.ReceiptFormatVersion == explorer.CurrentReceiptFormatVersion && prior.CompilerContractVersion == explorer.CurrentCompilerContractVersion { - logger.Info("Explorer receipt compile hit", "project", projectid.Canonical(request.Project), "explorer_id", request.ExplorerID, "receipt_id", prior.ID, "duration_ms", time.Since(started).Milliseconds()) - return prior, nil - } - } translated, err := explorercompilation.CompileWorkspace(ctx, request.Project, request.ExplorerID, workspace, snapshot) if err != nil { return nil, err @@ -448,6 +441,10 @@ func run(ctx context.Context, serverConfig Config) error { if err != nil { return nil, err } + verificationBindings := recipe.RuntimeBindings{Project: projectid.Legacy(request.Project), DatasetGeneration: snapshot.Identity.Generation, AuthResourcePaths: append([]string(nil), authorized.Scope.AuthResourcePaths...), AuthScopeMode: authorized.Scope.Mode} + if _, err := compileValidatedReceiptResolution(ctx, recipeEngine, stored, verificationBindings); err != nil { + return nil, explorerConflict("compile", "COMPILATION_NONDETERMINISTIC", "the compiler could not reproduce the stored receipt artifact", map[string]any{"receiptId": stored.ID}) + } receiptBytes := 0 if raw, marshalErr := json.Marshal(stored); marshalErr == nil { receiptBytes = len(raw) From 26579c7b6dc19d69f637a9ee0d501770c65f4822 Mon Sep 17 00:00:00 2001 From: matthewpeterkort Date: Fri, 28 Aug 2026 15:05:11 -0700 Subject: [PATCH 11/15] fix ci --- .github/workflows/tests.yaml | 5 +- docs/EXPLORER_AUTHORING.md | 100 ++- docs/EXPLORER_COMPILATION_ARCHITECTURE.md | 19 +- docs/LOOM_EXPLORER_ARCHITECTURE_POSTMORTEM.md | 10 +- docs/PLAN_BACKEND_OWNED_EXPLORER_AUTHORING.md | 799 ++++++++++++++++++ docs/PLAN_EXPLORER_V2_BRANCHED_TRAVERSAL.md | 282 +++++++ docs/README.md | 3 + .../explorer-v2-capability-authoring.md | 2 +- internal/explorer/authoringv2/commands.go | 600 +++++++++++++ .../explorer/authoringv2/commands_test.go | 121 +++ internal/explorer/authoringv2/types.go | 21 +- .../explorer/authoringv2/workspace_test.go | 17 +- internal/explorer/service.go | 122 +++ internal/explorer/store.go | 17 +- internal/explorer/types.go | 33 +- .../server/explorer_authoring_v2_routes.go | 85 +- internal/server/explorer_builder_lifecycle.go | 7 +- .../server/explorer_receipt_contract_test.go | 94 ++- 18 files changed, 2266 insertions(+), 71 deletions(-) create mode 100644 docs/PLAN_BACKEND_OWNED_EXPLORER_AUTHORING.md create mode 100644 docs/PLAN_EXPLORER_V2_BRANCHED_TRAVERSAL.md create mode 100644 internal/explorer/authoringv2/commands.go create mode 100644 internal/explorer/authoringv2/commands_test.go diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 008064bf..17f2b776 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -47,8 +47,11 @@ jobs: - name: Generate GraphQL code run: make generate-graphql + - name: Generate Explorer V2 API code + run: make generate-explorer-v2 + - name: Check generated code is current - run: git diff --exit-code -- generated/fhir generated/fhirschema generated/graphql + run: git diff --exit-code -- generated/fhir generated/fhirschema generated/graphql generated/explorerv2 - name: Run GraphQL contract checks run: make graphql-check diff --git a/docs/EXPLORER_AUTHORING.md b/docs/EXPLORER_AUTHORING.md index ebfcf3ce..015fc080 100644 --- a/docs/EXPLORER_AUTHORING.md +++ b/docs/EXPLORER_AUTHORING.md @@ -1,10 +1,10 @@ # Explorer authoring The public Builder contract is -`loom.calypr.org/explorer-authoring/v2`. The browser submits semantic intent -using opaque node, relationship, candidate, occurrence, and receipt IDs. Loom -owns recipe construction, output-column identities, authorization predicates, -physical planning, and AQL. +`loom.calypr.org/explorer-authoring/v2`. The browser submits canonical V2 +workspace documents with typed column sources, route occurrences, and +presentation intent. Loom owns recipe construction, authorization predicates, +physical planning, output contracts, and AQL. For the complete wire contract and frontend checklist, see [Explorer V2 capability authoring](frontend/explorer-v2-capability-authoring.md). @@ -22,19 +22,20 @@ All routes are under: | Operation | Route | Contract | | --- | --- | --- | | Read capability | `GET /capability` | exact active compiler-proven snapshot | -| Read Builder | `GET /builder` | capability plus active V2 document when present | -| Compile | `POST /compile` | `{document, snapshotToken}` | +| Read Builder | `GET /builder` | capability plus saved/active V2 workspace when present | +| Save draft | `PUT /draft` | `{workspace, snapshotToken, expectedDraftVersion, expectedDraftDigest?}` | +| Export workspace | `GET /export` | canonical portable V2 workspace | +| Compile | `POST /compile` | `{workspace, snapshotToken}` | | Compile alias | `POST /builder` | same operation for the current frontend | | Suggestions | `GET /capabilities/:snapshotToken/candidates/:candidateId/suggestions` | bounded values for one exact snapshot | | Preview | `POST /preview` | `{receiptId, outputId, limit?}` | | Publish | `POST /publish` | `{receiptId}` | -There is no public V1 authoring route. V1 types and the V1 compiler exist only -to migrate already stored legacy authoring documents. +There is no public V1 authoring route or lazy legacy migration path. -## Builder document +## Builder workspace -A V2 document contains one output, a concrete row-root node, an ordered finite +A V2 workspace contains ordered output documents and tabs. Each document has a concrete row-root node, an ordered finite route, occurrence-specific field selections, projection modes, and presentation preferences. It contains no FHIR selector path, recipe expression, traversal alias, collection name, AQL, or generated output column. @@ -63,16 +64,49 @@ Artifactless receipts created by older servers return ## Draft and publication behavior -The browser may keep its mutable V2 document locally and debounce compile. -Compile-before-preview is the safe fallback when the latest editor state has no -receipt. Concurrent compile responses cannot overwrite each other because each -receipt is immutable and content-addressed. +Loom stores canonical V2 workspace drafts with draft-version and optional +digest compare-and-swap. Repository/ETL publication advances that same version, +so an external replacement produces `DRAFT_CONFLICT` instead of silently +overwriting browser work. Compile-before-preview is the safe fallback when the +latest editor state has no receipt. Receipts remain immutable and +content-addressed. -Publish materializes and verifies the exact receipt before activating its +Repository publication accepts the same V2 workspace and uses the same receipt +compiler as browser publication. Publish materializes and verifies the exact receipt before activating its revision. A materialization, output-verification, or activation failure leaves the previous active revision intact. Active revisions retain the canonical V2 document so Builder reads can restore it directly. +## One-time V2 artifact migration + +Revisions published by an earlier V2 server may predate the revision-level +copies of the workspace, receipt ID, public output contract, or emissions. Run +the explicit migration once; normal Builder and Viewer reads never mutate +stored revisions. + +Dry-run one revision first: + +```bash +go run ./cmd/explorer-v2-artifact-migrate \ + -revision authoring_a46ec8372e6675684b3f58dfa0bf73f9956e3310259a149de5642c76f639677a +``` + +Apply after the report says `REPAIRABLE`: + +```bash +go run ./cmd/explorer-v2-artifact-migrate \ + -revision authoring_a46ec8372e6675684b3f58dfa0bf73f9956e3310259a149de5642c76f639677a \ + -apply +``` + +`ARANGO_URL`, `ARANGO_DATABASE`, `ARANGO_USERNAME`, and `ARANGO_PASSWORD` are +accepted from the environment. Omitting `-revision`, `-project`, and +`-explorer` scans all affected revisions. The migration derives +`receipt_` only for `authoring_` revisions, requires matching +project, Explorer, recipe, generation, and existing artifacts, fills only +missing fields, and reports conflicts without modifying them. Re-running it is +idempotent. + ## Authorization and generation rules Compilation requires the snapshot's generation to be active. Preview may use a @@ -84,6 +118,42 @@ Restricted-empty authorization is not equivalent to unrestricted access. Loom propagates the explicit scope mode and paths through deterministic lowering and execution. The frontend never supplies those predicates. +## Editable traversal trees and ordinary columns + +The V2 route is a finite occurrence tree. Builder clients may add sibling and +nested children through exact catalog edges and may attach ordinary primitive +field columns to any occurrence. `Document.Route` is the only durable route +source; compatibility-only linear route helpers are not an authoring contract. + +Compile and preview may persist and execute immutable receipts, but neither +operation changes the active Explorer revision. Publication is the only +Builder operation that materializes outputs and switches the active revision. + +## Future work TODO: advanced catalog-driven column addition + +The MVP Builder shows configured V2 columns and ordinary catalog field +candidates in one list. A selected catalog field becomes a durable typed +`source.kind: field` column; candidate identity is not retained as a second +authoring model. Existing field columns are reconciled to the list by their +single authoritative `fieldPath`, while typed project, identifier, extension, +coding, and observation sources remain ordinary configured columns. + +Future work is limited to candidate families that need more intent than one +field path, plus new route/table construction. That work must: + +- have Loom return a complete typed V2 column for identifier systems, + extension URLs, coding systems, and observation component codes; +- prove that every advertised candidate compiles under the snapshot that + advertised it; +- restore route and blank-table creation only when at least one valid column + can be added in the same workflow; and +- cover add through compile, preview, export, reload, and publish without + changing configured-column persistence. + +Do not introduce composite frontend matching such as +`occurrenceId + source.kind + source.fieldPath + source.match`. The resulting +typed V2 column remains the durable authoring state. + ## Cleanup Receipts referenced by immutable revisions are retained. Loom exposes receipt diff --git a/docs/EXPLORER_COMPILATION_ARCHITECTURE.md b/docs/EXPLORER_COMPILATION_ARCHITECTURE.md index 162ebaba..4c362eed 100644 --- a/docs/EXPLORER_COMPILATION_ARCHITECTURE.md +++ b/docs/EXPLORER_COMPILATION_ARCHITECTURE.md @@ -124,12 +124,15 @@ and is not semantic recompilation. ## Idempotency and persistence The compilation key covers the canonical intent, snapshot, scope, generation, -schema, receipt format, and compiler contract. Production checks this key -before translation. A hit returns the already persisted receipt. +schema, receipt format, and compiler contract. It is an idempotency identity, +not evidence that a previously stored artifact remains reproducible. Production +therefore rebuilds normalized intent on every explicit compile/recompile. -A miss is translated and validated, then persisted with immutable +The result is validated, then persisted with immutable `INSERT ... OPTIONS { overwriteMode: "ignore" }` semantics. Loom reads and -validates the stored document before returning success. The Arango collection +re-lowers the authoritative stored document with the same verifier used by +preview before returning success. A compile never returns 200 with an artifact +that preview would immediately reject. The Arango collection has a composite index over project, Explorer, compilation key, receipt format, and compiler contract. Receipt lookup for execution is always scoped by project, Explorer, and receipt ID. @@ -141,11 +144,9 @@ serialized bytes, oldest creation time, and unreferenced count. Loom retains explicit orphan purge but does not impose an automatic TTL until real storage measurements justify one. -The compiler records hit/compile duration, serialized receipt bytes, output -count, and public column count. The performance objectives are: - -- uncached compile p95 at or below 250 ms; and -- idempotent receipt lookup p95 at or below 50 ms. +The compiler records verified compile duration, serialized receipt bytes, +output count, and public column count. Performance objectives must be measured +against the complete rebuild-and-verify path and tenant-scoped receipt lookup. The pure native translator benchmark uses a 20-hop, 100-selection document and reports time and allocations. It is not a wall-clock CI assertion; service diff --git a/docs/LOOM_EXPLORER_ARCHITECTURE_POSTMORTEM.md b/docs/LOOM_EXPLORER_ARCHITECTURE_POSTMORTEM.md index 0aa80188..94ab2be0 100644 --- a/docs/LOOM_EXPLORER_ARCHITECTURE_POSTMORTEM.md +++ b/docs/LOOM_EXPLORER_ARCHITECTURE_POSTMORTEM.md @@ -927,10 +927,12 @@ pointer. Persisting the immutable receipt is necessary and is not publication. Compilation is idempotent. The same canonical intent, snapshot, scope, generation, schema, receipt format, and compiler contract produces the same -compilation key and content-addressed receipt ID. Loom performs a tenant-scoped -compilation-key lookup before translating. Arango uses immutable -`INSERT ... overwriteMode: "ignore"` rather than an updating UPSERT, then reads -and validates the stored artifact. +compilation key and content-addressed receipt ID. Explicit compile/recompile +always rebuilds normalized intent; a compilation-key match is not treated as +proof that an old artifact remains reproducible. Arango uses immutable +`INSERT ... overwriteMode: "ignore"` rather than an updating UPSERT, then Loom +reads and re-lowers the stored artifact with the preview verifier before it can +return success. The receipt must be stored before Loom returns a successful Builder reconciliation. Returning success without a retrievable artifact recreates the diff --git a/docs/PLAN_BACKEND_OWNED_EXPLORER_AUTHORING.md b/docs/PLAN_BACKEND_OWNED_EXPLORER_AUTHORING.md new file mode 100644 index 00000000..a934df09 --- /dev/null +++ b/docs/PLAN_BACKEND_OWNED_EXPLORER_AUTHORING.md @@ -0,0 +1,799 @@ +# Backend-owned Explorer authoring plan + +## Outcome + +Move Explorer Builder authoring from a browser-owned document model to a +server-owned command model. The browser should describe a user's intent and +render the authoritative result. Loom should create durable identities, apply +defaults, enforce capability and workspace invariants, persist the canonical +draft, and compile that stored draft. + +The first production milestone is deliberately narrow: + +> Starting from a brand-new Explorer with no workspace, selecting an eligible +> catalog node creates a valid table, saves it, compiles it, and returns an +> immutable receipt without the browser constructing an output ID, tab ID, +> route root, or recipe-facing name. + +This removes the current class of failure where `output.id` passes the public +authoring contract but fails later when Loom reuses it as +`recipe.outputs[].name`. + +## Design principles + +1. **Loom owns durable identity.** Output, tab, occurrence, column, emission, + and recipe-facing identifiers are generated or derived by the backend. +2. **The browser sends intent, not canonical documents.** It may keep temporary + component keys and optimistic visual state, but those values never become + persisted identities. +3. **The saved workspace remains the source of truth.** Commands are an input + protocol; they do not become a second durable authoring model. +4. **Every command is capability-scoped and concurrency-safe.** Structural + commands use the exact snapshot token shown to the user, and every mutation + uses draft version/digest compare-and-swap. +5. **Compilation remains receipt-based.** Commands do not weaken the existing + immutable receipt, preview, or publication boundaries. +6. **Invalid intermediate states are prevented at the mutation boundary.** A + client should not be able to construct a document Loom cannot lower. +7. **Migration is incremental.** Existing V2 workspaces, receipts, revisions, + export, preview, and publication continue to work while the UI moves one + operation at a time. + +## Current boundary and failure mode + +Today the browser submits a complete `Workspace` to `PUT /draft` and +`POST /compile` (with `POST /builder` as a compile alias). That makes the +browser responsible for assembling `Document`, `Output`, `Tab`, `RouteNode`, +`Column`, and their cross-references. + +The contract currently accepts any nonblank `output.id`. Compilation copies +that value directly into a recipe output name, whose grammar is stricter: + +```text +^[A-Za-z_][A-Za-z0-9_]*$ +``` + +Consequently, a browser-created UUID, slug containing `-`, label containing a +space, or digit-prefixed value survives authoring validation and fails during +recipe lowering. Debouncing the request only delays the same failure. + +The deeper issue is not just missing validation. A UI implementation should +not have to know recipe identifier rules in order to express “create a table +for this catalog node.” + +## Target request flow + +```text +Browser Loom + | | + | GET /builder | + |--------------------------->| + | workspace:null + catalog | + | + draft version/digest | + |<---------------------------| + | | + | CREATE_TABLE intent | + | nodeId + title + CAS | + |--------------------------->| + | | load/initialize workspace + | | authorize snapshot + | | generate output/tab IDs + | | resolve node to root type + | | validate + canonicalize + | | save draft with CAS + | authoritative workspace | + | + draft version/digest | + |<---------------------------| + | | + | reconcile stored draft | + |--------------------------->| + | immutable receipt | + |<---------------------------| +``` + +The frontend still owns interaction and presentation decisions. It does not +own durable identities, canonical defaults, cross-document referential +integrity, or compiler-facing names. + +## UI compatibility requirement + +This migration must not redesign the Builder UI. Existing controls, selection +behavior, table layout, loading indicators, preview dialog, publish flow, and +diagnostic panel remain visually and behaviorally equivalent. The change is +below the component boundary: + +```text +existing UI event + | + v +frontend Builder action/store + | + v +typed Loom command API + | + v +authoritative workspace response + | + v +existing UI view model +``` + +Do not make React components construct `Workspace`, `Document`, `Output`, +`Tab`, `RouteNode`, or `Column` wire objects. Components continue to report +events such as “root selected,” “candidate checked,” “column hidden,” and +“preview clicked.” A frontend integration layer maps those events to commands +and maps the returned workspace back into the existing view model. + +Temporary component keys are allowed for rendering a pending optimistic row or +table. They are UI-only, must be clearly typed as temporary, and must be +replaced by the backend response. They must never be sent as `outputId`, +`tabId`, `occurrenceId`, or `column`. + +## Frontend API migration + +The frontend implementation target is the existing IDP frontend Builder. The +first frontend task is to identify its current API module, Builder store, and +event handlers; the migration should modify those seams rather than rewrite +components. + +### Typed API client + +Generate request/response types and runtime validators from the updated +Explorer authoring OpenAPI document. The Builder-facing API module should +expose this small surface: + +```ts +interface ExplorerAuthoringApi { + getCapability(project: string, explorerId: string): Promise; + getBuilder(project: string, explorerId: string): Promise; + applyCommands( + project: string, + explorerId: string, + request: ApplyCommandsRequest, + signal?: AbortSignal, + ): Promise; + reconcile( + project: string, + explorerId: string, + request: ReconcileRequest, + signal?: AbortSignal, + ): Promise; + preview( + project: string, + explorerId: string, + request: PreviewRequest, + signal?: AbortSignal, + ): Promise; + publish( + project: string, + explorerId: string, + request: PublishRequest, + signal?: AbortSignal, + ): Promise; +} +``` + +Ordinary Builder code must stop calling `saveWorkspaceDraft`/`PUT /draft`, +`compileWorkspace`/`POST /builder`, or `POST /compile` with locally assembled +workspace content. Keep any whole-document calls in a separately named import +or compatibility module so a normal UI action cannot accidentally use them. + +### Existing UI event to new call mapping + +| Existing user action | Current client behavior to remove | New frontend call | Authoritative frontend update | +| --- | --- | --- | --- | +| Open Builder | GET Builder and sometimes fabricate an empty workspace | `GET /builder` | Store nullable workspace, catalog, snapshot token, draft version/digest | +| Click first/root node | Construct output/document/tab IDs and POST the workspace | `CREATE_TABLE {rootNodeId, title?}` | Replace workspace and select returned `outputId` | +| Add another table | Clone/build a document and tab locally | `CREATE_TABLE {rootNodeId, title?, afterOutputId?}` | Replace workspace; select returned table if current UX does so | +| Delete table | Splice documents/tabs and repair references locally | `DELETE_TABLE {outputId}` | Replace workspace and derive the next selected table from the response | +| Rename table | Patch document and tab titles locally | `RENAME_TABLE {outputId, title}` | Replace workspace while preserving current focus behavior | +| Reorder tables | Rewrite tab order locally | `REORDER_TABLES {outputIds}` | Render backend-normalized order | +| Change root | Rewrite root and clear dependent state locally | `SET_TABLE_ROOT {outputId, rootNodeId}` | Replace workspace and clear selections exactly as returned | +| Add route node | Build route/occurrence IDs locally | `ADD_ROUTE {outputId, parentOccurrenceId, edgeId}` | Expand/select the returned occurrence | +| Remove route node | Delete route subtree and dependent references locally | `REMOVE_ROUTE {outputId, occurrenceId}` | Replace route, columns, filters, and actions from the response | +| Check/add field | Construct a typed/physical column locally | `ADD_COLUMN {outputId, occurrenceId, candidateId, projectionMode?}` | Render the returned backend-created column | +| Uncheck/remove field | Splice column and dependent state locally | `REMOVE_COLUMN {outputId, columnId}` | Replace workspace from the response | +| Change visibility/order/label | Patch presentation object and autosave complete workspace | `UPDATE_COLUMN_PRESENTATION` (batchable) | Replace normalized presentation state | +| Autosave fires | PUT complete workspace | No separate call; every successful command is already persisted | Update saved indicator from returned draft version/digest | +| Preview clicked | Compile current local workspace if receipt is missing, then preview | Reconcile the current stored draft if needed, then `POST /preview` | Cache receipt by draft digest; render existing preview UI | +| Publish clicked | Compile local workspace if needed, then publish | Reconcile the current stored draft if needed, then `POST /publish {receiptId}` | Replace publication/active state from the response | +| Reload/reset | Rehydrate local document edits | `GET /builder` | Replace the Builder store with authoritative server state | + +This table is the frontend work package. A backend command is not considered +delivered until the corresponding existing UI action uses it end to end. + +### Frontend store state + +The frontend store should hold server state and request coordination, not a +second canonical authoring document: + +```ts +interface BuilderServerState { + workspace: Workspace | null; + catalog: CatalogSnapshot; + snapshotToken: string; + draftVersion: number; + draftDigest: string; + pendingCommands: PendingCommand[]; + receiptByDraftDigest: Record; + lastAppliedCommandId?: string; +} +``` + +The workspace is replaced from successful server responses. Do not merge the +response into a locally constructed workspace field by field. Existing UI +selectors may continue to derive selected table, route tree, candidate state, +and presentation from this workspace. + +Component selection state that is not durable—open panels, focus, search text, +scroll position, and temporary optimistic keys—remains local and is reconciled +using backend-returned identities. + +### Command dispatch and ordering + +Mutating commands for one Explorer must be serialized through one frontend +queue because each response advances the draft version and digest: + +1. Read the latest `draftVersion`, `draftDigest`, and `snapshotToken` from the + store when dispatch begins, not when a click handler is created. +2. Assign an ephemeral idempotency `commandId`. This is a request token, not a + domain identity; the backend still creates every durable authoring ID. +3. Send the command with the current CAS values. +4. On success, atomically replace workspace/version/digest and apply the typed + result to ephemeral selection/focus state. +5. Dispatch the next queued command using the returned CAS values. +6. Mark every cached receipt for an older draft digest as stale for preview and + publication purposes; retaining it for request completion is harmless. + +Presentation changes that currently debounce may be coalesced into one command +batch before dispatch. Structural commands should preserve user order and must +not be silently collapsed. + +Reconcile requests may be canceled in the browser when a newer mutation is +queued. Loom may still finish and persist the old immutable receipt; the +frontend ignores it unless its `intentDigest` matches the current draft +digest. This preserves the existing responsive UI without relying on request +timing for correctness. + +### Preview and publish orchestration + +The UI-facing `preview()` action becomes: + +```text +flush pending command queue + -> find receipt for current draftDigest + -> if absent, POST /reconcile for current version/digest + -> verify returned intentDigest == current draftDigest + -> POST /preview with receiptId + selected outputId + limit + -> always clear the existing preview loading state +``` + +The UI-facing `publish()` action uses the same receipt check, then sends only +`{receiptId}` to the existing publish route. It must not publish while commands +are pending or use a receipt associated with an older draft digest. + +This orchestration belongs in the store/action layer so existing Preview and +Publish components keep the same callbacks and visual states. + +### Frontend error behavior + +Use the existing Builder attention/diagnostic surface; this migration does not +require new screens. + +- `DRAFT_CONFLICT`: stop the command queue, GET Builder, replace authoritative + state, retain the rejected high-level command for an explicit retry, and + clear pending indicators. Do not PUT a merged workspace. +- `STALE_CATALOG_SNAPSHOT`: refresh Builder/catalog state. Retry automatically + only if the referenced node/edge/candidate still exists and the user action + has not been superseded; otherwise retain the selection intent and show the + existing diagnostic. +- `INVALID_COMMAND` or a command-specific `422`: leave authoritative workspace + unchanged and bind the diagnostic to the existing control when a JSON path + or entity ID is present. +- `503` or network failure: retain the queued intent and allow retry with the + same `commandId`; do not generate a replacement domain ID or mutate the + canonical workspace locally. +- Canceled reconcile/preview: clear loading state and suppress an error only + when cancellation was caused by a newer local action. +- Older command/reconcile response: ignore it unless its returned draft + version/digest still matches the current store. + +### Capability negotiation and coordinated deployment + +Extend `GET /capability` to advertise command and stored-draft reconcile +support explicitly, for example through `operations: [commands, reconcile]` +and command-family feature flags. The frontend must not discover support by +issuing a request and interpreting `404`. + +Deploy in this order: + +1. Backend ships schemas, command/reconcile routes, and capability flags with + flags disabled or unavailable until ready. +2. Frontend ships the new API/store adapter but continues using the existing + path when the advertised operation is absent during the migration window. +3. Enable the command path for coordinated environments and verify the shared + contract suite. +4. Make commands mandatory for supported browser versions. +5. Remove the browser fallback only after deployment telemetry shows the + supported backend fleet advertises the new operations. + +Fallback is temporary compatibility, not route probing. A partially supported +command family must remain disabled in the UI adapter until every operation +needed by that existing UI workflow is advertised. + +### Shared backend/frontend contract suite + +Check request/response fixtures generated from the OpenAPI contract into a +location consumable by both repositories. At minimum, share fixtures for: + +- nullable blank Builder state; +- successful `CREATE_TABLE` including backend-owned output/tab IDs; +- idempotent replay of the same create command; +- stale draft version conflict; +- stale snapshot rejection; +- add/remove column with backend-owned column identity; +- reconcile of an exact stored draft digest; +- ignored stale reconcile response; and +- preview/publish using the receipt for the current draft. + +The backend runs producer contract tests. The frontend runs consumer tests +through its real API adapter and Builder store, plus its existing component +tests to prove the rendered controls and interactions did not change. + +## Proposed additive API + +Keep the existing V2 namespace and add an operation-oriented surface. The +workspace schema remains V2 and the new routes are additive. + +### Read authoritative Builder state + +Extend `GET /builder` so its response includes the CAS metadata required by +the next command: + +```json +{ + "apiVersion": "loom.calypr.org/explorer-authoring/v2", + "kind": "ExplorerBuilderState", + "lifecycleState": "NEW", + "workspace": null, + "draftVersion": 0, + "draftDigest": "", + "catalog": {} +} +``` + +For a saved draft, return that draft's version and digest. When Builder falls +back to an active revision because no draft body exists, still return the +Explorer owner's current draft CAS values; the first command creates a new +draft from the active workspace against those values. The frontend must never +guess a version based on whether `workspace` is null. + +### Apply commands + +```http +POST /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/commands +Content-Type: application/json +``` + +```json +{ + "commandId": "01K...", + "snapshotToken": "...", + "expectedDraftVersion": 0, + "expectedDraftDigest": "", + "commands": [ + { + "type": "CREATE_TABLE", + "rootNodeId": "catalog-node-id", + "title": "Patients" + } + ] +} +``` + +Response: + +```json +{ + "commandId": "01K...", + "workspace": {}, + "draftVersion": 1, + "draftDigest": "sha256:...", + "results": [ + { + "type": "TABLE_CREATED", + "outputId": "out_6d1936f0...", + "tabId": "tab_6d1936f0..." + } + ], + "diagnostics": [] +} +``` + +Use an array so one user gesture can atomically express related changes. The +backend applies every command or none of them. + +### Reconcile the stored draft + +```http +POST /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/reconcile +Content-Type: application/json +``` + +```json +{ + "snapshotToken": "...", + "draftVersion": 1, + "draftDigest": "sha256:..." +} +``` + +Loom loads the referenced canonical draft and compiles it. The browser no +longer resubmits mutable workspace content to compile. The response is the +existing immutable compilation receipt response, optionally accompanied by +the authoritative workspace metadata used for compilation. + +Preview and publish remain unchanged and continue to accept a receipt ID. + +## Command model + +Implement commands as a closed, tagged union in the OpenAPI schema and as a +pure authoring-domain reducer. Do not put HTTP, storage, recipe, or publication +logic in the reducer. + +Initial command set: + +| Command | Browser declares | Loom owns | +| --- | --- | --- | +| `CREATE_TABLE` | catalog root node and display title | workspace initialization, output ID, tab ID, root route, order, visibility, defaults | +| `DELETE_TABLE` | output ID | tab removal, shared-filter cleanup, ordering normalization | +| `RENAME_TABLE` | output ID and title | synchronized document/tab presentation | +| `REORDER_TABLES` | ordered output IDs | contiguous authoritative tab ordering | +| `SET_TABLE_ROOT` | output ID and catalog node ID | root resolution and clearing/reconciling invalid routes, columns, filters, and actions | +| `ADD_ROUTE` | output ID, parent occurrence ID, catalog edge ID | occurrence ID, relationship/resource resolution, route insertion | +| `REMOVE_ROUTE` | output ID and occurrence ID | subtree, dependent column/filter/action cleanup | +| `ADD_COLUMN` | output ID, occurrence ID, candidate ID, projection intent | typed `Column`, physical column name, label/type/capabilities, presentation defaults | +| `REMOVE_COLUMN` | output ID and column identity | dependent filters/actions/shared bindings cleanup | +| `UPDATE_COLUMN_PRESENTATION` | visibility/order/label/pinning/chart/filter intent | validation and normalized order | +| `SET_FIXED_FILTER` | output ID, column identity, values | typed validation and canonical filter replacement | +| `SET_ACTIONS` | output ID and action intent | valid column references and canonical action representation | + +Start with `CREATE_TABLE`, `DELETE_TABLE`, `ADD_COLUMN`, and `REMOVE_COLUMN`. +They cover the first useful end-to-end Builder without prematurely designing +every presentation operation. + +## Identity policy + +Durable IDs must be opaque to the browser and stable across title changes. +They must not be derived only from user-visible labels. + +For the first implementation, generate recipe-safe IDs directly: + +```text +output: out_ +tab: tab_ +occurrence: occ_ (root remains "base") +column: col_ +``` + +The generator lives in `internal/explorer/authoringv2`, validates its own +output against the downstream recipe/physical-name grammar, and is covered by +property tests. The browser treats every returned ID as an opaque string. + +Use `commandId` as an idempotency key. A retry after a lost response must +return the prior result rather than create a second table. The durable design +should store a small command result keyed by project, Explorer, and command ID. +A deterministic ID derived from that tuple can simplify the first vertical +slice, but it does not replace command replay records for non-create commands. + +Longer term, consider separating opaque authoring identity from recipe-facing +physical names. That is not required for this migration and should not block +backend ownership. + +## Backend structure + +Add these boundaries: + +```text +internal/explorer/authoringv2/ + command_types.go closed command/result types + command_apply.go pure Apply(workspace, snapshot, commands) + identity.go server-owned ID generation + command_errors.go stable command diagnostics and paths + +internal/explorer/ + service.go orchestration: load, initialize, apply, CAS-save + +internal/server/ + explorer_authoring_v2_routes.go + HTTP authorization, strict decoding, response mapping +``` + +The service operation should perform: + +1. Load the Explorer identity and current draft. +2. If no draft exists, load the active workspace or initialize an empty + workspace using server-owned Explorer metadata. +3. Resolve and authorize the exact capability snapshot token. +4. Apply all commands to an in-memory copy. +5. Validate and canonicalize the resulting workspace. +6. Save with expected version and digest. +7. Persist the idempotency result. +8. Return the stored workspace and its new version/digest. + +The existing Arango draft write already performs compare-and-swap. Before +building commands on it, correct the `Store.SaveDraft` interface comment that +currently describes last-write-wins behavior and add adapter conformance tests +so every implementation has the same CAS semantics. + +## Validation ownership + +Even after the frontend stops creating IDs, close the current validation gap: + +- define one reusable backend predicate for recipe-safe output identity; +- apply it in `Document.Validate`, not only after lowering; +- add the same pattern to the OpenAPI schema as documentation and generated + client guidance, not as the source of truth; +- return an authoring diagnostic at + `$.workspace.documents[n].output.id` rather than wrapping it only as + `DOCUMENT_COMPILE_FAILED` at the document level; and +- audit tab, occurrence, and column identity constraints for the same kind of + authoring/compiler mismatch. + +Backend validation remains mandatory even when all known clients use commands. +Import, repository, migration, and older-client paths can still submit complete +documents during the transition. + +## Concurrency and idempotency + +- Require `expectedDraftVersion`; accept `expectedDraftDigest` as an additional + guard. +- Return `409 DRAFT_CONFLICT` with the current version/digest when CAS fails. +- Do not silently apply a command to a different draft revision. +- Do not let the frontend retry by replacing the entire workspace. +- Make exact `commandId` replay return the original result. +- Reject reuse of one `commandId` with different command content. +- Keep command application atomic for command arrays. +- Add a bounded command-result retention policy only after published usage data + exists; correctness comes before automatic cleanup. + +Automatic semantic rebasing can be considered later for operations proven to +commute. It should not be part of the initial cutover. + +## Compilation behavior + +Do not merge mutable authoring and immutable execution concepts: + +- commands mutate and save the draft; +- reconcile compiles one exact stored draft version into an immutable receipt; +- preview executes a receipt; +- publish materializes and activates a receipt. + +The UI may debounce reconcile requests, but correctness must not depend on the +debounce. Concurrent reconciliations remain safe because receipts are +content-addressed. A reconcile request for a stale draft version returns a +conflict instead of compiling newer state than the user intended. + +## Delivery phases + +### Phase 0: close the contract hole + +Backend: + +- Add backend output-ID validation at the authoring boundary. +- Add the OpenAPI pattern and precise diagnostic path. +- Add regression tests showing that authoring validation and recipe validation + accept and reject the same output identifiers. +- Add structured logging of command/type and diagnostic code, never complete + workspace bodies. + +Frontend: + +- Identify and document the existing API module, Builder store, UI event + handlers, and workspace-construction helpers that will be replaced. +- Add generated V2 types/runtime response validation and central error-code + decoding without changing components. +- Add characterization tests for the current UI interactions and rendered + states so the call migration can prove visual/behavioral equivalence. + +This improves correctness and diagnosis but does not by itself fix new-table +creation in the current frontend. + +### Phase 1: blank Explorer to server-created table + +Backend: + +- Add command types, pure reducer, identity generator, and command endpoint. +- Extend `GET /builder` with authoritative draft version/digest and advertise + the new operations through `GET /capability`. +- Implement empty-workspace initialization and `CREATE_TABLE`. +- Resolve `rootNodeId` only through the supplied capability snapshot and + require `RowRootEligible`. +- Create the output, root route, and tab together. +- Save through draft CAS and return the authoritative workspace. +- Add `POST /reconcile` to compile a stored draft version. + +Frontend: + +- Add `applyCommands` and `reconcile` to the typed API client. +- Route the existing first-node-click action through `CREATE_TABLE`; remove + output/tab/document construction from that handler. +- Replace the Builder store workspace/version/digest from the command response + and map the returned output ID into the existing selected-table state. +- Route the existing debounced compile action through stored-draft reconcile. +- Preserve the current loading, success, and Builder-attention UI states. +- Run the shared blank-state/create/reconcile fixtures against a coordinated + backend deployment. + +Exit criterion: the exact blank-config scenario that motivated this plan works +without any frontend-generated durable ID. + +### Phase 2: useful table construction + +Backend: + +- Implement `DELETE_TABLE`, `ADD_COLUMN`, and `REMOVE_COLUMN`. +- Resolve catalog candidates into complete typed columns on the backend. +- Generate physical column identities and compiler-owned defaults on the + backend. +- Cover compile, preview, export, reload, and publish for the resulting table. + +Frontend: + +- Route the existing table-delete and candidate checkbox handlers through + commands without changing their components. +- Remove local typed-column generation and dependent-reference repair. +- Add the serialized command queue and receipt-by-draft-digest cache. +- Change existing Preview and Publish callbacks to flush commands, reconcile + when needed, then call the unchanged receipt endpoints. +- Verify existing preview/publish dialogs and status indicators are unchanged. + +Exit criterion: a user can create, populate, preview, save, reload, and publish +a single table using commands only. + +### Phase 3: routes and multi-table workspaces + +Backend: + +- Implement route add/remove and root replacement with dependency cleanup. +- Implement table reorder/rename and multiple output handling. +- Ensure shared-filter bindings and tab order remain valid after every command. +- Add repeated-edge, self-loop, and route-subtree tests. + +Frontend: + +- Route existing root, route, rename, reorder, create-table, and delete-table + events through their commands. +- Remove occurrence-ID generation, route-tree mutation, tab-order repair, and + cross-table reference cleanup from frontend helpers. +- Preserve expansion, focus, selected table, and route-node selection as + ephemeral UI state keyed by backend-returned identities. + +Exit criterion: all structural Builder actions use server-owned commands. + +### Phase 4: presentation, filters, and actions + +Backend: + +- Move presentation normalization, fixed filters, shared filters, charts, and + file actions behind typed commands. +- Batch high-frequency presentation changes where appropriate. + +Frontend: + +- Route existing presentation/filter/chart/action controls through command + batches while retaining their current debounce behavior. +- Keep local optimistic UI state disposable and reconcile it against every + authoritative response. +- Delete the remaining ordinary-edit whole-workspace serializer and autosave + call path after the command coverage matrix is complete. + +Exit criterion: the browser no longer constructs or patches canonical +workspace objects. + +### Phase 5: compatibility retirement + +Backend and operations: + +- Measure use of full-workspace `PUT /draft`, `POST /compile`, and the + `POST /builder` compile alias by client version and caller class. +- Retain full-document import/export and repository ingestion as explicit + trusted workflows. +- Mark browser-oriented whole-workspace writes deprecated. +- Remove them only after supported frontends use commands and stored artifacts + have passed migration/audit checks. + +Frontend: + +- Remove the temporary legacy browser fallback and capability branch. +- Keep whole-document import/export in an explicitly separate workflow. +- Verify production bundles contain no ordinary Builder call site for + `PUT /draft`, workspace-bearing `POST /builder`, or `POST /compile`. + +## Test strategy + +### Domain tests + +- Every command either produces a fully valid workspace or leaves the input + unchanged. +- Generated identities always satisfy downstream grammars. +- Commands cannot reference stale outputs, occurrences, candidates, or edges. +- Removal commands clean every dependent reference. +- Reordering always produces contiguous stable order. +- Applying a command batch is atomic. + +### Service and storage tests + +- Empty, draft-backed, and active-revision-backed initialization paths. +- Version and digest conflict behavior across all store adapters. +- Exact command replay after a lost response. +- Command-ID reuse with different content. +- Concurrent commands from two tabs. +- No partial draft write when validation or persistence fails. + +### HTTP contract tests + +- Strict tagged-union decoding and unknown-field rejection. +- Authorization and capability-token checks. +- Stable diagnostic code, stage, and JSON path for every rejected command. +- Generated OpenAPI client models match the hand-written domain types. + +### End-to-end tests + +At minimum, automate these paths: + +1. blank Explorer -> select root -> server-created table -> reconcile; +2. add column -> reconcile -> preview; +3. reload -> authoritative IDs unchanged; +4. publish -> active revision -> viewer; +5. lost command response -> retry -> exactly one table; +6. two tabs mutate the same draft -> one succeeds, one receives a conflict; +7. snapshot becomes stale between read and command -> explicit stale-snapshot + response with no draft mutation; and +8. old valid V2 workspace -> command mutation -> reconcile -> publish. + +## Observability and rollout + +Record counters and latency for: + +- command type and outcome; +- validation, capability, conflict, and persistence failures; +- command replay hits; +- draft load/apply/validate/save durations; +- reconcile requests by draft version; +- legacy whole-workspace writes by client version; and +- frontend fallbacks to the legacy path. + +Roll out the command capability behind an advertised authoring feature. The +frontend selects the command path only when the server advertises it. Start +with internal projects, then new Explorers, then existing drafts. Do not infer +support from route failure. + +## Completion criteria + +The migration is complete when: + +- no supported browser generates or persists durable authoring IDs; +- no supported browser submits a complete workspace for ordinary editing; +- all browser structural edits are server-applied, capability-validated, and + CAS-persisted; +- compilation reads a specific stored draft revision instead of accepting + browser-supplied workspace content; +- existing Builder components and user-visible workflows remain unchanged, + with characterization/component tests proving the API/store cutover rather + than a UI rewrite; +- blank-to-first-table, retry, conflict, reload, preview, and publication flows + have end-to-end coverage; +- legacy whole-document endpoints are limited to explicit import, + repository/ETL, or compatibility workflows; and +- telemetry shows no supported-client use of the deprecated browser write path + for one full release window. + +## Explicit non-goals + +- Changing immutable receipt, preview, or publication semantics. +- Persisting recipe expressions, AQL, physical collection names, or + authorization predicates in browser intent. +- Automatic conflict merging in the first release. +- Replacing the canonical workspace with an event log. +- Removing V2 import/export or repository-authored configuration. diff --git a/docs/PLAN_EXPLORER_V2_BRANCHED_TRAVERSAL.md b/docs/PLAN_EXPLORER_V2_BRANCHED_TRAVERSAL.md new file mode 100644 index 00000000..e8a066e4 --- /dev/null +++ b/docs/PLAN_EXPLORER_V2_BRANCHED_TRAVERSAL.md @@ -0,0 +1,282 @@ +# Explorer V2 branched traversal authoring plan + +## Implementation status (2026-08-27) + +Implemented in Loom: + +- the semantic V2 route tree remains the sole backend route contract; +- sibling and nested routes lower recursively and deterministically; +- columns remain bound to their exact authored occurrence; +- compile and preview are covered as non-active receipt operations; +- Publish remains the only activation operation; and +- Explorer authoring documentation now identifies editable route trees as MVP + functionality and dynamic/pivot candidates as future work. + +The coordinated frontend tree editor is implemented in IDP-Frontend. The +remaining activity is live BForePC Kubernetes acceptance and an intentional +test publication; it is an operational verification step, not missing route +contract code. + +## Outcome + +Make the existing Explorer V2 route-tree contract safe for an interactive +Builder that can add, select, and remove traversal branches. Loom remains the +authority for capability edges, route policy, deterministic compilation, +preview execution, and publication. + +The primary implementation is in `IDP-Frontend`. Loom work is deliberately +limited to closing contract and test gaps around behavior that is already +substantially implemented. + +The coordinated frontend plan is: + +`IDP-Frontend/docs/PLAN_explorer-builder-branched-traversal.md` + +## Product boundary + +This work includes: + +- a finite traversal tree rooted at each output's row resource; +- sibling and nested branches; +- repeated resources represented by distinct occurrence IDs; +- adding columns from ordinary primitive catalog fields at any occurrence; +- local branch removal and its dependent-column cleanup; +- compile and preview against non-active receipts; and +- publication as the only operation that changes the active Explorer. + +This work does not include: + +- pivot-family authoring; +- dynamic column discovery or expansion; +- browser-authored recipe expressions; +- V1 decoding or migration; +- automatic draft persistence; or +- a general graph-query language outside the V2 `RouteNode` tree. + +## Current backend capability + +The semantic V2 contract already has the required shape: + +```text +RouteNode + occurrenceId + resourceType + relationship + children[] +``` + +Loom currently: + +- validates the complete recursive tree and globally unique occurrence IDs; +- resolves every child through an exact capability relationship; +- applies maximum-depth, repeated-edge, and self-loop policies; +- sorts siblings by occurrence ID for deterministic lowering; +- attaches columns to exact occurrences; +- recursively emits sibling `recipe.Traversal` values; +- compiles immutable receipts without changing the active revision; +- previews exact receipts without changing the active revision; and +- materializes and switches the active revision only in Publish. + +The existing BForePC V2 workspace is already a production-relevant branch +fixture. Its Specimen output has sibling Observation and Patient children, and +the Patient occurrence owns `HTAN_PARTICIPANT_ID`. + +## Gaps + +1. Explorer compilation tests cover nested routes but do not prove sibling + branches with columns on both siblings. +2. HTTP lifecycle tests do not prove that a branched compile and preview leave + the active revision unchanged. +3. There is no cross-system branch round trip covering repository workspace, + Builder edit, compile, preview, publish, Builder reload, and Viewer output. +4. Row-grain behavior for two populated, repeated sibling branches is not + asserted at the Explorer contract boundary. +5. Branch-specific route-policy errors are not covered with exact diagnostic + paths. +6. Compatibility-only linear fields and helpers in `authoringv2.Document` can + obscure which route model is authoritative. They must not be used by new + branch code. + +## Invariants + +### Authoring identity + +- `Document.Route` is the only durable route source. +- Every occurrence ID is globally unique within one document. +- Columns reference occurrences by exact occurrence ID. +- Sibling order does not change compilation identity. +- Snapshot-local catalog node, edge, and candidate IDs are never persisted as + the semantic route. +- Relationship and resource type are persisted exactly as the V2 contract + requires. + +### Lifecycle + +- Compile may persist an immutable receipt, but it must not save the workspace + as a draft, create a revision, materialize an output, or switch an active + pointer. +- Preview may execute a receipt, but it must not save a draft, create a + revision, materialize a published output, or switch an active pointer. +- Publish is the only browser operation in this feature that may materialize + and activate the edited workspace. +- A failed Publish retains the previously active Explorer revision. + +### Query behavior + +- Adding one sibling cannot change or remove another sibling. +- Removing one subtree removes only that subtree from the compiled recipe. +- Columns on retained occurrences preserve their names, labels, and + presentation contracts. +- Optional sibling traversal lowering must preserve the declared root row + grain. Any multiplicity behavior must be explicit in the output contract, + not an accidental Cartesian expansion. + +## Backend work packages + +### B1. Canonical branch fixtures + +Add a small semantic V2 fixture with this topology: + +```text +ResearchSubject (base) +├── Patient (patient) +│ └── Condition (patient__condition) +└── Specimen (specimen) +``` + +Attach at least one primitive field column to every occurrence. Use readable +column and occurrence identities that exercise the non-root prefix contract. + +Also load the BForePC Specimen route as a contract fixture where practical: + +```text +Specimen (base) +├── Observation (observation) +└── Patient (patient) +``` + +### B2. Semantic compiler coverage + +Add tests in `internal/explorer/compilation` proving: + +- sibling branches lower to sibling recipe traversals; +- nested children remain attached to the correct sibling; +- columns bind to the correct occurrence and physical prefix; +- reversing authored sibling order produces the same deterministic recipe and + receipt identity; +- duplicate occurrence IDs fail before lowering; +- ambiguous and unavailable relationships return exact route paths; +- maximum depth is evaluated per root-to-leaf path; +- repeated-edge and self-loop decisions match the advertised route policy; and +- removing a sibling changes only that sibling's recipe subtree and emissions. + +Do not add a second route representation or translate through compatibility +`RouteSteps`. + +### B3. Row-grain and physical execution coverage + +Add an execution-level fixture with data on two sibling branches. Assert: + +- the root output remains queryable; +- fields from both siblings appear under their frozen public names; +- missing optional children produce null/empty values according to the current + traversal contract; and +- two populated repeated siblings do not create an undocumented root-row + multiplication. + +If this exposes a dataframer defect, fix the existing recursive traversal +lowering. Do not special-case Explorer routes in the renderer. + +### B4. Receipt lifecycle coverage + +Extend the native V2 HTTP contract tests to execute: + +1. Load an Explorer with an existing active revision. +2. Compile a changed branched workspace. +3. Assert that the active revision, publication metadata, and Viewer contract + are unchanged. +4. Preview the compiled receipt. +5. Assert again that active state is unchanged. +6. Publish the receipt. +7. Assert that materialization succeeds and the new branched revision becomes + active atomically. +8. Reload Builder state and verify the exact route tree and occurrence IDs. + +Also assert that a failed materialization or activation retains the prior +active revision. + +### B5. Diagnostics and capability agreement + +Verify that a frontend can decide legal child additions from one capability +snapshot and receive the same decision from compilation: + +- exact source node; +- exact target node; +- exact relationship label; +- repeated-edge policy; +- self-loop policy; and +- maximum path depth. + +Use existing stable authoring diagnostics. Add a new error code only if no +existing code describes a demonstrated failure. Do not add a branch feature +flag unless mixed-version deployment proves it necessary. + +### B6. Documentation cleanup + +Update `docs/EXPLORER_AUTHORING.md` to state that: + +- ordinary catalog fields and editable route trees are part of the MVP; +- pivot/dynamic candidate families remain future work; +- semantic `RouteNode.children` is authoritative; and +- compile/preview receipts are non-active artifacts. + +Mark compatibility-only linear route helpers as non-authoritative. Remove them +only when existing internal tests no longer require them; their removal is not +a prerequisite for shipping branches. + +## Cross-system acceptance scenario + +Use the checked-in BForePC workspace as the acceptance fixture: + +1. Open the Specimen output. +2. Verify both Observation and Patient sibling occurrences are visible. +3. Select Patient and verify `HTAN_PARTICIPANT_ID` is editable. +4. Add one catalog-proven child under either existing occurrence. +5. Add an ordinary primitive field on the new occurrence. +6. Compile and preview successfully. +7. Verify the active Viewer still serves the old revision. +8. Remove or retain the new branch locally and preview again. +9. Publish the intended tree. +10. Reload Builder and Viewer and verify both sibling branches, labels, and + queryable columns. + +## Verification commands + +At minimum, implementation should run: + +```bash +go test ./internal/explorer/authoringv2 ./internal/explorer/compilation ./internal/server +``` + +Then run the existing Explorer conformance suite and the local authenticated +Kubernetes acceptance flow against the BForePC project. + +## Delivery order + +1. Land backend branch fixtures and failing coverage for the existing contract. +2. Implement the frontend tree model and interactions against that contract. +3. Run compile and preview acceptance without publication. +4. Run publication, reload, and Viewer acceptance. +5. Remove the frontend route-editing gate only when lossless branch hydration, + mutation, and reconstruction tests pass. + +## Exit criteria + +- Loom compiles, previews, publishes, and reloads sibling and nested route + branches without migration or fallback logic. +- Compile and Preview provably leave active Explorer state unchanged. +- Publish is the only operation that changes the active revision. +- BForePC Specimen retains both its Observation and Patient branches through a + full Builder round trip. +- Viewer columns and labels from all retained occurrences match the frozen V2 + output contract. diff --git a/docs/README.md b/docs/README.md index 548dfd42..4cb8a703 100644 --- a/docs/README.md +++ b/docs/README.md @@ -36,6 +36,9 @@ documented separately from migration notes and implementation plans. ## Migration and planning material +- [Backend-owned Explorer authoring plan](PLAN_BACKEND_OWNED_EXPLORER_AUTHORING.md) + — phased migration from browser-authored workspaces to server-owned intent + commands, identities, canonical drafts, and stored-draft reconciliation. - [Historical Explorer V2 migration](FRONTEND_EXPLORER_V2_MIGRATION.md) — retained for compatibility and ETL migration context. It is not the current browser authoring contract; use [Explorer authoring](EXPLORER_AUTHORING.md) diff --git a/docs/frontend/explorer-v2-capability-authoring.md b/docs/frontend/explorer-v2-capability-authoring.md index 3d084311..750b7e63 100644 --- a/docs/frontend/explorer-v2-capability-authoring.md +++ b/docs/frontend/explorer-v2-capability-authoring.md @@ -128,7 +128,7 @@ compile it, persist an immutable receipt, and return: "snapshotToken": "sha256:...", "generation": "generation-...", "intentDigest": "sha256:...", - "compilerVersion": "explorer-authoring-v2", + "compilerVersion": "loom.explorer.compiler/v7+authoring-v2-native-4", "outputs": [], "diagnostics": [] } diff --git a/internal/explorer/authoringv2/commands.go b/internal/explorer/authoringv2/commands.go new file mode 100644 index 00000000..978882fc --- /dev/null +++ b/internal/explorer/authoringv2/commands.go @@ -0,0 +1,600 @@ +package authoringv2 + +import ( + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "sort" + "strings" +) + +const ( + CommandCreateTable = "CREATE_TABLE" + CommandDuplicateTable = "DUPLICATE_TABLE" + CommandDeleteTable = "DELETE_TABLE" + CommandRenameTable = "RENAME_TABLE" + CommandReorderTables = "REORDER_TABLES" + CommandSetTableRoot = "SET_TABLE_ROOT" + CommandAddRoute = "ADD_ROUTE" + CommandRemoveRoute = "REMOVE_ROUTE" + CommandAddColumn = "ADD_COLUMN" + CommandUpdateColumn = "UPDATE_COLUMN" + CommandRemoveColumn = "REMOVE_COLUMN" + CommandResultTableCreated = "TABLE_CREATED" + CommandResultTableChanged = "TABLE_CHANGED" + CommandResultRouteAdded = "ROUTE_ADDED" + CommandResultColumnAdded = "COLUMN_ADDED" + InitialPresentationTable = "TABLE" + InitialPresentationFilter = "FILTER" + InitialPresentationChart = "CHART" +) + +// ApplyCommandsRequest is the browser's mutation envelope. CommandID is an +// idempotency token, never a durable authoring identity. +type ApplyCommandsRequest struct { + CommandID string `json:"commandId"` + SnapshotToken string `json:"snapshotToken"` + ExpectedDraftVersion int64 `json:"expectedDraftVersion"` + ExpectedDraftDigest string `json:"expectedDraftDigest,omitempty"` + Commands []Command `json:"commands"` +} + +type Command struct { + Type string `json:"type"` + OutputID string `json:"outputId,omitempty"` + SourceOutputID string `json:"sourceOutputId,omitempty"` + Title string `json:"title,omitempty"` + RootNodeID string `json:"rootNodeId,omitempty"` + ParentOccurrenceID string `json:"parentOccurrenceId,omitempty"` + OccurrenceID string `json:"occurrenceId,omitempty"` + EdgeID string `json:"edgeId,omitempty"` + CandidateID string `json:"candidateId,omitempty"` + ProjectionMode string `json:"projectionMode,omitempty"` + InitialPresentation string `json:"initialPresentation,omitempty"` + Column string `json:"column,omitempty"` + ColumnValue *Column `json:"columnValue,omitempty"` + OutputIDs []string `json:"outputIds,omitempty"` +} + +type CommandResult struct { + Type string `json:"type"` + OutputID string `json:"outputId,omitempty"` + TabID string `json:"tabId,omitempty"` + OccurrenceID string `json:"occurrenceId,omitempty"` + Column string `json:"column,omitempty"` +} + +type ApplyCommandsResponse struct { + CommandID string `json:"commandId"` + Workspace Workspace `json:"workspace"` + DraftVersion int64 `json:"draftVersion"` + DraftDigest string `json:"draftDigest"` + Results []CommandResult `json:"results"` + Diagnostics []any `json:"diagnostics"` +} + +func (r ApplyCommandsRequest) Validate() error { + if emptyID(r.CommandID) || strings.TrimSpace(r.SnapshotToken) == "" { + return fmt.Errorf("commandId and snapshotToken are required") + } + if r.ExpectedDraftVersion < 0 { + return fmt.Errorf("expectedDraftVersion must not be negative") + } + if len(r.Commands) == 0 { + return fmt.Errorf("at least one command is required") + } + for i, command := range r.Commands { + if err := command.validate(); err != nil { + return fmt.Errorf("commands[%d]: %w", i, err) + } + } + return nil +} + +func (r ApplyCommandsRequest) Digest() (string, error) { + canonical, err := json.Marshal(struct { + SnapshotToken string `json:"snapshotToken"` + Commands []Command `json:"commands"` + }{r.SnapshotToken, r.Commands}) + if err != nil { + return "", err + } + sum := sha256.Sum256(canonical) + return "sha256:" + hex.EncodeToString(sum[:]), nil +} + +func (c Command) validate() error { + required := func(values ...string) bool { + for _, value := range values { + if strings.TrimSpace(value) == "" { + return false + } + } + return true + } + switch c.Type { + case CommandCreateTable: + if !required(c.Title, c.RootNodeID) { + return fmt.Errorf("CREATE_TABLE requires title and rootNodeId") + } + case CommandDuplicateTable: + if !required(c.SourceOutputID, c.Title) { + return fmt.Errorf("DUPLICATE_TABLE requires sourceOutputId and title") + } + case CommandDeleteTable: + if !required(c.OutputID) { + return fmt.Errorf("DELETE_TABLE requires outputId") + } + case CommandRenameTable: + if !required(c.OutputID, c.Title) { + return fmt.Errorf("RENAME_TABLE requires outputId and title") + } + case CommandReorderTables: + if len(c.OutputIDs) == 0 { + return fmt.Errorf("REORDER_TABLES requires outputIds") + } + case CommandSetTableRoot: + if !required(c.OutputID, c.RootNodeID) { + return fmt.Errorf("SET_TABLE_ROOT requires outputId and rootNodeId") + } + case CommandAddRoute: + if !required(c.OutputID, c.ParentOccurrenceID, c.EdgeID) { + return fmt.Errorf("ADD_ROUTE requires outputId, parentOccurrenceId, and edgeId") + } + case CommandRemoveRoute: + if !required(c.OutputID, c.OccurrenceID) || c.OccurrenceID == RootOccurrenceID { + return fmt.Errorf("REMOVE_ROUTE requires a non-root occurrenceId") + } + case CommandAddColumn: + if !required(c.OutputID, c.OccurrenceID, c.CandidateID) { + return fmt.Errorf("ADD_COLUMN requires outputId, occurrenceId, and candidateId") + } + if c.InitialPresentation != "" && !contains([]string{InitialPresentationTable, InitialPresentationFilter, InitialPresentationChart}, strings.ToUpper(strings.TrimSpace(c.InitialPresentation))) { + return fmt.Errorf("ADD_COLUMN initialPresentation must be TABLE, FILTER, or CHART") + } + case CommandUpdateColumn: + if !required(c.OutputID, c.Column) || c.ColumnValue == nil { + return fmt.Errorf("UPDATE_COLUMN requires outputId, column, and columnValue") + } + case CommandRemoveColumn: + if !required(c.OutputID, c.Column) { + return fmt.Errorf("REMOVE_COLUMN requires outputId and column") + } + default: + return fmt.Errorf("unsupported command type %q", c.Type) + } + return nil +} + +// ApplyCommands is a pure reducer over canonical authoring state. It clones +// the input and either returns one fully valid workspace or no mutation. +func ApplyCommands(workspace Workspace, catalog CatalogSnapshot, commandID string, commands []Command) (Workspace, []CommandResult, error) { + working, err := cloneWorkspace(workspace) + if err != nil { + return Workspace{}, nil, err + } + results := make([]CommandResult, 0, len(commands)) + for index, command := range commands { + result, applyErr := applyCommand(&working, catalog, commandID, index, command) + if applyErr != nil { + return Workspace{}, nil, fmt.Errorf("commands[%d]: %w", index, applyErr) + } + results = append(results, result) + } + working = working.NormalizePresentationOrders() + if err := (BuilderState{APIVersion: APIVersion, Kind: StateKind, LifecycleState: LifecycleReady, Workspace: &working, Catalog: catalog}).Validate(); err != nil { + return Workspace{}, nil, err + } + return working, results, nil +} + +func applyCommand(workspace *Workspace, catalog CatalogSnapshot, commandID string, index int, command Command) (CommandResult, error) { + result := CommandResult{Type: CommandResultTableChanged, OutputID: command.OutputID} + switch command.Type { + case CommandCreateTable: + node, ok := catalogNode(catalog, command.RootNodeID) + if !ok || !node.RowRootEligible { + return result, fmt.Errorf("rootNodeId %q is not an eligible catalog root", command.RootNodeID) + } + outputID := commandGeneratedID("out_", commandID, index, command.Type) + tabID := commandGeneratedID("tab_", commandID, index, command.Type) + for _, document := range workspace.Documents { + if document.Output.ID == outputID { + return CommandResult{Type: CommandResultTableCreated, OutputID: outputID, TabID: tabID}, nil + } + } + title := strings.TrimSpace(command.Title) + workspace.Documents = append(workspace.Documents, Document{Kind: Kind, Output: Output{ID: outputID, Title: title}, RootResourceType: node.ResourceType, Route: RouteNode{OccurrenceID: RootOccurrenceID, ResourceType: node.ResourceType}, Columns: []Column{}}) + workspace.Tabs = append(workspace.Tabs, Tab{ID: tabID, Title: title, OutputID: outputID, Order: len(workspace.Tabs), Visible: true}) + return CommandResult{Type: CommandResultTableCreated, OutputID: outputID, TabID: tabID, OccurrenceID: RootOccurrenceID}, nil + case CommandDuplicateTable: + sourceIndex := documentIndex(workspace, command.SourceOutputID) + if sourceIndex < 0 { + return result, fmt.Errorf("source output %q was not found", command.SourceOutputID) + } + outputID := commandGeneratedID("out_", commandID, index, command.Type) + tabID := commandGeneratedID("tab_", commandID, index, command.Type) + copy := workspace.Documents[sourceIndex] + copy.Output.ID, copy.Output.Title = outputID, strings.TrimSpace(command.Title) + workspace.Documents = append(workspace.Documents, copy) + workspace.Tabs = append(workspace.Tabs, Tab{ID: tabID, Title: copy.Output.Title, OutputID: outputID, Order: len(workspace.Tabs), Visible: true}) + return CommandResult{Type: CommandResultTableCreated, OutputID: outputID, TabID: tabID, OccurrenceID: RootOccurrenceID}, nil + case CommandDeleteTable: + document := documentIndex(workspace, command.OutputID) + if document < 0 { + return result, fmt.Errorf("output %q was not found", command.OutputID) + } + workspace.Documents = append(workspace.Documents[:document], workspace.Documents[document+1:]...) + workspace.Tabs = removeOutputTab(workspace.Tabs, command.OutputID) + cleanupWorkspaceBindings(workspace) + return result, nil + case CommandRenameTable: + document := documentIndex(workspace, command.OutputID) + if document < 0 { + return result, fmt.Errorf("output %q was not found", command.OutputID) + } + title := strings.TrimSpace(command.Title) + workspace.Documents[document].Output.Title = title + for i := range workspace.Tabs { + if workspace.Tabs[i].OutputID == command.OutputID { + workspace.Tabs[i].Title = title + } + } + return result, nil + case CommandReorderTables: + if len(command.OutputIDs) != len(workspace.Documents) { + return result, fmt.Errorf("outputIds must list every table exactly once") + } + positions := map[string]int{} + seen := map[string]bool{} + for order, outputID := range command.OutputIDs { + if documentIndex(workspace, outputID) < 0 || seen[outputID] { + return result, fmt.Errorf("outputIds contains an unknown or duplicate output") + } + seen[outputID] = true + positions[outputID] = order + 1 + } + sort.SliceStable(workspace.Tabs, func(i, j int) bool { + return positions[workspace.Tabs[i].OutputID] < positions[workspace.Tabs[j].OutputID] + }) + for order := range workspace.Tabs { + workspace.Tabs[order].Order = order + } + return result, nil + case CommandSetTableRoot: + document := documentIndex(workspace, command.OutputID) + node, ok := catalogNode(catalog, command.RootNodeID) + if document < 0 || !ok || !node.RowRootEligible { + return result, fmt.Errorf("output or eligible root node was not found") + } + workspace.Documents[document].RootResourceType = node.ResourceType + workspace.Documents[document].Route = RouteNode{OccurrenceID: RootOccurrenceID, ResourceType: node.ResourceType} + workspace.Documents[document].Columns = []Column{} + workspace.Documents[document].FixedFilters = nil + workspace.Documents[document].Actions = nil + cleanupWorkspaceBindings(workspace) + return result, nil + case CommandAddRoute: + document := documentIndex(workspace, command.OutputID) + if document < 0 { + return result, fmt.Errorf("output %q was not found", command.OutputID) + } + parent := findRoute(&workspace.Documents[document].Route, command.ParentOccurrenceID) + edge, ok := catalogEdge(catalog, command.EdgeID) + if parent == nil || !ok { + return result, fmt.Errorf("parent occurrence or edge was not found") + } + from, fromOK := catalogNode(catalog, edge.FromNodeID) + to, toOK := catalogNode(catalog, edge.ToNodeID) + if !fromOK || !toOK || from.ResourceType != parent.ResourceType { + return result, fmt.Errorf("edge %q does not extend occurrence %q", edge.ID, command.ParentOccurrenceID) + } + occurrenceID := commandGeneratedID("occ_", commandID, index, command.Type) + if findRoute(&workspace.Documents[document].Route, occurrenceID) != nil { + return CommandResult{Type: CommandResultRouteAdded, OutputID: command.OutputID, OccurrenceID: occurrenceID}, nil + } + parent.Children = append(parent.Children, RouteNode{OccurrenceID: occurrenceID, ResourceType: to.ResourceType, Relationship: edge.Label}) + return CommandResult{Type: CommandResultRouteAdded, OutputID: command.OutputID, OccurrenceID: occurrenceID}, nil + case CommandRemoveRoute: + document := documentIndex(workspace, command.OutputID) + if document < 0 { + return result, fmt.Errorf("output %q was not found", command.OutputID) + } + removed := map[string]bool{} + if !removeRoute(&workspace.Documents[document].Route, command.OccurrenceID, removed) { + return result, fmt.Errorf("occurrence %q was not found", command.OccurrenceID) + } + columns := workspace.Documents[document].Columns[:0] + for _, column := range workspace.Documents[document].Columns { + if !removed[column.OccurrenceID] { + columns = append(columns, column) + } + } + workspace.Documents[document].Columns = columns + cleanupDocumentReferences(&workspace.Documents[document]) + cleanupWorkspaceBindings(workspace) + return result, nil + case CommandAddColumn: + document := documentIndex(workspace, command.OutputID) + candidate, ok := catalogCandidate(catalog, command.CandidateID) + if document < 0 || !ok { + return result, fmt.Errorf("output or candidate was not found") + } + occurrence := findRoute(&workspace.Documents[document].Route, command.OccurrenceID) + node, nodeOK := catalogNode(catalog, candidate.NodeID) + if occurrence == nil || !nodeOK || occurrence.ResourceType != node.ResourceType { + return result, fmt.Errorf("candidate %q does not belong to occurrence %q", candidate.ID, command.OccurrenceID) + } + mode := strings.ToUpper(strings.TrimSpace(command.ProjectionMode)) + if mode == "" { + mode = candidate.DefaultProjectionMode + } + if !contains(candidate.ProjectionModes, mode) { + return result, fmt.Errorf("projection mode %q is not advertised", mode) + } + presentation := strings.ToUpper(strings.TrimSpace(command.InitialPresentation)) + if presentation == "" { + presentation = InitialPresentationTable + } + if presentation == InitialPresentationFilter && !candidate.Filterable { + return result, fmt.Errorf("candidate %q does not support filters", candidate.ID) + } + if presentation == InitialPresentationChart && !candidate.Chartable { + return result, fmt.Errorf("candidate %q does not support charts", candidate.ID) + } + for i := range workspace.Documents[document].Columns { + column := &workspace.Documents[document].Columns[i] + if column.OccurrenceID == command.OccurrenceID && column.Source.Kind == SourceField && strings.TrimPrefix(column.Source.FieldPath, "root.") == strings.TrimPrefix(candidate.FieldPath, "root.") && strings.EqualFold(column.Source.ProjectionMode, mode) { + applyInitialPresentation(column, presentation, nextTableOrder(workspace.Documents[document].Columns)) + return CommandResult{Type: CommandResultColumnAdded, OutputID: command.OutputID, Column: column.Column}, nil + } + } + columnID := commandGeneratedID("col_", command.OutputID, command.OccurrenceID, candidate.ID, mode) + if command.OccurrenceID != RootOccurrenceID { + columnID = command.OccurrenceID + "__" + columnID + } + label := strings.TrimSpace(command.Title) + if label == "" { + label = candidate.Label + } + column := Column{Column: columnID, Label: label, LogicalType: candidate.LogicalType, OccurrenceID: command.OccurrenceID, Source: ColumnSource{Kind: SourceField, FieldPath: strings.TrimPrefix(candidate.FieldPath, "root."), ProjectionMode: mode}} + applyInitialPresentation(&column, presentation, nextTableOrder(workspace.Documents[document].Columns)) + workspace.Documents[document].Columns = append(workspace.Documents[document].Columns, column) + return CommandResult{Type: CommandResultColumnAdded, OutputID: command.OutputID, Column: columnID}, nil + case CommandUpdateColumn: + document := documentIndex(workspace, command.OutputID) + if document < 0 { + return result, fmt.Errorf("output %q was not found", command.OutputID) + } + for i := range workspace.Documents[document].Columns { + current := &workspace.Documents[document].Columns[i] + if current.Column != command.Column { + continue + } + value := command.ColumnValue + if strings.TrimSpace(value.Label) == "" { + return result, fmt.Errorf("column label is required") + } + current.Label, current.Table, current.Filter, current.Chart = value.Label, value.Table, value.Filter, value.Chart + return CommandResult{Type: CommandResultTableChanged, OutputID: command.OutputID, Column: current.Column}, nil + } + return result, fmt.Errorf("column %q was not found", command.Column) + case CommandRemoveColumn: + document := documentIndex(workspace, command.OutputID) + if document < 0 { + return result, fmt.Errorf("output %q was not found", command.OutputID) + } + columns := workspace.Documents[document].Columns[:0] + found := false + for _, column := range workspace.Documents[document].Columns { + if column.Column == command.Column { + found = true + continue + } + columns = append(columns, column) + } + if !found { + return result, fmt.Errorf("column %q was not found", command.Column) + } + workspace.Documents[document].Columns = columns + cleanupDocumentReferences(&workspace.Documents[document]) + cleanupWorkspaceBindings(workspace) + return result, nil + } + return result, fmt.Errorf("unsupported command type %q", command.Type) +} + +func cloneWorkspace(value Workspace) (Workspace, error) { + raw, err := json.Marshal(value) + if err != nil { + return Workspace{}, err + } + var result Workspace + if err := json.Unmarshal(raw, &result); err != nil { + return Workspace{}, err + } + return result, nil +} + +func commandGeneratedID(prefix string, values ...any) string { + parts := make([]string, len(values)) + for i, value := range values { + parts[i] = fmt.Sprint(value) + } + sum := sha256.Sum256([]byte(strings.Join(parts, "\x00"))) + return prefix + hex.EncodeToString(sum[:12]) +} + +func documentIndex(workspace *Workspace, outputID string) int { + for i := range workspace.Documents { + if workspace.Documents[i].Output.ID == outputID { + return i + } + } + return -1 +} + +func catalogNode(catalog CatalogSnapshot, id string) (CatalogNode, bool) { + for _, value := range catalog.Nodes { + if value.ID == id { + return value, true + } + } + return CatalogNode{}, false +} + +func catalogEdge(catalog CatalogSnapshot, id string) (CatalogEdge, bool) { + for _, value := range catalog.Edges { + if value.ID == id { + return value, true + } + } + return CatalogEdge{}, false +} + +func catalogCandidate(catalog CatalogSnapshot, id string) (CatalogCandidate, bool) { + for _, value := range catalog.Candidates { + if value.ID == id { + return value, true + } + } + return CatalogCandidate{}, false +} + +func contains(values []string, want string) bool { + for _, value := range values { + if strings.EqualFold(value, want) { + return true + } + } + return false +} + +func findRoute(route *RouteNode, occurrenceID string) *RouteNode { + if route.OccurrenceID == occurrenceID { + return route + } + for i := range route.Children { + if found := findRoute(&route.Children[i], occurrenceID); found != nil { + return found + } + } + return nil +} + +func removeRoute(route *RouteNode, occurrenceID string, removed map[string]bool) bool { + for i := range route.Children { + if route.Children[i].OccurrenceID == occurrenceID { + collectOccurrences(route.Children[i], removed) + route.Children = append(route.Children[:i], route.Children[i+1:]...) + return true + } + if removeRoute(&route.Children[i], occurrenceID, removed) { + return true + } + } + return false +} + +func collectOccurrences(route RouteNode, values map[string]bool) { + values[route.OccurrenceID] = true + for _, child := range route.Children { + collectOccurrences(child, values) + } +} + +func removeOutputTab(tabs []Tab, outputID string) []Tab { + result := tabs[:0] + for _, tab := range tabs { + if tab.OutputID != outputID { + result = append(result, tab) + } + } + for i := range result { + result[i].Order = i + } + return result +} + +func cleanupDocumentReferences(document *Document) { + columns := map[string]bool{} + for _, column := range document.Columns { + columns[column.Column] = true + } + filters := document.FixedFilters[:0] + for _, filter := range document.FixedFilters { + if columns[filter.Column] { + filters = append(filters, filter) + } + } + document.FixedFilters = filters + for i := range document.Actions { + kept := document.Actions[i].Columns[:0] + for _, column := range document.Actions[i].Columns { + if columns[column.Column] { + kept = append(kept, column) + } + } + document.Actions[i].Columns = kept + } +} + +func cleanupWorkspaceBindings(workspace *Workspace) { + available := map[string]map[string]bool{} + for i := range workspace.Documents { + cleanupDocumentReferences(&workspace.Documents[i]) + available[workspace.Documents[i].Output.ID] = map[string]bool{} + for _, column := range workspace.Documents[i].Columns { + available[workspace.Documents[i].Output.ID][column.Column] = true + } + } + for name, bindings := range workspace.SharedFilters { + kept := bindings[:0] + for _, binding := range bindings { + if available[binding.OutputID][binding.Column] { + kept = append(kept, binding) + } + } + if len(kept) == 0 { + delete(workspace.SharedFilters, name) + } else { + workspace.SharedFilters[name] = kept + } + } +} + +func applyInitialPresentation(column *Column, presentation string, tableOrder int) { + switch presentation { + case InitialPresentationFilter: + if column.Filter == nil { + column.Filter = &FilterPresentation{Label: column.Label} + } + case InitialPresentationChart: + if column.Chart == nil { + column.Chart = &ChartPresentation{Type: "bar", Title: column.Label} + } + default: + visible := true + if column.Table == nil { + order := tableOrder + column.Table = &TablePresentation{Visible: &visible, Order: &order} + return + } + column.Table.Visible = &visible + if column.Table.Order == nil { + order := tableOrder + column.Table.Order = &order + } + } +} + +func nextTableOrder(columns []Column) int { + result := 0 + for _, column := range columns { + if column.Table != nil && column.Table.Order != nil && *column.Table.Order >= result { + result = *column.Table.Order + 1 + } + } + return result +} diff --git a/internal/explorer/authoringv2/commands_test.go b/internal/explorer/authoringv2/commands_test.go new file mode 100644 index 00000000..9fcdab0d --- /dev/null +++ b/internal/explorer/authoringv2/commands_test.go @@ -0,0 +1,121 @@ +package authoringv2 + +import ( + "encoding/json" + "regexp" + "strings" + "testing" +) + +func emptyCommandWorkspace() Workspace { + return Workspace{APIVersion: APIVersion, Kind: WorkspaceKind, Explorer: ExplorerMetadata{Title: "Builder"}, Documents: []Document{}, Tabs: []Tab{}} +} + +func commandCatalog() CatalogSnapshot { + catalog := testCatalog() + for index := range catalog.Candidates { + catalog.Candidates[index].ProjectionModes = []string{"VALUE"} + catalog.Candidates[index].DefaultProjectionMode = "VALUE" + catalog.Candidates[index].FieldPath = "id" + } + return catalog +} + +func TestApplyCommandsCreatesRecipeSafeBackendIdentities(t *testing.T) { + workspace, results, err := ApplyCommands(emptyCommandWorkspace(), commandCatalog(), "browser-request-with-hyphens", []Command{{Type: CommandCreateTable, Title: "Patients", RootNodeID: "patient"}}) + if err != nil { + t.Fatal(err) + } + if len(results) != 1 || len(workspace.Documents) != 1 || len(workspace.Tabs) != 1 { + t.Fatalf("workspace=%#v results=%#v", workspace, results) + } + safe := regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*$`) + if !safe.MatchString(results[0].OutputID) || results[0].OutputID != workspace.Documents[0].Output.ID { + t.Fatalf("backend generated invalid output identity %q", results[0].OutputID) + } + if results[0].TabID == "" || results[0].OccurrenceID != RootOccurrenceID { + t.Fatalf("result=%#v", results[0]) + } + wire, err := json.Marshal(workspace) + if err != nil { + t.Fatal(err) + } + if !strings.Contains(string(wire), `"columns":[]`) { + t.Fatalf("empty columns must remain an array on the wire: %s", wire) + } +} + +func TestApplyCommandsOwnsNestedRouteAndColumnIdentities(t *testing.T) { + workspace, create, err := ApplyCommands(emptyCommandWorkspace(), commandCatalog(), "create", []Command{{Type: CommandCreateTable, Title: "Patients", RootNodeID: "patient"}}) + if err != nil { + t.Fatal(err) + } + outputID := create[0].OutputID + workspace, route, err := ApplyCommands(workspace, commandCatalog(), "route", []Command{{Type: CommandAddRoute, OutputID: outputID, ParentOccurrenceID: RootOccurrenceID, EdgeID: "patient-encounter"}}) + if err != nil { + t.Fatal(err) + } + workspace, columns, err := ApplyCommands(workspace, commandCatalog(), "column", []Command{{Type: CommandAddColumn, OutputID: outputID, OccurrenceID: route[0].OccurrenceID, CandidateID: "encounter-id"}}) + if err != nil { + t.Fatal(err) + } + if route[0].OccurrenceID == "" || columns[0].Column == "" || workspace.Documents[0].Columns[0].Column != columns[0].Column { + t.Fatalf("route=%#v columns=%#v workspace=%#v", route, columns, workspace) + } +} + +func TestApplyCommandsAddsFilterAndChartWithoutMakingColumnTableVisible(t *testing.T) { + catalog := commandCatalog() + catalog.Candidates[0].Filterable = true + catalog.Candidates[0].Chartable = true + workspace, created, err := ApplyCommands(emptyCommandWorkspace(), catalog, "create", []Command{{Type: CommandCreateTable, Title: "Patients", RootNodeID: "patient"}}) + if err != nil { + t.Fatal(err) + } + outputID := created[0].OutputID + workspace, added, err := ApplyCommands(workspace, catalog, "filter", []Command{{Type: CommandAddColumn, OutputID: outputID, OccurrenceID: RootOccurrenceID, CandidateID: "patient-id", InitialPresentation: InitialPresentationFilter}}) + if err != nil { + t.Fatal(err) + } + if len(workspace.Documents[0].Columns) != 1 { + t.Fatalf("columns=%#v", workspace.Documents[0].Columns) + } + column := workspace.Documents[0].Columns[0] + if column.Column != added[0].Column || column.Table != nil || column.Filter == nil || column.Chart != nil { + t.Fatalf("filter-only column=%#v", column) + } + + workspace, _, err = ApplyCommands(workspace, catalog, "chart", []Command{{Type: CommandAddColumn, OutputID: outputID, OccurrenceID: RootOccurrenceID, CandidateID: "patient-id", InitialPresentation: InitialPresentationChart}}) + if err != nil { + t.Fatal(err) + } + column = workspace.Documents[0].Columns[0] + if len(workspace.Documents[0].Columns) != 1 || column.Table != nil || column.Filter == nil || column.Chart == nil || column.Chart.Type != "bar" { + t.Fatalf("filter-and-chart column=%#v", column) + } +} + +func TestApplyCommandsRejectsUnsupportedInitialPresentation(t *testing.T) { + workspace, created, err := ApplyCommands(emptyCommandWorkspace(), commandCatalog(), "create", []Command{{Type: CommandCreateTable, Title: "Patients", RootNodeID: "patient"}}) + if err != nil { + t.Fatal(err) + } + _, _, err = ApplyCommands(workspace, commandCatalog(), "filter", []Command{{Type: CommandAddColumn, OutputID: created[0].OutputID, OccurrenceID: RootOccurrenceID, CandidateID: "patient-id", InitialPresentation: InitialPresentationFilter}}) + if err == nil || !strings.Contains(err.Error(), "does not support filters") { + t.Fatalf("error=%v", err) + } +} + +func TestApplyCommandsRejectsBatchAtomically(t *testing.T) { + original := emptyCommandWorkspace() + _, _, err := ApplyCommands(original, commandCatalog(), "batch", []Command{ + {Type: CommandCreateTable, Title: "Patients", RootNodeID: "patient"}, + {Type: CommandDeleteTable, OutputID: "missing"}, + }) + if err == nil { + t.Fatal("invalid second command unexpectedly succeeded") + } + if len(original.Documents) != 0 || len(original.Tabs) != 0 { + t.Fatalf("input mutated after rejected batch: %#v", original) + } +} diff --git a/internal/explorer/authoringv2/types.go b/internal/explorer/authoringv2/types.go index 213a39f0..f7ef4d49 100644 --- a/internal/explorer/authoringv2/types.go +++ b/internal/explorer/authoringv2/types.go @@ -55,7 +55,7 @@ type Document struct { Output Output `json:"output"` RootResourceType string `json:"rootResourceType,omitempty"` Route RouteNode `json:"route,omitempty"` - Columns []Column `json:"columns,omitempty"` + Columns []Column `json:"columns"` FixedFilters []FixedFilter `json:"fixedFilters,omitempty"` Actions []Action `json:"actions,omitempty"` @@ -215,6 +215,8 @@ type BuilderState struct { APIVersion string `json:"apiVersion"` Kind string `json:"kind"` LifecycleState string `json:"lifecycleState"` + DraftVersion int64 `json:"draftVersion"` + DraftDigest string `json:"draftDigest"` Workspace *Workspace `json:"workspace"` // Document is retained only as a source-compatible internal migration aid. Document *Document `json:"-"` @@ -282,6 +284,9 @@ func (d Document) Validate() error { if emptyID(d.Output.ID) || strings.TrimSpace(d.Output.Title) == "" { return fmt.Errorf("output id and title are required") } + if !physicalColumnPattern.MatchString(d.Output.ID) { + return fmt.Errorf("output id must contain only letters, digits, and underscores and may not start with a digit") + } if d.semantic() { return d.validateSemantic() } @@ -518,6 +523,9 @@ func (c CatalogSnapshot) Validate() error { } func (s BuilderState) Validate() error { + if s.DraftVersion < 0 { + return fmt.Errorf("draftVersion must not be negative") + } if s.APIVersion != APIVersion || s.Kind != StateKind { return fmt.Errorf("unsupported V2 builder state protocol or kind") } @@ -736,6 +744,9 @@ func (w Workspace) CanonicalJSON() ([]byte, error) { n.Documents = append([]Document(nil), n.Documents...) for i := range n.Documents { n.Documents[i].APIVersion = "" + if n.Documents[i].Columns == nil { + n.Documents[i].Columns = []Column{} + } n.Documents[i].Selections = append([]Selection(nil), n.Documents[i].Selections...) sort.SliceStable(n.Documents[i].Selections, func(a, b int) bool { left := n.Documents[i].Selections[a] @@ -777,6 +788,9 @@ func (w Workspace) NormalizePresentationOrders() Workspace { for documentIndex := range n.Documents { document := &n.Documents[documentIndex] columns := append([]Column(nil), document.Columns...) + if columns == nil { + columns = []Column{} + } for columnIndex := range columns { column := &columns[columnIndex] if column.Table != nil { @@ -993,6 +1007,11 @@ func DecodeWorkspace(raw []byte) (Workspace, error) { if err := out.Validate(); err != nil { return out, err } + for i := range out.Documents { + if out.Documents[i].Columns == nil { + out.Documents[i].Columns = []Column{} + } + } return out, nil } diff --git a/internal/explorer/authoringv2/workspace_test.go b/internal/explorer/authoringv2/workspace_test.go index 3545bf8c..150f6c90 100644 --- a/internal/explorer/authoringv2/workspace_test.go +++ b/internal/explorer/authoringv2/workspace_test.go @@ -54,7 +54,7 @@ func TestWorkspaceCanonicalizesDuplicateTableOrdersByStableColumnIdentity(t *tes func fiveTableWorkspace() Workspace { w := Workspace{APIVersion: APIVersion, Kind: WorkspaceKind, Documents: []Document{}, Tabs: []Tab{}} for i := 0; i < 5; i++ { - id := fmt.Sprintf("output-%d", i) + id := fmt.Sprintf("output_%d", i) w.Documents = append(w.Documents, workspaceDocument(id)) w.Tabs = append(w.Tabs, Tab{ID: "tab-" + id, Title: id, OutputID: id, Order: i, Visible: true}) } @@ -158,3 +158,18 @@ func TestDecodeWorkspaceRejectsUnknownFields(t *testing.T) { t.Fatalf("error=%v", err) } } + +func TestDecodeWorkspaceRepairsPreviouslyOmittedEmptyColumns(t *testing.T) { + raw := `{"apiVersion":"` + APIVersion + `","kind":"` + WorkspaceKind + `","explorer":{"title":"Patients"},"documents":[{"kind":"` + Kind + `","output":{"id":"patients","title":"Patients"},"rootResourceType":"Patient","route":{"occurrenceId":"base","resourceType":"Patient"}}],"tabs":[{"id":"tab-patients","title":"Patients","outputId":"patients","order":0,"visible":true}]}` + workspace, err := DecodeWorkspace([]byte(raw)) + if err != nil { + t.Fatal(err) + } + encoded, err := json.Marshal(workspace) + if err != nil { + t.Fatal(err) + } + if !strings.Contains(string(encoded), `"columns":[]`) { + t.Fatalf("decoded legacy draft did not restore required columns array: %s", encoded) + } +} diff --git a/internal/explorer/service.go b/internal/explorer/service.go index 92c5f6d2..eb4bf01e 100644 --- a/internal/explorer/service.go +++ b/internal/explorer/service.go @@ -176,6 +176,47 @@ func (s *Service) CreateEmptyInteractive(ctx context.Context, project, id, title return s.store.CreateInteractive(ctx, Explorer{Project: projectid.Legacy(project), ExplorerID: id, Title: title, ManagementMode: ManagementInteractive, UpdatedBy: actor, UpdatedAt: s.now()}) } +// CreateInteractiveFrom creates a new Explorer identity and, when requested, +// seeds it from a server-owned source workspace without asking the browser to +// reconstruct or re-identify that workspace. +func (s *Service) CreateInteractiveFrom(ctx context.Context, project, id, title, sourceExplorerID, actor string) (*Explorer, error) { + if strings.TrimSpace(sourceExplorerID) == "" { + return s.CreateEmptyInteractive(ctx, project, id, title, actor) + } + if id == "" || id == "default" { + return nil, fmt.Errorf("invalid interactive Explorer identity") + } + source, err := s.Get(ctx, project, sourceExplorerID) + if err != nil { + return nil, err + } + raw := source.DraftConfig + if len(raw) == 0 && source.ActiveRevisionID != "" { + revision, revisionErr := s.store.GetRevision(ctx, source.ActiveRevisionID) + if revisionErr != nil { + return nil, revisionErr + } + raw = revision.AuthoringBundle + } + if len(raw) == 0 { + return s.CreateEmptyInteractive(ctx, project, id, title, actor) + } + workspace, err := authoringv2.DecodeWorkspace(raw) + if err != nil { + return nil, fmt.Errorf("source Explorer has no cloneable workspace: %w", err) + } + workspace.Explorer.Title = title + canonical, err := workspace.CanonicalJSON() + if err != nil { + return nil, err + } + digest, err := workspace.Digest() + if err != nil { + return nil, err + } + return s.store.CreateInteractive(ctx, Explorer{Project: projectid.Legacy(project), ExplorerID: id, Title: title, ManagementMode: ManagementInteractive, DraftConfig: canonical, DraftVersion: 1, DraftDigest: digest, UpdatedBy: actor, UpdatedAt: s.now()}) +} + // SaveWorkspaceDraft persists canonical V2 authoring intent with optimistic // concurrency. It never compiles, materializes, or changes the active pointer. func (s *Service) SaveWorkspaceDraft(ctx context.Context, project, id string, workspace authoringv2.Workspace, expectedVersion int64, expectedDigest, actor string) (*Explorer, error) { @@ -200,6 +241,87 @@ func (s *Service) SaveWorkspaceDraft(ctx context.Context, project, id string, wo } return s.store.SaveDraft(ctx, *owner, expectedVersion, expectedDigest) } + +// ApplyWorkspaceCommands is the authoritative Builder mutation boundary. It +// resolves backend-owned identities, applies a command batch atomically, and +// persists both the new draft and the replay record in one compare-and-swap. +func (s *Service) ApplyWorkspaceCommands(ctx context.Context, project, id string, catalog authoringv2.CatalogSnapshot, request authoringv2.ApplyCommandsRequest, actor string) (*authoringv2.ApplyCommandsResponse, error) { + if err := request.Validate(); err != nil { + return nil, err + } + commandDigest, err := request.Digest() + if err != nil { + return nil, err + } + owner, err := s.Get(ctx, project, id) + if err != nil { + return nil, err + } + if owner.LastAuthoringCommandID == request.CommandID { + if owner.LastAuthoringCommandDigest != commandDigest { + return nil, ErrAuthoringCommandConflict + } + workspace, decodeErr := authoringv2.DecodeWorkspace(owner.DraftConfig) + if decodeErr != nil { + return nil, fmt.Errorf("decode replayed authoring workspace: %w", decodeErr) + } + results := []authoringv2.CommandResult{} + if len(owner.LastAuthoringCommandResults) != 0 { + if decodeErr := json.Unmarshal(owner.LastAuthoringCommandResults, &results); decodeErr != nil { + return nil, fmt.Errorf("decode replayed authoring command results: %w", decodeErr) + } + } + return &authoringv2.ApplyCommandsResponse{CommandID: request.CommandID, Workspace: workspace, DraftVersion: owner.DraftVersion, DraftDigest: owner.DraftDigest, Results: results, Diagnostics: []any{}}, nil + } + if owner.DraftVersion != request.ExpectedDraftVersion || (request.ExpectedDraftDigest != "" && owner.DraftDigest != request.ExpectedDraftDigest) { + return nil, ErrDraftConflict + } + + workspace := authoringv2.Workspace{APIVersion: authoringv2.APIVersion, Kind: authoringv2.WorkspaceKind, Explorer: authoringv2.ExplorerMetadata{Title: owner.Title}, Documents: []authoringv2.Document{}, Tabs: []authoringv2.Tab{}} + if len(owner.DraftConfig) != 0 { + workspace, err = authoringv2.DecodeWorkspace(owner.DraftConfig) + } else if owner.ActiveRevisionID != "" { + var revision *Revision + revision, err = s.store.GetRevision(ctx, owner.ActiveRevisionID) + if err == nil { + workspace, err = authoringv2.DecodeWorkspace(revision.AuthoringBundle) + } + } + if err != nil { + return nil, err + } + workspace, results, err := authoringv2.ApplyCommands(workspace, catalog, request.CommandID, request.Commands) + if err != nil { + return nil, err + } + canonical, err := workspace.CanonicalJSON() + if err != nil { + return nil, err + } + draftDigest, err := workspace.Digest() + if err != nil { + return nil, err + } + resultJSON, err := json.Marshal(results) + if err != nil { + return nil, err + } + owner.DraftConfig = canonical + owner.DraftDigest = draftDigest + owner.LastAuthoringCommandID = request.CommandID + owner.LastAuthoringCommandDigest = commandDigest + owner.LastAuthoringCommandResults = resultJSON + owner.UpdatedBy = actor + owner.UpdatedAt = s.now() + if strings.TrimSpace(workspace.Explorer.Title) != "" { + owner.Title = workspace.Explorer.Title + } + stored, err := s.store.SaveDraft(ctx, *owner, request.ExpectedDraftVersion, request.ExpectedDraftDigest) + if err != nil { + return nil, err + } + return &authoringv2.ApplyCommandsResponse{CommandID: request.CommandID, Workspace: workspace, DraftVersion: stored.DraftVersion, DraftDigest: stored.DraftDigest, Results: results, Diagnostics: []any{}}, nil +} func (s *Service) Revision(ctx context.Context, id string) (*Revision, error) { return s.store.GetRevision(ctx, id) } diff --git a/internal/explorer/store.go b/internal/explorer/store.go index 1354d29a..a6f1f793 100644 --- a/internal/explorer/store.go +++ b/internal/explorer/store.go @@ -6,11 +6,12 @@ import ( ) var ( - ErrNotFound = errors.New("explorer not found") - ErrDraftConflict = errors.New("explorer draft conflict") - ErrImmutableRevision = errors.New("explorer revision content is immutable") - ErrStaleCatalog = errors.New("stale Explorer authoring catalog") - ErrIncompleteCatalog = errors.New("Explorer catalog discovery is incomplete") + ErrNotFound = errors.New("explorer not found") + ErrDraftConflict = errors.New("explorer draft conflict") + ErrAuthoringCommandConflict = errors.New("Explorer authoring command ID was reused with different intent") + ErrImmutableRevision = errors.New("explorer revision content is immutable") + ErrStaleCatalog = errors.New("stale Explorer authoring catalog") + ErrIncompleteCatalog = errors.New("Explorer catalog discovery is incomplete") // ErrCorruptReceipt means that a persisted receipt does not match its // content-addressed identity, or that an immutable key was reused for a // different receipt. Callers must fail closed rather than execute it. @@ -27,10 +28,8 @@ type Store interface { Get(context.Context, string, string) (*Explorer, error) CreateInteractive(context.Context, Explorer) (*Explorer, error) CreateRepository(context.Context, Explorer) (*Explorer, error) - // expected and expectedDigest are retained for adapter compatibility and - // observability. Draft writes are last-write-wins; adapters must increment - // the stored draft version from the current value rather than trusting the - // caller's expected version. + // SaveDraft is an optimistic compare-and-swap. Adapters must reject a + // mismatched expected version/digest and increment the persisted version. SaveDraft(context.Context, Explorer, int64, ...string) (*Explorer, error) InsertCompilationReceipt(context.Context, CompilationReceipt) (*CompilationReceipt, error) GetCompilationReceiptForExplorer(context.Context, string, string, string) (*CompilationReceipt, error) diff --git a/internal/explorer/types.go b/internal/explorer/types.go index 673baa8a..0e797321 100644 --- a/internal/explorer/types.go +++ b/internal/explorer/types.go @@ -98,21 +98,24 @@ type Explorer struct { ManagementMode ManagementMode `json:"managementMode"` // DraftConfig is the lossless, canonical ExplorerConfigV2 packet used by // the Builder. - DraftConfig json.RawMessage `json:"draftConfig,omitempty"` - DraftVersion int64 `json:"draftVersion"` - DraftDigest string `json:"draftDigest,omitempty"` - ActiveRevisionID string `json:"activeRevisionId,omitempty"` - ActiveConfig json.RawMessage `json:"activeConfig,omitempty"` - RecipeDigest string `json:"recipeDigest,omitempty"` - ResolvedSchemaDigest string `json:"resolvedSchemaDigest,omitempty"` - SourceGeneration string `json:"sourceGeneration,omitempty"` - EmittedColumns []EmittedColumn `json:"emittedColumns,omitempty"` - Materializations []Materialization `json:"materializations,omitempty"` - Dataset DatasetMetadata `json:"dataset,omitempty"` - Publication PublicationMetadata `json:"publication,omitempty"` - Diagnostics []Diagnostic `json:"diagnostics,omitempty"` - UpdatedBy string `json:"updatedBy,omitempty"` - UpdatedAt time.Time `json:"updatedAt"` + DraftConfig json.RawMessage `json:"draftConfig,omitempty"` + DraftVersion int64 `json:"draftVersion"` + DraftDigest string `json:"draftDigest,omitempty"` + LastAuthoringCommandID string `json:"lastAuthoringCommandId,omitempty"` + LastAuthoringCommandDigest string `json:"lastAuthoringCommandDigest,omitempty"` + LastAuthoringCommandResults json.RawMessage `json:"lastAuthoringCommandResults,omitempty"` + ActiveRevisionID string `json:"activeRevisionId,omitempty"` + ActiveConfig json.RawMessage `json:"activeConfig,omitempty"` + RecipeDigest string `json:"recipeDigest,omitempty"` + ResolvedSchemaDigest string `json:"resolvedSchemaDigest,omitempty"` + SourceGeneration string `json:"sourceGeneration,omitempty"` + EmittedColumns []EmittedColumn `json:"emittedColumns,omitempty"` + Materializations []Materialization `json:"materializations,omitempty"` + Dataset DatasetMetadata `json:"dataset,omitempty"` + Publication PublicationMetadata `json:"publication,omitempty"` + Diagnostics []Diagnostic `json:"diagnostics,omitempty"` + UpdatedBy string `json:"updatedBy,omitempty"` + UpdatedAt time.Time `json:"updatedAt"` } type Materialization struct { OutputID string `json:"outputId"` diff --git a/internal/server/explorer_authoring_v2_routes.go b/internal/server/explorer_authoring_v2_routes.go index f6761332..e1b252ab 100644 --- a/internal/server/explorer_authoring_v2_routes.go +++ b/internal/server/explorer_authoring_v2_routes.go @@ -52,7 +52,7 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth return c.JSON(explorerv2api.AuthoringCapability{ ApiVersion: explorerv2api.LoomCalyprOrgexplorerAuthoringv2, Kind: explorerv2api.ExplorerAuthoringCapabilities, - Operations: []explorerv2api.AuthoringCapabilityOperations{explorerv2api.Builder, explorerv2api.Compile, explorerv2api.Draft, explorerv2api.Export, explorerv2api.Suggestions, explorerv2api.Preview, explorerv2api.Publish}, + Operations: []explorerv2api.AuthoringCapabilityOperations{explorerv2api.Builder, explorerv2api.Compile, explorerv2api.Draft, explorerv2api.Export, explorerv2api.Suggestions, explorerv2api.Preview, explorerv2api.Publish, explorerv2api.Commands, explorerv2api.Reconcile}, PreviewLimits: []int{10, 25, 50, 100}, Features: explorerv2api.AuthoringFeatures{EmissionFilters: true, EmissionCharts: true}, }) @@ -138,7 +138,7 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth if err != nil { return authoringHTTPError(c, err) } - state := authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, LifecycleState: authoringv2.LifecycleNew, Catalog: wire} + state := authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, LifecycleState: authoringv2.LifecycleNew, DraftVersion: owner.DraftVersion, DraftDigest: owner.DraftDigest, Catalog: wire} var activeWorkspace *authoringv2.Workspace if owner.ActiveRevisionID != "" { active, activeErr := explorers.ActiveRevision(c.Context(), project, id) @@ -238,14 +238,39 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth return c.Send(canonical) }) - compileHandler := func(c fiber.Ctx) error { + app.Post(prefix+"/commands", func(c fiber.Ctx) error { if err := authoringWrite(c, authorizer); err != nil { return err } - var request explorerv2api.CompileRequest + var request authoringv2.ApplyCommandsRequest if err := decodeAuthoringStrict(c.Body(), &request); err != nil { - return authoringHTTPError(c, malformedRouteError("intent", err)) + return authoringHTTPError(c, malformedRouteError("commands", err)) + } + if err := request.Validate(); err != nil { + return authoringHTTPError(c, malformedRouteError("commands", err)) + } + if capabilities.CapabilityToken == nil { + return authoringHTTPError(c, explorerUnavailable("commands", "CAPABILITY_UNAVAILABLE", "Explorer capability lookup is not configured")) + } + project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) + snapshot, err := capabilities.CapabilityToken(c.Context(), project, request.SnapshotToken) + if err != nil || snapshot.ValidateToken(request.SnapshotToken) != nil { + return authoringHTTPError(c, explorerConflict("commands", "STALE_CATALOG_SNAPSHOT", "the catalog snapshot is stale or unavailable", nil)) + } + response, err := explorers.ApplyWorkspaceCommands(c.Context(), project, id, authoringV2Catalog(snapshot, id), request, subjectFromFiber(c)) + switch { + case errors.Is(err, explorer.ErrDraftConflict): + return authoringHTTPError(c, explorerConflict("commands", "DRAFT_CONFLICT", "the Explorer draft changed; reload before editing", nil)) + case errors.Is(err, explorer.ErrAuthoringCommandConflict): + return authoringHTTPError(c, explorerConflict("commands", "COMMAND_ID_CONFLICT", "commandId was already used for different intent", nil)) + case err != nil: + return authoringHTTPError(c, authoringSemanticRoute("commands", "$.commands", "INVALID_AUTHORING_COMMAND", err.Error(), nil)) + default: + return c.JSON(response) } + }) + + compileWorkspace := func(c fiber.Ctx, workspace authoringv2.Workspace, snapshotToken string) error { if (capabilities.CapabilityToken == nil && capabilities.AuthorizedCapabilityCompile == nil) || capabilities.CompileReceipt == nil { return authoringHTTPError(c, explorerUnavailable("compile", "CAPABILITY_UNAVAILABLE", "Explorer V2 compiler is not configured")) } @@ -254,20 +279,20 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth var snapshot capability.Snapshot var authorized AuthorizedCapability if capabilities.AuthorizedCapabilityCompile != nil { - authorized, err = capabilities.AuthorizedCapabilityCompile(c.Context(), project, request.SnapshotToken) + authorized, err = capabilities.AuthorizedCapabilityCompile(c.Context(), project, snapshotToken) snapshot = authorized.Snapshot } else { - snapshot, err = capabilities.CapabilityToken(c.Context(), project, request.SnapshotToken) + snapshot, err = capabilities.CapabilityToken(c.Context(), project, snapshotToken) } if err != nil { - return authoringHTTPError(c, explorerConflict("capability", "STALE_CATALOG_SNAPSHOT", "the capability snapshot is stale or unavailable", map[string]any{"snapshotToken": request.SnapshotToken})) + return authoringHTTPError(c, explorerConflict("capability", "STALE_CATALOG_SNAPSHOT", "the capability snapshot is stale or unavailable", map[string]any{"snapshotToken": snapshotToken})) } wire := authoringV2Catalog(snapshot, id) - state := authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, Workspace: &request.Workspace, Catalog: wire} + state := authoringv2.BuilderState{APIVersion: authoringv2.APIVersion, Kind: authoringv2.StateKind, Workspace: &workspace, Catalog: wire} if err := state.Validate(); err != nil { return authoringHTTPError(c, authoringSemanticRoute("intent", "$", workspaceValidationCode(err), err.Error(), nil)) } - stored, err := capabilities.CompileReceipt(c.Context(), ExplorerV2ReceiptCompileRequest{Project: project, ExplorerID: id, Workspace: request.Workspace, SnapshotToken: snapshot.Token, RequestID: requestIDFromFiber(c), Authorized: authorized}) + stored, err := capabilities.CompileReceipt(c.Context(), ExplorerV2ReceiptCompileRequest{Project: project, ExplorerID: id, Workspace: workspace, SnapshotToken: snapshot.Token, RequestID: requestIDFromFiber(c), Authorized: authorized}) if err != nil { var compileErr *explorercompilation.Error if errors.As(err, &compileErr) { @@ -278,10 +303,48 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth if stored == nil || strings.TrimSpace(stored.ID) == "" { return authoringHTTPError(c, explorerUnavailable("compile", "COMPILATION_RECEIPT_STORE_FAILED", "compiled authoring receipt was not persisted")) } - return c.JSON(v2ReceiptResponse(stored, request.Workspace)) + return c.JSON(v2ReceiptResponse(stored, workspace)) + } + compileHandler := func(c fiber.Ctx) error { + if err := authoringWrite(c, authorizer); err != nil { + return err + } + var request explorerv2api.CompileRequest + if err := decodeAuthoringStrict(c.Body(), &request); err != nil { + return authoringHTTPError(c, malformedRouteError("intent", err)) + } + return compileWorkspace(c, request.Workspace, request.SnapshotToken) } app.Post(prefix+"/builder", compileHandler) app.Post(prefix+"/compile", compileHandler) + app.Post(prefix+"/reconcile", func(c fiber.Ctx) error { + if err := authoringWrite(c, authorizer); err != nil { + return err + } + var request struct { + SnapshotToken string `json:"snapshotToken"` + DraftVersion int64 `json:"draftVersion"` + DraftDigest string `json:"draftDigest"` + } + if err := decodeAuthoringStrict(c.Body(), &request); err != nil || strings.TrimSpace(request.SnapshotToken) == "" || request.DraftVersion < 0 { + if err == nil { + err = fmt.Errorf("snapshotToken, draftVersion, and draftDigest are required") + } + return authoringHTTPError(c, malformedRouteError("reconcile", err)) + } + owner, err := explorers.Get(c.Context(), explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId"))) + if err != nil { + return authoringHTTPError(c, err) + } + if owner.DraftVersion != request.DraftVersion || owner.DraftDigest != request.DraftDigest { + return authoringHTTPError(c, explorerConflict("reconcile", "DRAFT_CONFLICT", "the Explorer draft changed; reload before reconciling", nil)) + } + workspace, err := authoringv2.DecodeWorkspace(owner.DraftConfig) + if err != nil { + return authoringHTTPError(c, explorerConflict("reconcile", "AUTHORING_STATE_MISSING", "the saved Explorer draft cannot be reconciled", nil)) + } + return compileWorkspace(c, workspace, request.SnapshotToken) + }) app.Post(prefix+"/preview", func(c fiber.Ctx) error { started := time.Now() diff --git a/internal/server/explorer_builder_lifecycle.go b/internal/server/explorer_builder_lifecycle.go index 34ceff00..b7327d9c 100644 --- a/internal/server/explorer_builder_lifecycle.go +++ b/internal/server/explorer_builder_lifecycle.go @@ -53,8 +53,9 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author return err } var request struct { - Name string `json:"name"` - Title string `json:"title,omitempty"` + Name string `json:"name"` + Title string `json:"title,omitempty"` + SourceExplorerID string `json:"sourceExplorerId,omitempty"` } if err := decodeStrict(c.Body(), &request); err != nil || strings.TrimSpace(request.Name) == "" { return explorerV2Error(c, 400, "MALFORMED_REQUEST", "name is required") @@ -67,7 +68,7 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author if title == "" { title = strings.TrimSpace(request.Name) } - value, err := explorers.CreateEmptyInteractive(c.Context(), project, id, title, subjectFromFiber(c)) + value, err := explorers.CreateInteractiveFrom(c.Context(), project, id, title, strings.TrimSpace(request.SourceExplorerID), subjectFromFiber(c)) if errors.Is(err, explorer.ErrDraftConflict) { return explorerV2Error(c, 409, "EXPLORER_EXISTS", "an Explorer with this name already exists") } diff --git a/internal/server/explorer_receipt_contract_test.go b/internal/server/explorer_receipt_contract_test.go index fb3bf97c..397fea88 100644 --- a/internal/server/explorer_receipt_contract_test.go +++ b/internal/server/explorer_receipt_contract_test.go @@ -3,7 +3,9 @@ package server import ( "context" "encoding/json" + "fmt" "net/http" + "regexp" "strings" "testing" "time" @@ -91,7 +93,7 @@ func TestCompiledExplorerWorkspaceConfigUsesIndependentStablePresentationOrders( {EmissionID: "column_a", OutputID: "out", PublicColumn: "column_a"}, }, Presentations: []explorercompilation.PresentationConfig{{OutputID: "out", Columns: []explorercompilation.PresentationColumn{ - {EmissionID: "column_b", PublicColumn: "column_b", Label: "B", Visible: true, Order: 0, FilterLabel: "B", FilterOrder: 0, ChartType: "bar", ChartOrder: 0}, + {EmissionID: "column_b", PublicColumn: "column_b", Label: "B", Visible: false, Order: 0, FilterLabel: "B", FilterOrder: 0, ChartType: "bar", ChartOrder: 0}, {EmissionID: "column_a", PublicColumn: "column_a", Label: "A", Visible: true, Order: 0, FilterLabel: "A", FilterOrder: 0, ChartType: "line", ChartOrder: 1}, }}}, } @@ -110,6 +112,9 @@ func TestCompiledExplorerWorkspaceConfigUsesIndependentStablePresentationOrders( if view.Filters[0].Column != "column_a" || view.Filters[1].Column != "column_b" { t.Fatalf("filter order=%#v", view.Filters) } + if view.Table.Columns[1].Visible || view.Filters[1].Column != view.Table.Columns[1].Column { + t.Fatalf("hidden filter-only column was not preserved: table=%#v filters=%#v", view.Table.Columns, view.Filters) + } if view.Charts[0].Column != "column_b" || view.Charts[1].Column != "column_a" { t.Fatalf("chart order=%#v", view.Charts) } @@ -218,6 +223,93 @@ func TestNativeV2RouteUsesAuthorizedPersistedReceipt(t *testing.T) { } } +func TestBuilderCommandsCreateBackendOwnedDraftAndReconcileIt(t *testing.T) { + snapshot := testAuthoringV2CapabilitySnapshot() + service, err := explorer.NewService(newTestExplorerStore()) + if err != nil { + t.Fatal(err) + } + if _, err := service.CreateEmptyInteractive(context.Background(), "project-a", "custom", "Custom", "test"); err != nil { + t.Fatal(err) + } + config := ExplorerV2LifecycleConfig{ + Capability: func(context.Context, string, string, string) (capability.Snapshot, error) { return snapshot, nil }, + CapabilityToken: func(context.Context, string, string) (capability.Snapshot, error) { return snapshot, nil }, + AuthorizedCapabilityCompile: func(context.Context, string, string) (AuthorizedCapability, error) { + return AuthorizedCapability{Snapshot: snapshot, Scope: authscope.ReadScope{Mode: authscope.ReadScopeUnrestricted}}, nil + }, + CompileReceipt: func(ctx context.Context, request ExplorerV2ReceiptCompileRequest) (*explorer.CompilationReceipt, error) { + return persistTestNativeReceipt(ctx, t, service, request, snapshot) + }, + } + app := fiber.New() + RegisterExplorerAuthoringV2Routes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, config) + + commandBody := `{"commandId":"browser-command-1","snapshotToken":"` + snapshot.Token + `","expectedDraftVersion":0,"commands":[{"type":"CREATE_TABLE","title":"Patients","rootNodeId":"n_patient"}]}` + created := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/commands", commandBody) + if created.StatusCode != http.StatusOK { + t.Fatalf("command status=%d body=%s", created.StatusCode, created.Body) + } + if !strings.Contains(created.Body, `"columns":[]`) { + t.Fatalf("command response omitted required empty columns array: %s", created.Body) + } + var response authoringv2.ApplyCommandsResponse + if err := json.Unmarshal([]byte(created.Body), &response); err != nil { + t.Fatal(err) + } + if response.DraftVersion != 1 || len(response.Workspace.Documents) != 1 || !regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*$`).MatchString(response.Workspace.Documents[0].Output.ID) { + t.Fatalf("command response=%#v", response) + } + replayed := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/commands", commandBody) + if replayed.StatusCode != http.StatusOK || !strings.Contains(replayed.Body, `"draftVersion":1`) { + t.Fatalf("replay status=%d body=%s", replayed.StatusCode, replayed.Body) + } + conflicting := strings.Replace(commandBody, `"Patients"`, `"Different"`, 1) + conflict := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/commands", conflicting) + if conflict.StatusCode != http.StatusConflict || !strings.Contains(conflict.Body, `"code":"COMMAND_ID_CONFLICT"`) { + t.Fatalf("command ID conflict status=%d body=%s", conflict.StatusCode, conflict.Body) + } + reconcileBody := fmt.Sprintf(`{"snapshotToken":%q,"draftVersion":%d,"draftDigest":%q}`, snapshot.Token, response.DraftVersion, response.DraftDigest) + reconciled := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/reconcile", reconcileBody) + if reconciled.StatusCode != http.StatusOK || !strings.Contains(reconciled.Body, `"kind":"ExplorerBuilderReceipt"`) { + t.Fatalf("reconcile status=%d body=%s", reconciled.StatusCode, reconciled.Body) + } +} + +func TestCreateExplorerFromCurrentClonesWorkspaceOnServer(t *testing.T) { + service, err := explorer.NewService(newTestExplorerStore()) + if err != nil { + t.Fatal(err) + } + if _, err := service.CreateEmptyInteractive(context.Background(), "project-a", "source", "Source", "test"); err != nil { + t.Fatal(err) + } + workspace, err := authoringv2.DecodeWorkspace(baselineExplorerWorkspaceV2()) + if err != nil { + t.Fatal(err) + } + if _, err := service.SaveWorkspaceDraft(context.Background(), "project-a", "source", workspace, 0, "", "test"); err != nil { + t.Fatal(err) + } + app := fiber.New() + RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{}) + created := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers", `{"name":"Cloned Explorer","title":"Cloned Explorer","sourceExplorerId":"source"}`) + if created.StatusCode != http.StatusCreated { + t.Fatalf("clone status=%d body=%s", created.StatusCode, created.Body) + } + clone, err := service.Get(context.Background(), "project-a", explorer.StableExplorerID("Cloned Explorer")) + if err != nil { + t.Fatal(err) + } + clonedWorkspace, err := authoringv2.DecodeWorkspace(clone.DraftConfig) + if err != nil { + t.Fatal(err) + } + if clone.DraftVersion != 1 || clonedWorkspace.Explorer.Title != "Cloned Explorer" || len(clonedWorkspace.Documents) != len(workspace.Documents) || clonedWorkspace.Documents[0].Output.ID != workspace.Documents[0].Output.ID { + t.Fatalf("cloned Explorer=%#v workspace=%#v", clone, clonedWorkspace) + } +} + func persistTestNativeReceipt(ctx context.Context, t *testing.T, service *explorer.Service, request ExplorerV2ReceiptCompileRequest, snapshot capability.Snapshot) (*explorer.CompilationReceipt, error) { t.Helper() workspace := request.Workspace From c682c4ee14b7ec7e4c2546a6058aad3e308e42a1 Mon Sep 17 00:00:00 2001 From: matthewpeterkort Date: Fri, 28 Aug 2026 16:33:27 -0700 Subject: [PATCH 12/15] cleanup docs, wire up routes to openapi spec --- .github/workflows/tests.yaml | 11 +- Makefile | 13 +- README.md | 21 +- cmd/explorer-config-v2-convert/main.go | 377 + cmd/generate/fhir_helpers.go.tmpl | 141 + cmd/generate/helpers.go | 10 + cmd/generate/main.go | 16 +- cmd/generate/model_test.go | 1 + cmd/gqlgenfix/main.go | 45 +- cmd/gqlgenfix/main_test.go | 40 + docs/CODE_GENERATION.md | 20 +- docs/DATAFRAMER_RECIPES.md | 9 +- docs/DEVELOPER_ARCHITECTURE.md | 20 +- docs/EXPLORER_AUTHORING.md | 25 - docs/EXPLORER_RECIPE_BOUNDARY.md | 546 -- ...ONTEND_DATAFRAME_FACET_PERFORMANCE_PLAN.md | 467 - docs/FRONTEND_EXPLORER_V2_MIGRATION.md | 484 -- docs/GRAPHQL_API.md | 2 +- docs/LOOM _CLEANUP.md | 93 - docs/LOOM_EXPLORER_ARCHITECTURE_POSTMORTEM.md | 1439 ---- docs/PLAN_BACKEND_OWNED_EXPLORER_AUTHORING.md | 799 -- docs/PLAN_EXPLORER_V2_BRANCHED_TRAVERSAL.md | 282 - docs/QUICKSTART.md | 25 +- docs/README.md | 34 +- .../explorer-v2-capability-authoring.md | 51 +- generated/fhir/helpers.go | 4 +- generated/graphql/graph/executor/scalars.go | 24 - .../graph/executor/schema.generated.go | 18 + generated/loomapi/api.gen.go | 7538 +++++++++++++++++ go.mod | 6 + go.sum | 22 + internal/api/bulk/load/generation_route.go | 4 +- internal/api/bulk/load/handler.go | 9 - internal/api/bulk/load/raw_load.go | 2 +- internal/api/bulk/load/resource_route.go | 9 +- internal/api/bulk/load/resource_route_test.go | 2 +- internal/api/bulk/load/snapshot_route.go | 39 +- internal/api/bulk/load/snapshot_route_test.go | 2 +- .../api/bulk/load/test_server_helpers_test.go | 30 +- internal/api/graphql/graph/handler.go | 15 - .../graphql/graph/http_integration_test.go | 7 +- internal/api/http/http_test.go | 21 +- internal/api/http/recipe_execution.go | 78 +- internal/api/http/routes.go | 13 +- .../server/explorer_authoring_v2_routes.go | 74 +- internal/server/explorer_builder_lifecycle.go | 30 +- internal/server/explorer_config_route.go | 32 +- internal/server/explorer_config_route_test.go | 2 +- internal/server/explorer_lifecycle_helpers.go | 10 - internal/server/explorer_preview_response.go | 2 +- .../server/explorer_receipt_contract_test.go | 6 +- .../explorer_route_test_helpers_test.go | 40 + internal/server/explorer_state_route_test.go | 4 +- .../server/openapi_route_inventory_test.go | 124 + internal/server/openapi_routes.go | 1196 +++ internal/server/routes.go | 15 +- internal/server/routes_test.go | 16 +- internal/server/server.go | 8 +- openapi/README.md | 40 + openapi/oapi-codegen.yaml | 10 + openapi/openapi.yaml | 1645 ++++ 61 files changed, 11582 insertions(+), 4486 deletions(-) create mode 100644 cmd/explorer-config-v2-convert/main.go create mode 100644 cmd/generate/fhir_helpers.go.tmpl create mode 100644 cmd/generate/helpers.go create mode 100644 cmd/gqlgenfix/main_test.go delete mode 100644 docs/EXPLORER_RECIPE_BOUNDARY.md delete mode 100644 docs/FRONTEND_DATAFRAME_FACET_PERFORMANCE_PLAN.md delete mode 100644 docs/FRONTEND_EXPLORER_V2_MIGRATION.md delete mode 100644 docs/LOOM _CLEANUP.md delete mode 100644 docs/LOOM_EXPLORER_ARCHITECTURE_POSTMORTEM.md delete mode 100644 docs/PLAN_BACKEND_OWNED_EXPLORER_AUTHORING.md delete mode 100644 docs/PLAN_EXPLORER_V2_BRANCHED_TRAVERSAL.md delete mode 100644 generated/graphql/graph/executor/scalars.go create mode 100644 generated/loomapi/api.gen.go create mode 100644 internal/server/explorer_route_test_helpers_test.go create mode 100644 internal/server/openapi_route_inventory_test.go create mode 100644 internal/server/openapi_routes.go create mode 100644 openapi/README.md create mode 100644 openapi/oapi-codegen.yaml create mode 100644 openapi/openapi.yaml diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 17f2b776..45c06a31 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -47,11 +47,16 @@ jobs: - name: Generate GraphQL code run: make generate-graphql - - name: Generate Explorer V2 API code - run: make generate-explorer-v2 + - name: Generate Loom OpenAPI code + run: make generate-openapi - name: Check generated code is current - run: git diff --exit-code -- generated/fhir generated/fhirschema generated/graphql generated/explorerv2 + run: | + git diff --exit-code -- generated/fhir generated/fhirschema generated/graphql generated/loomapi + test -z "$(git status --porcelain --untracked-files=all -- generated)" + + - name: Check OpenAPI route ownership + run: make openapi-check - name: Run GraphQL contract checks run: make graphql-check diff --git a/Makefile b/Makefile index 3e3f2cae..96c8e554 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: build build-cli build-server clean compiler-bench dataframe-demo dataframe-profile dataframe-boundaries dataframe-test conformance generate generate-explorer-v2 generate-fhir generate-graphql graphql-check gqlgen-check test docker-build docker-run +.PHONY: build build-cli build-server clean compiler-bench dataframe-demo dataframe-profile dataframe-boundaries dataframe-test conformance generate generate-openapi generate-fhir generate-graphql graphql-check gqlgen-check openapi-check test docker-build docker-run GO ?= go GO_VERSION ?= 1.26.5 @@ -20,7 +20,7 @@ DATAFRAME_PROFILE_LIMIT ?= 1000 build: build-cli build-server -generate: generate-fhir generate-graphql generate-explorer-v2 +generate: generate-fhir generate-graphql generate-openapi build-cli: mkdir -p bin $(GOCACHE_DIR) @@ -40,9 +40,12 @@ generate-fhir: GOCACHE=$(GOCACHE_DIR) GOTOOLCHAIN=$(GO_TOOLCHAIN) $(GO) run ./cmd/generate -schema $(SCHEMA_PATH) -structs-out generated/fhir -metadata-out generated/fhirschema/generated.go gofmt -w generated/fhir/*.go generated/fhirschema/generated.go -generate-explorer-v2: - mkdir -p generated/explorerv2 $(GOCACHE_DIR) - GOCACHE=$(GOCACHE_DIR) GOTOOLCHAIN=$(GO_TOOLCHAIN) $(GO) run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@$(OAPI_CODEGEN_VERSION) --config schemas/explorer-authoring-v2/oapi-codegen.yaml schemas/explorer-authoring-v2/openapi.yaml +generate-openapi: + mkdir -p generated/loomapi $(GOCACHE_DIR) + GOCACHE=$(GOCACHE_DIR) GOTOOLCHAIN=$(GO_TOOLCHAIN) $(GO) run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@$(OAPI_CODEGEN_VERSION) --config openapi/oapi-codegen.yaml openapi/openapi.yaml + +openapi-check: + bash scripts/check_openapi_route_ownership.sh graphql-check: mkdir -p $(GOCACHE_DIR) diff --git a/README.md b/README.md index d4f2e1f3..e6f6927f 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ replacement FHIR model. It is a recipe-driven graph-to-flat data service with explicit authorization and publication boundaries. Explorer Builder authoring is intent-driven: the browser submits the versioned -V1 authoring document, Loom lowers it to a native recipe, and the existing +V2 authoring document, Loom lowers it to a native recipe, and the existing recipe compiler produces the scoped plan/AQL. The browser never constructs or repairs the recipe AST. See [the Explorer authoring contract](docs/EXPLORER_AUTHORING.md). @@ -60,19 +60,19 @@ recipe, translation-version, and output selector. | `arango-fhir-server` | HTTP server for graph compilation/control and flat dataframe reads. | | `POST /graphql/graph` | Arango graph and recipe control plane: explicit graph traversal, typed FHIR reads, recipe validation, preview, execution, publication reads, and recipe control. | | `POST /graphql/dataframe` | Arango-backed FHIR dataframe compiler and executor (`runFhirDataframe`). | -| `POST /api/v1/projects/:project/explorers/...` | REST Explorer lifecycle and V1 intent authoring used by the Builder. | +| `POST /api/v1/projects/:project/explorers/...` | REST Explorer lifecycle and V2 intent authoring used by the Builder. | | `PUT /api/v1/projects/:project/resources/:resourceType` | Primary multipart NDJSON resource loader. | `GET /graphql/graph` serves GraphQL Playground for the graph API. `GET /apollo` opens Apollo Sandbox pointed at `/graphql/graph`. There is intentionally no `/graphql` compatibility route. -The server exposes only the primary resource upload route from the bulk -load package. Raw, generation, and dump handlers remain available to -in-cluster operators and direct database tooling, but are not public routes. -The `:project` path parameter is required: it is the tenancy identity used for -authorization and becomes the published row `project_id` (for example, -`HTAN_INT-BForePC`). +The canonical contract for every server route is +[`openapi/openapi.yaml`](openapi/openapi.yaml). It includes health, ingestion, +snapshot/release, recipe execution, GraphQL transport, Explorer lifecycle, and +Explorer authoring operations. The `:project` path parameter is the tenancy +identity used for authorization and becomes the published row `project_id` +(for example, `HTAN_INT-BForePC`). ## Data lifecycle @@ -294,6 +294,7 @@ without rebuilding the server image. | Path | Responsibility | | --- | --- | | [`cmd/`](cmd) | Operator CLI, server executable, and developer tools. | +| [`openapi/`](openapi) | Canonical Loom HTTP specification and generator configuration. | | [`schemas/`](schemas) | Source FHIR graph schema. | | [`gqlgen.yml`](gqlgen.yml) | gqlgen source configuration. | | [`generated/`](generated) | Checked-in generator-managed artifacts; see the code-generation guide before editing. | @@ -305,7 +306,7 @@ without rebuilding the server image. | [`internal/ingest`](internal/ingest) | NDJSON loading, validation, graph extraction, and ingest lifecycle. | | [`internal/dataset`](internal/dataset) | Immutable generation and active-manifest contracts. | | [`internal/catalog`](internal/catalog) | Evidence of populated fields, references, and authorization paths. | -| [`internal/explorer`](internal/explorer) | V1 authoring intent, resolved Builder models, server compilation receipts, immutable revisions, publication state, and legacy ETL compatibility types. | +| [`internal/explorer`](internal/explorer) | V2 authoring intent, resolved Builder models, server compilation receipts, immutable revisions, publication state, and legacy migration types. | | [`internal/dataframe/compiler`](internal/dataframe/compiler) | Typed plan IR, lowering, optimization, and AQL rendering. | | [`internal/dataframe/recipe`](internal/dataframe/recipe) | Recipe contract, validation, schema resolution, execution, and control services. | | [`internal/dataframe/publication`](internal/dataframe/publication) | Backend-neutral bounded streaming publication contract. | @@ -322,6 +323,7 @@ without rebuilding the server image. make build # server and CLI binaries make generate-fhir # generated FHIR structs and schema metadata make generate-graphql # gqlgen bindings +make generate-openapi # Loom HTTP models and strict Fiber server make graphql-check # GraphQL and dataframe checks make test # full Go test suite make conformance # compiler conformance corpus @@ -343,6 +345,7 @@ go test ./... ## Further reading - [Documentation index](docs/README.md) +- [OpenAPI contract](openapi/README.md) - [Quickstart](docs/QUICKSTART.md) - [Explorer authoring contract](docs/EXPLORER_AUTHORING.md) - [Default dataframer recipe authoring guide](docs/DATAFRAMER_RECIPES.md) diff --git a/cmd/explorer-config-v2-convert/main.go b/cmd/explorer-config-v2-convert/main.go new file mode 100644 index 00000000..0cc97e9a --- /dev/null +++ b/cmd/explorer-config-v2-convert/main.go @@ -0,0 +1,377 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "os" + "sort" + "strings" + "unicode" + + "github.com/calypr/loom/internal/dataframe/recipe" + "github.com/calypr/loom/internal/explorer" + "github.com/calypr/loom/internal/explorer/authoringv2" +) + +type report struct { + Source string `json:"source"` + Outputs map[string]int `json:"outputs"` + Converted int `json:"convertedColumns"` + Unsupported []string `json:"unsupportedColumns"` + DroppedOutputs []string `json:"droppedOutputs"` + DroppedFeatures []string `json:"droppedFeatures"` +} + +func main() { + input := flag.String("in", "", "legacy ExplorerConfigV2 JSON") + output := flag.String("out", "", "V2 authoring workspace JSON") + reportPath := flag.String("report", "", "conversion report JSON") + flag.Parse() + if *input == "" || *output == "" { + fatalf("-in and -out are required") + } + raw, err := os.ReadFile(*input) + if err != nil { + fatalf("read input: %v", err) + } + var config explorer.ConfigV2 + if err := json.Unmarshal(raw, &config); err != nil { + fatalf("decode input: %v", err) + } + bundle, err := recipe.Parse(config.Recipe) + if err != nil { + fatalf("decode recipe: %v", err) + } + workspace, conversionReport, err := convert(*input, config, bundle) + if err != nil { + fatalf("convert: %v", err) + } + workspaceJSON, err := json.MarshalIndent(workspace, "", " ") + if err != nil { + fatalf("encode workspace: %v", err) + } + workspaceJSON = append(workspaceJSON, '\n') + if err := os.WriteFile(*output, workspaceJSON, 0o644); err != nil { + fatalf("write workspace: %v", err) + } + if *reportPath != "" { + reportJSON, _ := json.MarshalIndent(conversionReport, "", " ") + if err := os.WriteFile(*reportPath, append(reportJSON, '\n'), 0o644); err != nil { + fatalf("write report: %v", err) + } + } + if len(conversionReport.Unsupported) != 0 { + fatalf("conversion left %d unsupported columns; see %s", len(conversionReport.Unsupported), *reportPath) + } +} + +func convert(source string, config explorer.ConfigV2, bundle recipe.Bundle) (authoringv2.Workspace, report, error) { + result := authoringv2.Workspace{APIVersion: authoringv2.APIVersion, Kind: authoringv2.WorkspaceKind, Explorer: authoringv2.ExplorerMetadata{Title: config.Explorer.Title, Description: config.Explorer.Description}, Documents: []authoringv2.Document{}, Tabs: []authoringv2.Tab{}, SharedFilters: map[string][]authoringv2.SharedFilterBinding{}} + conversionReport := report{Source: source, Outputs: map[string]int{}, DroppedFeatures: []string{"unreferenced discovery-expanded columns", "unreferenced recipe outputs"}} + outputs := map[string]recipe.Output{} + for _, output := range bundle.Outputs { + outputs[output.Name] = output + } + visibleOutputs := map[string]bool{} + for tabIndex, view := range config.Views { + legacyOutput, ok := outputs[view.Output] + if !ok { + return result, conversionReport, fmt.Errorf("view %q references unknown output %q", view.ID, view.Output) + } + visibleOutputs[view.Output] = true + referenced := referencedColumns(config, view) + paths := routePaths(legacyOutput) + document := authoringv2.Document{Kind: authoringv2.Kind, Output: authoringv2.Output{ID: view.Output, Title: view.Title, RowLabel: view.RowLabel}, RootResourceType: legacyOutput.RootResourceType, Columns: []authoringv2.Column{}, FixedFilters: []authoringv2.FixedFilter{}, Actions: []authoringv2.Action{}} + usedOccurrences := map[string]bool{authoringv2.RootOccurrenceID: true} + for _, name := range referenced { + occurrenceID, leaf := occurrenceForColumn(name, paths) + legacyPresentation := presentationFor(view, name) + sourceSpec, logicalType, inferErr := inferSource(config.Project, legacyOutput.RootResourceType, occurrenceID, leaf, name) + if inferErr != nil { + conversionReport.Unsupported = append(conversionReport.Unsupported, view.Output+":"+name+":"+inferErr.Error()) + continue + } + usedOccurrences[occurrenceID] = true + document.Columns = append(document.Columns, authoringv2.Column{Column: name, Label: legacyPresentation.label, LogicalType: logicalType, OccurrenceID: occurrenceID, Source: sourceSpec, Table: legacyPresentation.table, Filter: legacyPresentation.filter, Chart: legacyPresentation.chart}) + } + document.Route = prunedRoute(legacyOutput, paths, usedOccurrences) + for column, values := range view.FixedFilters { + document.FixedFilters = append(document.FixedFilters, authoringv2.FixedFilter{Column: column, Values: append([]string(nil), values...)}) + } + sort.Slice(document.FixedFilters, func(i, j int) bool { return document.FixedFilters[i].Column < document.FixedFilters[j].Column }) + for _, action := range view.Actions { + converted := authoringv2.Action{Type: action.Type, Title: action.Title, FileName: action.FileName} + for _, column := range action.Columns { + converted.Columns = append(converted.Columns, authoringv2.ActionColumn{Column: column}) + } + document.Actions = append(document.Actions, converted) + } + conversionReport.Outputs[view.Output] = len(document.Columns) + conversionReport.Converted += len(document.Columns) + result.Documents = append(result.Documents, document) + result.Tabs = append(result.Tabs, authoringv2.Tab{ID: view.ID, Title: view.Title, OutputID: view.Output, Order: tabIndex, Visible: true}) + } + for _, output := range bundle.Outputs { + if !visibleOutputs[output.Name] { + conversionReport.DroppedOutputs = append(conversionReport.DroppedOutputs, output.Name) + } + } + for name, bindings := range config.SharedFilters { + for _, binding := range bindings { + if visibleOutputs[binding.Output] { + result.SharedFilters[name] = append(result.SharedFilters[name], authoringv2.SharedFilterBinding{OutputID: binding.Output, Column: binding.Column}) + } + } + } + if len(config.FileActions.Extensions) != 0 || len(config.FileActions.Actions) != 0 { + result.FileActions = &authoringv2.FileActions{Extensions: config.FileActions.Extensions, Actions: config.FileActions.Actions} + } + if err := result.ValidateForPublication(); err != nil && len(conversionReport.Unsupported) == 0 { + return result, conversionReport, err + } + sort.Strings(conversionReport.Unsupported) + sort.Strings(conversionReport.DroppedOutputs) + return result, conversionReport, nil +} + +type routePath struct { + id string + resourceType string + relationship string + parent string +} + +func routePaths(output recipe.Output) []routePath { + result := []routePath{{id: authoringv2.RootOccurrenceID, resourceType: output.RootResourceType}} + var walk func([]recipe.Traversal, string, string) + walk = func(items []recipe.Traversal, parentID, prefix string) { + for _, item := range items { + alias := item.Alias + if alias == "" { + alias = item.Name + } + id := alias + if prefix != "" { + id = prefix + "__" + alias + } + result = append(result, routePath{id: id, resourceType: item.ToResourceType, relationship: item.Name, parent: parentID}) + walk(item.Traversals, id, id) + } + } + walk(output.Traversals, authoringv2.RootOccurrenceID, "") + return result +} + +func occurrenceForColumn(column string, paths []routePath) (string, string) { + best := authoringv2.RootOccurrenceID + for _, path := range paths { + if path.id != authoringv2.RootOccurrenceID && strings.HasPrefix(column, path.id+"__") && len(path.id) > len(best) { + best = path.id + } + } + if best == authoringv2.RootOccurrenceID { + return best, column + } + return best, strings.TrimPrefix(column, best+"__") +} + +func prunedRoute(output recipe.Output, paths []routePath, used map[string]bool) authoringv2.RouteNode { + byID := map[string]routePath{} + for _, path := range paths { + byID[path.id] = path + } + for id := range used { + for current := byID[id]; current.id != "" && current.parent != ""; current = byID[current.parent] { + used[current.parent] = true + } + } + var build func(string) authoringv2.RouteNode + build = func(id string) authoringv2.RouteNode { + path := byID[id] + node := authoringv2.RouteNode{OccurrenceID: id, ResourceType: path.resourceType, Relationship: path.relationship} + for _, child := range paths { + if child.parent == id && used[child.id] { + node.Children = append(node.Children, build(child.id)) + } + } + sort.Slice(node.Children, func(i, j int) bool { return node.Children[i].OccurrenceID < node.Children[j].OccurrenceID }) + return node + } + return build(authoringv2.RootOccurrenceID) +} + +type columnPresentation struct { + label string + table *authoringv2.TablePresentation + filter *authoringv2.FilterPresentation + chart *authoringv2.ChartPresentation +} + +func presentationFor(view explorer.ConfigView, column string) columnPresentation { + result := columnPresentation{label: column} + for index, binding := range view.Table.Columns { + if binding.Column == column { + order, visible := index, binding.Visible + result.label = first(binding.Label, result.label) + result.table = &authoringv2.TablePresentation{Visible: &visible, Order: &order, Pinned: binding.Pinned, CellRenderer: binding.CellRenderer} + if strings.EqualFold(binding.Label, "File Actions") { + result.table.CellRenderer = "fileActions" + } + } + } + for index, binding := range view.Filters { + if binding.Column == column { + order := index + result.label = first(binding.Label, result.label) + result.filter = &authoringv2.FilterPresentation{Label: binding.Label, Order: &order} + } + } + for index, binding := range view.Charts { + if binding.Column == column { + order := index + result.chart = &authoringv2.ChartPresentation{Type: binding.Type, Title: binding.Title, Order: &order} + } + } + return result +} + +func referencedColumns(config explorer.ConfigV2, view explorer.ConfigView) []string { + seen := map[string]bool{} + add := func(value string) { + if value != "" { + seen[value] = true + } + } + for _, item := range view.Table.Columns { + add(item.Column) + } + for _, item := range view.Filters { + add(item.Column) + } + for _, item := range view.Charts { + add(item.Column) + } + for item := range view.FixedFilters { + add(item) + } + for _, action := range view.Actions { + for _, item := range action.Columns { + add(item) + } + } + for _, bindings := range config.SharedFilters { + for _, item := range bindings { + if item.Output == view.Output { + add(item.Column) + } + } + } + result := make([]string, 0, len(seen)) + for item := range seen { + result = append(result, item) + } + sort.Strings(result) + return result +} + +func inferSource(project, rootResourceType, occurrenceID, leaf, physical string) (authoringv2.ColumnSource, string, error) { + if physical == "project_id" { + return authoringv2.ColumnSource{Kind: authoringv2.SourceProjectID, ProjectionMode: "FIRST"}, "string", nil + } + if marker := "observation_component_values__"; strings.Contains(leaf, marker) { + return authoringv2.ColumnSource{Kind: authoringv2.SourceObservationComponentByCode, Match: leaf[strings.Index(leaf, marker)+len(marker):], FieldPath: "component[]", ProjectionMode: "FIRST"}, "string", nil + } + if marker := "identifier_by_system_"; strings.Contains(leaf, marker) { + encoded := leaf[strings.Index(leaf, marker)+len(marker):] + match, ok := decodeKnownURL(project, encoded) + if !ok { + return authoringv2.ColumnSource{}, "", fmt.Errorf("cannot recover identifier system %q", encoded) + } + return authoringv2.ColumnSource{Kind: authoringv2.SourceIdentifierBySystem, Match: match, FieldPath: "identifier[]", ProjectionMode: "FIRST"}, "string", nil + } + if marker := "extension_by_url_"; strings.Contains(leaf, marker) { + encoded := leaf[strings.Index(leaf, marker)+len(marker):] + match, ok := decodeKnownURL(project, encoded) + if !ok { + return authoringv2.ColumnSource{}, "", fmt.Errorf("cannot recover extension URL %q", encoded) + } + return authoringv2.ColumnSource{Kind: authoringv2.SourceExtensionByURL, Match: match, FieldPath: "extension[]", ProjectionMode: "FIRST"}, "string", nil + } + if rootResourceType == "DocumentReference" && strings.HasPrefix(leaf, "document_reference_") { + name := strings.TrimPrefix(leaf, "document_reference_") + switch name { + case "title": + return field("content[].attachment.title", "string"), "string", nil + case "size": + return field("content[].attachment.size", "integer"), "integer", nil + case "identifier": + return field("identifier[].value", "string"), "string", nil + default: + return authoringv2.ColumnSource{Kind: authoringv2.SourceCodingBySystem, Match: "https://humantumoratlas.org/" + name, FieldPath: "category[].coding[]", ProjectionMode: "FIRST"}, "string", nil + } + } + switch leaf { + case "research_subject_identifier", "specimen_identifier": + return field("identifier[].value", "string"), "string", nil + case "specimen_id": + return field("id", "string"), "string", nil + case "specimen_type_text": + return field("type.text", "string"), "string", nil + case "specimen_processing_method_text": + return field("processing[].method.text", "string"), "string", nil + case "deceasedBoolean": + return field("deceasedBoolean", "boolean"), "boolean", nil + case "code_coding_code": + return field("code.coding[].code", "string"), "string", nil + } + return authoringv2.ColumnSource{}, "", fmt.Errorf("no fixed source mapping for occurrence %q leaf %q", occurrenceID, leaf) +} + +func field(path, _ string) authoringv2.ColumnSource { + return authoringv2.ColumnSource{Kind: authoringv2.SourceField, FieldPath: path, ProjectionMode: "FIRST"} +} + +func decodeKnownURL(project, encoded string) (string, bool) { + projectKey := sanitize(project) + aced := "https___aced_idp_org_" + projectKey + if encoded == aced { + return "https://aced-idp.org/" + project, true + } + if strings.HasPrefix(encoded, aced+"_") { + return "https://aced-idp.org/" + project + "/" + strings.TrimPrefix(encoded, aced+"_"), true + } + htan := "https___humantumoratlas_org_" + if strings.HasPrefix(encoded, htan) { + return "https://humantumoratlas.org/" + strings.TrimPrefix(encoded, htan), true + } + core := "http___hl7_org_fhir_us_core_StructureDefinition_us_core_" + if strings.HasPrefix(encoded, core) { + name := strings.TrimPrefix(encoded, core) + if name == "birthsex" { + return "http://hl7.org/fhir/us/core/StructureDefinition-us-core-birthsex", true + } + return "http://hl7.org/fhir/us/core/StructureDefinition/us-core-" + name, true + } + return "", false +} + +func sanitize(value string) string { + return strings.Map(func(r rune) rune { + if unicode.IsLetter(r) || unicode.IsDigit(r) { + return r + } + return '_' + }, value) +} + +func first(values ...string) string { + for _, value := range values { + if value != "" { + return value + } + } + return "" +} + +func fatalf(format string, values ...any) { fmt.Fprintf(os.Stderr, format+"\n", values...); os.Exit(1) } diff --git a/cmd/generate/fhir_helpers.go.tmpl b/cmd/generate/fhir_helpers.go.tmpl new file mode 100644 index 00000000..479b092b --- /dev/null +++ b/cmd/generate/fhir_helpers.go.tmpl @@ -0,0 +1,141 @@ +// Code generated by cmd/generate/main.go. DO NOT EDIT. +package fhir + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "net/url" + "strings" + "time" + + "github.com/google/uuid" +) + +// FHIRComments handles comments that can be a single JSON string or a JSON array of strings. +type FHIRComments []string + +// UnmarshalJSON unmarshals FHIR comments from a string or array of strings. +func (c *FHIRComments) UnmarshalJSON(data []byte) error { + if len(data) == 0 { + return nil + } + if data[0] == '"' { + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + *c = []string{s} + return nil + } + var arr []string + if err := json.Unmarshal(data, &arr); err != nil { + return err + } + *c = arr + return nil +} + +// MarshalJSON marshals FHIR comments to a single string (if length is 1) or an array of strings. +func (c FHIRComments) MarshalJSON() ([]byte, error) { + if len(c) == 1 { + return json.Marshal(c[0]) + } + return json.Marshal([]string(c)) +} + +// ValidateFhirDateTime checks a string against FHIR date-time rules (YYYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm] or partial date). +func ValidateFhirDateTime(s string) error { + if !strings.Contains(s, "T") { + return validatePartialFhirDate(s, "FHIR date-time") + } + if _, err := time.Parse(time.RFC3339Nano, s); err != nil { + return fmt.Errorf("value '%s' is not a valid FHIR date-time: %w", s, err) + } + return nil +} + +func validatePartialFhirDate(s, typeName string) error { + switch len(s) { + case 4: // YYYY + if _, err := time.Parse("2006", s); err != nil { + return fmt.Errorf("value '%s' is not a valid partial %s (YYYY): %w", s, typeName, err) + } + case 7: // YYYY-MM + if _, err := time.Parse("2006-01", s); err != nil { + return fmt.Errorf("value '%s' is not a valid partial %s (YYYY-MM): %w", s, typeName, err) + } + case 10: // YYYY-MM-DD + if _, err := time.Parse("2006-01-02", s); err != nil { + return fmt.Errorf("value '%s' is not a valid partial %s (YYYY-MM-DD): %w", s, typeName, err) + } + default: + return fmt.Errorf("value '%s' has invalid length for a partial %s", s, typeName) + } + return nil +} + +// ValidateFhirDate checks a string against FHIR date rules (YYYY[-MM[-DD]]). +func ValidateFhirDate(s string) error { + return validatePartialFhirDate(s, "FHIR date") +} + +// ValidateFhirTime checks a string against FHIR time rules (HH:MM:SS[.SSSS]). +func ValidateFhirTime(s string) error { + if len(s) < 8 { + return fmt.Errorf("value '%s' is too short for a FHIR time (minimum 8 characters)", s) + } + + timePart := s + if s[8] == '.' { + timePart = s[:8] + if len(s) == 9 { + return fmt.Errorf("value '%s' is not a valid FHIR time: missing fractional second digits after '.'", s) + } + for i := 9; i < len(s); i++ { + if s[i] < '0' || s[i] > '9' { + return fmt.Errorf("value '%s' is not a valid FHIR time: non-digit characters in fractional seconds", s) + } + } + } else if len(s) != 8 { + return fmt.Errorf("value '%s' has invalid length for FHIR time (expected 8 or 9+ with fractional seconds)", s) + } + + if timePart[2] != ':' || timePart[5] != ':' { + return fmt.Errorf("value '%s' is not a valid FHIR time: missing or misplaced colons", s) + } + + if _, err := time.Parse("15:04:05", timePart); err != nil { + return fmt.Errorf("value '%s' is not a valid FHIR time: invalid time components (%w)", s, err) + } + + return nil +} + +// ValidateFhirURI checks a string against FHIR URI rules (must be an absolute URI). +func ValidateFhirURI(s string) error { + u, err := url.ParseRequestURI(s) + if err != nil { + return fmt.Errorf("value '%s' is not a valid URI: %w", s, err) + } + if !u.IsAbs() { + return fmt.Errorf("value '%s' is not an absolute URI (must include a scheme like 'http://' or 'urn:')", s) + } + return nil +} + +// ValidateFhirUUID checks a string against FHIR UUID rules (RFC 4122). +func ValidateFhirUUID(s string) error { + if _, err := uuid.Parse(s); err != nil { + return fmt.Errorf("value '%s' is not a valid UUID (RFC 4122): %w", s, err) + } + return nil +} + +// ValidateFhirBinary checks that a string is a valid base64-encoded value. +func ValidateFhirBinary(s string) error { + if _, err := base64.StdEncoding.DecodeString(s); err != nil { + return fmt.Errorf("value is not a valid Base64 encoded string: %w", err) + } + return nil +} diff --git a/cmd/generate/helpers.go b/cmd/generate/helpers.go new file mode 100644 index 00000000..34386fa6 --- /dev/null +++ b/cmd/generate/helpers.go @@ -0,0 +1,10 @@ +package main + +import _ "embed" + +//go:embed fhir_helpers.go.tmpl +var fhirHelpersSource string + +func generateFHIRHelpers(path string) error { + return writeGeneratedGo(path, fhirHelpersSource) +} diff --git a/cmd/generate/main.go b/cmd/generate/main.go index e8b3b700..7ee19e7a 100644 --- a/cmd/generate/main.go +++ b/cmd/generate/main.go @@ -42,31 +42,37 @@ func main() { os.Exit(1) } - // 1. Generate model.go + // 1. Generate package support used by the schema-derived files. + if err := generateFHIRHelpers(filepath.Join(*structsDir, "helpers.go")); err != nil { + fmt.Fprintf(os.Stderr, "Error generating helpers.go: %v\n", err) + os.Exit(1) + } + + // 2. Generate model.go if err := generateModel(&schema, filepath.Join(*structsDir, "model.go")); err != nil { fmt.Fprintf(os.Stderr, "Error generating model.go: %v\n", err) os.Exit(1) } - // 2. Generate validate.go + // 3. Generate validate.go if err := generateValidate(&schema, filepath.Join(*structsDir, "validate.go")); err != nil { fmt.Fprintf(os.Stderr, "Error generating validate.go: %v\n", err) os.Exit(1) } - // 3. Generate extract.go + // 4. Generate extract.go if err := generateExtract(&schema, filepath.Join(*structsDir, "extract.go")); err != nil { fmt.Fprintf(os.Stderr, "Error generating extract.go: %v\n", err) os.Exit(1) } - // 4. Generate the concrete-resource registry and GraphQL markers. + // 5. Generate the concrete-resource registry and GraphQL markers. if err := generateFHIRResources(&schema, filepath.Join(*structsDir, "resources.go"), filepath.Join(*structsDir, "graphql.go")); err != nil { fmt.Fprintf(os.Stderr, "Error generating resource registry: %v\n", err) os.Exit(1) } - // 5. Generate internal compiler schema metadata + // 6. Generate internal compiler schema metadata if err := generateFHIRSchema(&schema, *metadataOut); err != nil { fmt.Fprintf(os.Stderr, "Error generating generated/fhirschema/generated.go: %v\n", err) os.Exit(1) diff --git a/cmd/generate/model_test.go b/cmd/generate/model_test.go index ca741e2b..1ec8bc1c 100644 --- a/cmd/generate/model_test.go +++ b/cmd/generate/model_test.go @@ -17,6 +17,7 @@ func TestFHIRStructGenerationMatchesCheckedInArtifacts(t *testing.T) { {name: "model.go", generate: generateModel}, {name: "validate.go", generate: generateValidate}, {name: "extract.go", generate: generateExtract}, + {name: "helpers.go", generate: func(_ *Schema, path string) error { return generateFHIRHelpers(path) }}, } { t.Run(artifact.name, func(t *testing.T) { generatedPath := filepath.Join(t.TempDir(), artifact.name) diff --git a/cmd/gqlgenfix/main.go b/cmd/gqlgenfix/main.go index 918ac414..5926a90e 100644 --- a/cmd/gqlgenfix/main.go +++ b/cmd/gqlgenfix/main.go @@ -18,14 +18,24 @@ func main() { fail("read %s: %v", path, err) } - source := string(contents) + source, err := fixGeneratedSource(string(contents)) + if err != nil { + fail("fix generated source: %v", err) + } + if err := os.WriteFile(path, []byte(source), 0o644); err != nil { + fail("write %s: %v", path, err) + } +} + +func fixGeneratedSource(source string) (string, error) { + var err error source, err = replaceInFunction(source, "func (ec *executionContext) unmarshalNJSON2", "return &res, graphql.ErrorOnPath(ctx, err)", "return res, graphql.ErrorOnPath(ctx, err)", ) if err != nil { - fail("fix JSON unmarshal return: %v", err) + return "", fmt.Errorf("fix JSON unmarshal return: %w", err) } source, err = replaceInFunctionIfPresent(source, "func (ec *executionContext) unmarshalNFhirAggregateInput", @@ -33,12 +43,37 @@ func main() { "return &res, graphql.ErrorOnPath(ctx, err)", ) if err != nil { - fail("fix aggregate input unmarshal return: %v", err) + return "", fmt.Errorf("fix aggregate input unmarshal return: %w", err) } - if err := os.WriteFile(path, []byte(source), 0o644); err != nil { - fail("write %s: %v", path, err) + if !strings.Contains(source, "func MarshalJSON(") { + const imports = "\t\"errors\"\n" + if !strings.Contains(source, imports) { + return "", fmt.Errorf("generated import anchor not found") + } + source = strings.Replace(source, imports, imports+"\t\"io\"\n", 1) + source += jsonScalarHelpers } + return source, nil +} + +const jsonScalarHelpers = ` + +// JSON scalar support is appended by cmd/gqlgenfix because gqlgen does not +// emit helpers for the encoding/json.RawMessage model mapping. +func MarshalJSON(v json.RawMessage) graphql.Marshaler { + return graphql.WriterFunc(func(w io.Writer) { + _, _ = w.Write(v) + }) +} + +func (ec *executionContext) unmarshalInputJSON(ctx context.Context, v any) (json.RawMessage, error) { + return json.Marshal(v) +} + +func (ec *executionContext) _JSON(ctx context.Context, sel ast.SelectionSet, v json.RawMessage) graphql.Marshaler { + return MarshalJSON(v) } +` func replaceInFunctionIfPresent(contents, signature, old, replacement string) (string, error) { if !strings.Contains(contents, signature) { diff --git a/cmd/gqlgenfix/main_test.go b/cmd/gqlgenfix/main_test.go new file mode 100644 index 00000000..46b9260e --- /dev/null +++ b/cmd/gqlgenfix/main_test.go @@ -0,0 +1,40 @@ +package main + +import ( + "strings" + "testing" +) + +func TestFixGeneratedSourceAddsJSONScalarSupportIdempotently(t *testing.T) { + source := `package executor + +import ( + "context" + "encoding/json" + "errors" +) + +func (ec *executionContext) unmarshalNJSON2(ctx context.Context, v any) (json.RawMessage, error) { + var res json.RawMessage + var err error + return &res, graphql.ErrorOnPath(ctx, err) +} +` + got, err := fixGeneratedSource(source) + if err != nil { + t.Fatal(err) + } + if !strings.Contains(got, `"io"`) || !strings.Contains(got, "func MarshalJSON(") { + t.Fatalf("JSON scalar support was not appended:\n%s", got) + } + if strings.Contains(got, "return &res, graphql.ErrorOnPath") { + t.Fatal("invalid JSON pointer return was not fixed") + } + again, err := fixGeneratedSource(got) + if err != nil { + t.Fatal(err) + } + if again != got { + t.Fatal("post-processing is not idempotent") + } +} diff --git a/docs/CODE_GENERATION.md b/docs/CODE_GENERATION.md index 0836ecd9..79290214 100644 --- a/docs/CODE_GENERATION.md +++ b/docs/CODE_GENERATION.md @@ -6,7 +6,13 @@ under `generated/` is produced or managed by a generator; resolver packages live under `internal/api/graphql`. Change an input and regenerate instead of patching executor, model, schema, or FHIR output by hand. -The two gqlgen configurations live at the repository root: +The generated tree is reproducible from an empty directory. In particular, +`generated/fhir/helpers.go` is emitted from +`cmd/generate/fhir_helpers.go.tmpl`, and `cmd/gqlgenfix` appends Loom's JSON +scalar support to gqlgen's generated executor. There are no handwritten source +files under `generated/`. + +The gqlgen configuration lives at the repository root: - `gqlgen.yml` builds the graph and FHIR dataframe API. @@ -22,6 +28,7 @@ under `internal`: | `generated/graphql/graph/executor/` | `executor` | Primary gqlgen executable schema. | | `generated/graphql/graph/model/` | `model` | Shared GraphQL input/output models. | | `internal/api/graphql/graph/resolver/` | `resolver` | Primary gqlgen resolver bindings. | +| `generated/loomapi/` | `loomapi` | OpenAPI models, Fiber v3 adapters, strict server interfaces, registrar, and embedded contract. | The generated executors expose gqlgen's resolver interfaces. gqlgen requires resolver receivers and preserved resolver implementations to share one Go @@ -50,7 +57,7 @@ The handwritten GraphQL inputs and runtime wiring are deliberately separate: | --- | --- | --- | | `schemas/graph-fhir.json` and `cmd/generate/` | `make generate-fhir` | `generated/fhir/*.go`, `generated/fhirschema/generated.go`, and `generated/graphql/graph/schema/fhir_schema.graphqls` | | `internal/api/graphql/graph/schema/schema.graphqls`, generated FHIR SDL, and `gqlgen.yml` | `make generate-graphql` | Primary executor, models, and resolver bindings under `generated/graphql/graph/` and `internal/api/graphql/graph/resolver/` | -| `schemas/explorer-authoring-v2/openapi.yaml` and its oapi-codegen config | `make generate-explorer-v2` | Explorer V2 wire models and Fiber v3 strict-server interfaces under `generated/explorerv2/` | +| [`openapi/openapi.yaml`](../openapi/openapi.yaml) and [`openapi/oapi-codegen.yaml`](../openapi/oapi-codegen.yaml) | `make generate-openapi` | All Loom HTTP wire models, Fiber v3 strict-server interfaces, registrar, and embedded specification under `generated/loomapi/` | `generated/graphql/graph/executor/fhir_schema.generated.go` and `generated/graphql/graph/executor/root_.generated.go` are @@ -58,6 +65,11 @@ large because gqlgen emits executable dispatch code for every selectable field in the typed FHIR schema. They are generated runtime code, not duplicate data models or a second query engine. +`generated/graphql/graph/executor/schema.generated.go` is post-processed by +`cmd/gqlgenfix` to correct pinned-gqlgen return types and add the JSON scalar +glue required by the `encoding/json.RawMessage` model mapping. That +post-processing is part of `make generate-graphql`, not a manual edit. + `internal/api/graphql/graph/resolver/fhir_schema.resolvers.go` contains generated field bindings that call shared helpers. It lets all JSON FHIR property names remain selectable without hand-writing one resolver per field. @@ -89,3 +101,7 @@ git diff --check To understand an executor, model, schema, or FHIR result, start at its input above. Regeneration overwrites those artifacts; only the resolver adapter bodies described above are preserved for handwritten transport mapping. + +The OpenAPI source is documented beside the spec in +[`openapi/README.md`](../openapi/README.md). Do not register production Fiber +routes outside the generated registrar. diff --git a/docs/DATAFRAMER_RECIPES.md b/docs/DATAFRAMER_RECIPES.md index 99295083..fb964f06 100644 --- a/docs/DATAFRAMER_RECIPES.md +++ b/docs/DATAFRAMER_RECIPES.md @@ -18,7 +18,7 @@ names, or SQL. This document describes the native recipe language used by repository, ETL, and developer workflows. It is not the browser Builder contract. The Builder -sends the intent-only V1 document described in +sends the intent-only V2 document described in [`EXPLORER_AUTHORING.md`](EXPLORER_AUTHORING.md); Loom lowers that document to a native recipe and then runs the recipe compiler described here. Do not make frontend code construct or repair recipe ASTs. @@ -28,7 +28,7 @@ The deployed default is ordinary JSON loaded from For direct recipe authoring, do not write a recipe from memory: discover the loaded graph, prototype the shape through `runFhirDataframe`, and then promote -the proven shape into a persistent recipe. For Builder authoring, use the V1 +the proven shape into a persistent recipe. For Builder authoring, use the V2 REST contract instead of this native recipe format. ## Recommended workflow @@ -156,12 +156,11 @@ must deliberately produce multiple rows. ## Step 2: discover the graph that is actually loaded -Use the REST V1 authoring compiler and its server-owned catalog discovery. It +Use the REST V2 authoring compiler and its server-owned catalog discovery. It reports populated fields, route candidates, and valid relationships for the selected generation. Do not infer relationship labels from FHIR property names or manufacture browser selector IDs. See -[`EXPLORER_AUTHORING.md`](EXPLORER_AUTHORING.md). The V2 migration guide is -historical and retained only for compatibility context. +[`EXPLORER_AUTHORING.md`](EXPLORER_AUTHORING.md). For a second hop, select the first-hop target in the authoring request. For example: diff --git a/docs/DEVELOPER_ARCHITECTURE.md b/docs/DEVELOPER_ARCHITECTURE.md index f54f6ecd..b8b8dc86 100644 --- a/docs/DEVELOPER_ARCHITECTURE.md +++ b/docs/DEVELOPER_ARCHITECTURE.md @@ -12,6 +12,7 @@ The top-level directories have distinct ownership: | Path | Ownership | | --- | --- | +| `openapi/` | Canonical Loom HTTP contract and oapi-codegen configuration. | | `schemas/` | Source schemas edited by developers. | | `gqlgen.yml` | GraphQL generator configuration. | | `generated/` | Checked-in generated output; never server business logic. | @@ -32,9 +33,9 @@ they do not live in `generated/`. The Builder integration contract is documented in [`EXPLORER_AUTHORING.md`](EXPLORER_AUTHORING.md). The Builder uses the REST -Explorer lifecycle and submits V1 intent; GraphQL does not expose Explorer -lifecycle or authoring types. The old V2 packet guide is retained for -compatibility and ETL migration context, not as the current Builder contract. +Explorer lifecycle and submits V2 intent; GraphQL does not expose Explorer +lifecycle or authoring types. Every HTTP method and path is defined in the +canonical [`openapi/openapi.yaml`](../openapi/openapi.yaml) contract. Ownership map: `dataset` owns immutable FHIR generation lifecycle; `catalog` owns persistence-neutral observed facts; `catalog/arango` owns catalog @@ -59,11 +60,12 @@ runner; `dataframe/publication/{arango,clickhouse}` own storage adapters; and - `discover-populated-references` and `discover-populated-fields` for catalog diagnostics. -`cmd/arango-fhir-server` owns the HTTP process. It mounts health, GraphQL, -developer GraphQL tools, and the primary project/resourceType upload endpoint. -Complete immutable generations remain an explicit CLI/load workflow. +`cmd/arango-fhir-server` owns the HTTP process. Generated OpenAPI registration +mounts health, ingestion, snapshot/release, recipe execution, GraphQL, and +Explorer operations; handwritten strict-interface implementations remain under +`internal/server`. -The GraphQL dataframe mutation is the live compiler transport. Explorer V1 +The GraphQL dataframe mutation is the live compiler transport. Explorer V2 authoring adds an intent-to-native-recipe lowering phase, then calls the same recipe resolver/compiler and AQL renderer. Do not add a second query compiler or hand-maintained AQL path behind another endpoint. See @@ -262,6 +264,10 @@ under `internal/`. See [`CODE_GENERATION.md`](CODE_GENERATION.md) for the full source/output map and package boundaries. +Run `make generate-openapi` after changing the canonical HTTP contract or its +generator configuration under `openapi/`. Do not hand-edit +`generated/loomapi/api.gen.go`. + The normal verification targets are: ```bash diff --git a/docs/EXPLORER_AUTHORING.md b/docs/EXPLORER_AUTHORING.md index 015fc080..2daf61c7 100644 --- a/docs/EXPLORER_AUTHORING.md +++ b/docs/EXPLORER_AUTHORING.md @@ -129,31 +129,6 @@ Compile and preview may persist and execute immutable receipts, but neither operation changes the active Explorer revision. Publication is the only Builder operation that materializes outputs and switches the active revision. -## Future work TODO: advanced catalog-driven column addition - -The MVP Builder shows configured V2 columns and ordinary catalog field -candidates in one list. A selected catalog field becomes a durable typed -`source.kind: field` column; candidate identity is not retained as a second -authoring model. Existing field columns are reconciled to the list by their -single authoritative `fieldPath`, while typed project, identifier, extension, -coding, and observation sources remain ordinary configured columns. - -Future work is limited to candidate families that need more intent than one -field path, plus new route/table construction. That work must: - -- have Loom return a complete typed V2 column for identifier systems, - extension URLs, coding systems, and observation component codes; -- prove that every advertised candidate compiles under the snapshot that - advertised it; -- restore route and blank-table creation only when at least one valid column - can be added in the same workflow; and -- cover add through compile, preview, export, reload, and publish without - changing configured-column persistence. - -Do not introduce composite frontend matching such as -`occurrenceId + source.kind + source.fieldPath + source.match`. The resulting -typed V2 column remains the durable authoring state. - ## Cleanup Receipts referenced by immutable revisions are retained. Loom exposes receipt diff --git a/docs/EXPLORER_RECIPE_BOUNDARY.md b/docs/EXPLORER_RECIPE_BOUNDARY.md deleted file mode 100644 index 19379fd6..00000000 --- a/docs/EXPLORER_RECIPE_BOUNDARY.md +++ /dev/null @@ -1,546 +0,0 @@ -# The Explorer recipe boundary - -This document explains why the Explorer Builder sends authoring intent instead -of constructing Loom's complete native recipe. The short version is: - -> The frontend chooses what the user wants. Loom decides how that request is -> interpreted, authorized, lowered, optimized, and executed. - -The frontend could generate a syntactically valid recipe for simple cases. The -problem is that a Loom recipe is not merely a JSON formatting template. It is a -storage-neutral compiler input whose fields expand into schema rules, graph -traversal rules, authorization predicates, dynamic projections, physical IR, -and AQL. - -For the request and endpoint contract, see -[Explorer authoring](EXPLORER_AUTHORING.md). For the complete compilation -sequence, see [Explorer compilation architecture](EXPLORER_COMPILATION_ARCHITECTURE.md). - -## What the frontend owns - -The V1 Builder owns authoring intent: - -- which output the user is creating; -- which catalog node is the base and row node; -- which ordered catalog edges form the route; -- which opaque candidates are selected at which occurrences; and -- labels, ordering, visibility, filters, and charts for server-owned emissions. - -For example: - -```json -{ - "apiVersion": "loom.calypr.org/explorer-authoring/v1", - "kind": "ExplorerAuthoringBundle", - "project": "project-a", - "explorerId": "patient-explorer", - "document": { - "kind": "ExplorerBuilderDocument", - "output": { "id": "patient" }, - "baseNodeId": "node_patient", - "rowNodeId": "node_condition", - "routeEdgeIds": ["edge_patient_condition"], - "routeOccurrences": [ - { - "id": "condition_1", - "index": 0, - "nodeId": "node_condition", - "incomingEdgeId": "edge_patient_condition" - } - ], - "candidateIds": ["candidate_condition_status"], - "candidateOccurrences": [ - { - "candidateId": "candidate_condition_status", - "occurrenceId": "condition_1" - } - ] - } -} -``` - -This is durable authoring intent. It does not contain `expr`, `select`, -aliases, generated column names, physical collections, AQL, or authorization -paths. - -## What Loom owns - -Loom owns the translation from that intent to executable behavior: - -```text -intent document - -> authoritative catalog and snapshot resolution - -> route and candidate resolution - -> native recipe construction - -> semantic and schema validation - -> physical graph plan - -> authorization and generation scope - -> optimization - -> parameterized AQL -``` - -Some values below are technically discoverable by a frontend. They are still -server-owned because they depend on authoritative state, security context, or -compiler implementation rules. - -## 1. Selector paths and array semantics - -### What the frontend sees - -The V1 catalog gives the frontend an opaque candidate and useful display -metadata: - -```json -{ - "candidateId": "candidate_observation_code_display", - "nodeId": "node_observation", - "fieldRef": "Observation.code.coding.display", - "logicalType": "string", - "filterable": true, - "chartable": true -} -``` - -The catalog intentionally does not expose the internal recipe selector path. - -### What the native recipe needs - -The server may lower that candidate into: - -```json -{ - "name": "c_", - "fieldRef": "Observation.code.coding.display", - "expr": { - "select": "root.code.coding[].display" - } -} -``` - -The `[]` is not decoration. It says that `coding` is repeated and that the -compiler must iterate it. - -Depending on value mode and cardinality, Loom may need behavior equivalent to: - -```aql -FOR coding IN (root.code.coding ? root.code.coding : []) - FILTER coding.display != null - RETURN coding.display -``` - -or: - -```aql -FIRST( - FOR coding IN (root.code.coding ? root.code.coding : []) - FILTER coding.display != null - RETURN coding.display -) -``` - -The compiler determines whether a selector is scalar or repeated, whether -arrays need flattening, how nulls are handled, and whether a direct scalar -access or a generated nested loop is safe. That behavior lives in selector -parsing, schema metadata, semantic typing, and AQL rendering. - -A frontend could copy those rules, but it would then be implementing part of -the Loom compiler. - -## 2. Field references are not complete execution selectors - -`fieldRef` is provenance and catalog identity. It is not always enough to -construct the executable selector. - -For example, a FHIR choice or nested repeated field may have distinctions such -as: - -```text -Observation.value[x] -Observation.valueString -Observation.valueQuantity.value -DocumentReference.content[].attachment.extension[].url -``` - -The generated schema decides which paths exist, their logical type, whether -they are repeated, and which selector form the recipe compiler accepts. - -For a traversal field, the selector also needs the correct lexical context: - -```json -{ "select": "route_0.code.text" } -``` - -The meaning of `route_0` comes from the server-generated traversal scope. A -frontend-generated selector can be syntactically plausible while referring to -an alias that does not exist at that location. - -## 3. Routes, traversal targets, and aliases - -### User intent - -The user selects a logical route: - -```text -Patient --subject_Patient--> Condition -``` - -The V1 document represents that with node IDs, edge IDs, and occurrences. - -### Native recipe - -Loom may construct: - -```json -{ - "traversals": [ - { - "name": "subject_Patient", - "alias": "route_0", - "toResourceType": "Condition", - "matchMode": "OPTIONAL", - "fields": [ - { - "name": "c_", - "fieldRef": "Condition.status", - "expr": { "select": "route_0.status" } - } - ] - } - ] -} -``` - -Some of those values can be derived from the catalog. The server still has to -verify that: - -- the edge exists in the current snapshot; -- the edge connects to the current route node; -- the next edge begins at the previous edge's target; -- the occurrence index matches the ordered route; -- the terminal node equals `rowNodeId`; and -- the route depth is supported. - -If the route is: - -```text -Patient -> Patient -> Condition -``` - -then `Patient.id` may be valid at two different occurrences. A resource type -alone cannot tell Loom which one the candidate belongs to. V1 therefore has -explicit route occurrences and candidate-occurrence references. - -## 4. Logical routes versus physical graph traversal - -The authoring catalog describes logical relationships. Loom stores graph -relationships in `fhir_edge` with physical endpoint fields and indexed route -shapes. - -The recipe may say: - -```text -traverse subject_Patient to Condition -``` - -The physical compiler must decide how to implement that using the actual edge -layout: - -```text -logical relationship - -> physical _from/_to endpoint choice - -> edge label predicate - -> target resource type predicate - -> correct graph index route - -> target resource lookup -``` - -The frontend should not know the physical endpoint orientation, index names, -or storage-specific route proof. That is why the generated native recipe does -not need to carry a browser-supplied physical direction. - -## 5. Aliases are lexical compiler scope - -Aliases determine which expressions are legal. - -This is valid: - -```json -{ - "alias": "condition", - "toResourceType": "Condition", - "fields": [ - { "expr": { "select": "condition.code.text" } } - ] -} -``` - -This is invalid if `specimen` is not in the current scope: - -```json -{ - "alias": "condition", - "toResourceType": "Condition", - "fields": [ - { "expr": { "select": "specimen.code.text" } } - ] -} -``` - -The semantic compiler tracks aliases, resource types, selector paths, and -expression types together. Server-generated aliases such as `route_0` avoid -making the frontend responsible for maintaining that lexical compiler scope. - -## 6. Generated fields, emissions, and public columns - -One selection passes through several identities: - -```text -(candidateId, occurrenceId) - -> emission ID - -> native recipe field name - -> public output column -``` - -For example: - -```text -candidateId = candidate_patient_id -occurrence = base -emissionId = em_ -fieldName = c_ -publicName = c_ -``` - -These identities connect the authoring document to presentation, compiled -configuration, output schema, persisted revisions, and materialized columns. - -The frontend could copy the hashing algorithms, but then those internal -algorithms become a public frontend dependency. A server change to identity -generation would invalidate browser-authored documents. - -That is why V1 presentation looks like: - -```json -{ - "presentation": { - "em_": { - "label": "Patient ID", - "visible": true - } - } -} -``` - -It does not look like: - -```json -{ - "presentation": { - "column": "c_abc123" - } -} -``` - -The frontend presents an emission. Loom decides which concrete column that -emission becomes. - -## 7. Authorization is runtime context, not recipe intent - -The frontend can provide a project identity: - -```json -{ "project": "project-a" } -``` - -It should not provide authorization paths. Loom obtains those from the -authenticated principal and request scope, then binds them during compilation. - -The physical plan requires scope checks for every resource and relationship. -Conceptually, the generated AQL includes logic like: - -```aql -FOR root IN @@patient_collection - FILTER root.project == @project - FILTER root.dataset_generation == @dataset_generation - LET root_scope_allowed = AUTH_RESOURCE_PATH_ALLOWED( - root.auth_resource_path, - @auth_resource_paths, - @auth_resource_paths_unrestricted - ) - FILTER root_scope_allowed -``` - -Traversed edges and target resources receive equivalent checks. A browser -recipe that omits them may still look semantically valid while being unsafe to -execute. A browser that supplies them cannot be trusted to widen or alter the -scope. - -## 8. Generation and catalog snapshots go stale - -Consider: - -```text -10:00 Builder fetches catalog for generation G1 -10:02 ETL activates generation G2 -10:03 Builder submits candidate IDs discovered from G1 -``` - -The candidate IDs may still be well-formed. They may even look valid. But they -can now resolve to a different schema, edge set, or authorization scope. - -The V1 snapshot token binds the catalog to project, generation, authorization -scope, nodes, edges, candidates, and completeness. Loom re-reads and validates -that snapshot during compilation. The correct result for stale state is a -typed conflict such as: - -```text -409 STALE_CATALOG_SNAPSHOT -``` - -A frontend cannot guarantee consistency between catalog discovery and later -compile, preview, or publish. - -## 9. Dynamic schema depends on actual data - -Some native recipes discover columns from project data. For example, a -DocumentReference extension family may produce keys such as: - -```text -source_path -sha256 -sample_id -``` - -A native dynamic-column declaration may look conceptually like: - -```json -{ - "name": "attachment_extensions", - "source": { - "select": "root.content[].attachment.extension[]" - }, - "key": { - "call": "last_segment", - "args": [{ "select": "item.url" }] - }, - "value": { - "select": "item.valueString" - }, - "maxColumns": 128 -} -``` - -The compiler must then: - -1. discover the actual keys; -2. freeze the allowed key set; -3. determine logical value types; -4. enforce the maximum column bound; -5. create deterministic physical projections; -6. create keyed-map lookups and bind variables; and -7. validate runtime key/type drift. - -The result depends on: - -```text -project + generation + data + authorization scope -``` - -A frontend can display a current key list, but it cannot make that list -authoritative for a later publication. - -## 10. Recipe validation is semantic - -Recipe validation checks more than JSON shape. - -An expression must have exactly one operator: - -```json -{ "select": "root.id" } -``` - -is valid, while this is invalid: - -```json -{ - "select": "root.id", - "literal": "also-present" -} -``` - -Other semantic checks include: - -- selectors must resolve against the resource type in scope; -- aliases cannot shadow existing lexical bindings; -- traversal match modes must be supported; -- traversal depth must remain within compiler limits; -- dynamic sources must have the required array cardinality; -- dynamic item selectors must be valid scalar paths; -- output and field names must be stable recipe identifiers; and -- physical plans must contain required project, generation, and auth scope - operations before AQL rendering. - -The frontend could duplicate these rules, but it would then be maintaining a -second implementation of Loom's compiler semantics. - -## 11. The physical plan is where storage and security meet - -The native recipe may only say: - -```text -root = Patient -traverse subject_Patient to Condition -select Condition.code.text -``` - -The physical plan expands that into operations such as: - -```text -scan Patient collection -filter project -filter dataset generation -check root authorization -traverse fhir_edge -filter edge project/generation -check edge authorization -load Condition target -check target authorization -extract payload.code.text -construct row identity -project public columns -``` - -Only after that does the canonical AQL renderer produce parameterized AQL and -bind variables. - -The frontend should not know collection names, edge indexes, bind-variable -names, payload extraction rules, scope-check ordering, row-identity rules, or -which physical optimizations are safe. - -## Why this is a server boundary - -The first authoring stage is not required because every individual value is -unknowable to a browser. It is required because the browser should not own or -be trusted with: - -- authoritative catalog interpretation; -- snapshot and generation consistency; -- authorization scope; -- schema and cardinality semantics; -- generated executable identities; -- dynamic data-dependent schema; -- physical storage behavior; or -- compiler validation and optimization rules. - -If the frontend generated the complete native recipe, it would become a second -Loom compiler. Loom would still need to validate and recompile that recipe for -authorization, snapshots, schema, and physical correctness. - -The V1 boundary keeps the responsibilities clear: - -```text -Frontend: user intent and presentation choices -Loom: catalog resolution, recipe construction, compilation, authorization, - physical planning, AQL, preview, and materialization -``` - diff --git a/docs/FRONTEND_DATAFRAME_FACET_PERFORMANCE_PLAN.md b/docs/FRONTEND_DATAFRAME_FACET_PERFORMANCE_PLAN.md deleted file mode 100644 index 76278f5a..00000000 --- a/docs/FRONTEND_DATAFRAME_FACET_PERFORMANCE_PLAN.md +++ /dev/null @@ -1,467 +0,0 @@ -# Frontend Dataframe Facet Performance Plan - -## Purpose - -Use this document as the implementation plan in the frontend Codex workspace. -It is intentionally framework-neutral: the implementing agent should first -locate the existing Explorer table hooks, GraphQL documents, generated types, -and request-cache library, then map the steps below onto those components. - -The goal is to make the Explorer table feel fast without changing Loom's -GraphQL schema or inventing another endpoint. - -## Current problem and measured baseline - -The current table render eagerly requests 156 aliased `dataframeAggregate` -fields, including distributions for identifiers and reference-like columns. -It also sends dataset metadata, table rows, scalar counts, and facet -distributions as separate GraphQL operations. - -Measurements from the local Loom deployment on 2026-08-18: - -- The 156-facet operation takes approximately 1.05-1.22 seconds. -- It is already one ClickHouse statement, not 156 statements. -- Federation/project metadata takes approximately 653-669 ms. -- Aggregate planning, ClickHouse execution, and result decoding take - approximately 374-559 ms. -- A separate one-job count takes approximately 666 ms end-to-end even when - ClickHouse takes only 5 ms, demonstrating that repeated metadata resolution - is a major cost. -- Dataset, count, facet, and row requests have different request IDs, so Loom's - request-scoped project/federation cache cannot be shared across them. - -The 156 aliases are not themselves the bug. They are GraphQL response names. -The remaining problems are eager overfetching, unbounded legacy facet results, -and multiple HTTP operations for one logical table render. - -## Desired user experience - -1. Initial navigation renders the table, count, and immediately visible filter - controls from one GraphQL operation. -2. The page does not calculate distributions for every dataset column. -3. A facet is loaded only when it is visible, explicitly configured for eager - display, or opened by the user. -4. Facet menus return a bounded number of terms and clearly represent missing - and truncated results. -5. Reopening an unchanged facet is instant from the frontend cache. -6. Filter, sort, pagination, and publication changes cannot display stale - results from an older request. - -## Frozen backend contract - -Do not require Loom schema or route changes. Continue using: - -- `POST /loom/graphql/graph` (or the frontend's configured Loom GraphQL base). -- `dataframeRows(input: DataframeRowsInput!)`. -- `dataframeAggregate(input: DataframeAggregateInput!)` where a distinct - scalar count is genuinely required. -- `dataframeAggregations(input: DataframeAggregationsInput!)` for bounded - `TERMS` facets. - -The exact selector remains: - -```graphql -input DataframeSelectorInput { - recipe: String! - translationVersion: String! - output: String! -} -``` - -Never send a physical table name or infer a selector from a display label. - -## Target request architecture - -### Initial table render - -Replace separate dataset, rows, filtered-count, unfiltered-count, and eager -facet operations with one operation wherever their selector and filter state -are the same. - -Use this representative shape and adapt field names to the frontend's query -generator: - -```graphql -query ExplorerTableRender( - $rows: DataframeRowsInput! - $facets: DataframeAggregationsInput! -) { - table: dataframeRows(input: $rows) { - materialization { - id - name - revision - rowCount - availability - completeness - columns { - name - logicalType - nullable - repeated - filterable - sortable - aggregatable - } - } - columns - rows - totalCount - pageInfo { - hasNextPage - endCursor - } - } - - facets: dataframeAggregations(input: $facets) { - materialization { - id - revision - } - aggregations - } -} -``` - -The rows and facets variables must use the same selector and current filter -snapshot. Do not make the dataset metadata request separately: the -`dataframeRows.materialization` object already provides the column and -revision metadata needed by the table. - -Use `dataframeRows.totalCount` as the filtered row count. Do not issue another -ungrouped `COUNT` for the same filters. Add an aliased `dataframeAggregate` -field to this same operation only when the UI displays a genuinely different -count scope that cannot be derived from `totalCount` or materialization -metadata. - -If there are no eager facets, use a rows-only version of the document. Do not -send an empty `dataframeAggregations.specs` list because Loom rejects it. - -### Bounded facet specifications - -Represent facet menus with `TERMS`, not legacy unbounded `COUNT + groupBy`: - -```json -{ - "selector": { - "recipe": "calypr-meta-default", - "translationVersion": "...", - "output": "Patient" - }, - "filters": [], - "specs": [ - { - "name": "facet__project_id", - "kind": "TERMS", - "column": "project_id", - "size": 50, - "excludeSelfFilter": true - } - ] -} -``` - -Rules: - -- Default `size` to 50; make it configurable per filter and cap normal UI use - at 100. -- Use stable, collision-free spec names derived from the public column name. -- Use `excludeSelfFilter: true` for a column's own filter menu so selected - values remain visible while other active filters still constrain counts. -- Consume `missingCount` and `truncated` from the returned aggregation JSON. -- When `truncated` is true, label the list as partial and offer text entry or - another refinement mechanism. Do not imply that every distinct value was - returned. -- A `dataframeAggregations` field supports at most 50 specifications. Normal - initial rendering should remain well below that. If a deliberate bulk load - exceeds 50, split it deterministically into multiple aliased - `dataframeAggregations` fields in the same GraphQL operation. - -## Facet demand policy - -Do not derive eager facets from every column where `aggregatable == true`. -That flag means the operation is legal, not that it is useful at page load. - -Define one explicit frontend policy function, for example: - -```text -facetMode(column, explorerConfig) -> eager | lazy | none -``` - -Recommended policy: - -- `eager`: explicitly configured filter controls that are visible without user - interaction, such as project, status, category, or small enumerations. -- `lazy`: useful categorical/date/number filters whose menus are collapsed at - initial render. -- `none`: row identifiers, subject/patient identifiers, opaque identifiers, - free text, URLs, resource references, attachment paths, and other fields - whose distributions are high-cardinality or not meaningful as a menu. - -Prefer explicit Explorer configuration over name heuristics. A conservative -name heuristic may be used only as a fallback and must be overridable. In -particular, do not eagerly facet columns ending in `_id`, identifier values, -or `*_reference` merely because the backend says they are aggregatable. - -Set an initial safety budget, such as at most 12 eager facets. Additional -facets become lazy even if configured eager, with a development warning so a -configuration author can correct the layout. - -## Lazy facet loading - -When a facet control opens or becomes visible: - -1. Capture one immutable snapshot of selector and filters. -2. Remove only that facet's own predicates when `excludeSelfFilter` semantics - are desired; retain every other predicate. -3. Submit a bounded `dataframeAggregations` request containing that facet and - any other newly requested facets collected during a short batching window - (approximately one animation frame or 10-25 ms). -4. Deduplicate identical in-flight requests. -5. Cancel obsolete network requests with `AbortController` or the equivalent - supported by the existing GraphQL client. -6. Apply a response only if its selector, filter signature, and - materialization revision still match current table state. - -Do not fire one request per facet when several controls mount together. Batch -newly demanded facets into one `dataframeAggregations` field, up to 50 specs. - -## Frontend cache model - -Cache each facet independently even when several arrive in one response. - -The cache key must include: - -```text -selector recipe/version/output -+ materialization revision -+ public column name -+ aggregation kind and size -+ canonical effective filters after self-filter exclusion -``` - -Canonical filter rules: - -- Trim column and operation names; uppercase operations. -- Sort the final filter list because filters are combined with `AND`. -- Sort members of `IN`, `NOT_IN`, and `ARRAY_OVERLAPS` by stable JSON because - member order is not semantic. -- Preserve duplicate predicates. -- Use stable JSON encoding for values. - -The materialization revision makes published data immutable for the key. When -the revision changes, old entries may remain in the cache but must no longer -be selected. Apply a bounded LRU/TTL policy to prevent unlimited growth. - -Suggested freshness behavior: - -- Fresh for the current revision during the browser session. -- Revalidate after a configurable interval if the existing client library - requires it. -- Never reuse across different principals unless the application's existing - cache is already scoped to the authenticated session. - -## State management and race safety - -Create one table-render input model containing: - -- exact selector; -- selected row columns; -- canonical filters; -- sort; -- pagination cursor/page size; -- demanded facet columns; and -- materialization revision once known. - -Derive GraphQL variables from that model in one place. Do not let rows, count, -and facets independently read mutable filter state during the same render. - -On filter or sort changes: - -- reset the row cursor; -- preserve cached facets whose effective filter signature did not change; -- invalidate/refetch affected facets; -- cancel stale table-render requests; and -- retain the last successful rows/facets according to the product's existing - loading-state convention, rather than flashing an empty table unnecessarily. - -On selector or publication revision changes, invalidate the complete logical -table view. - -## Implementation sequence for the frontend Codex agent - -### 1. Discover the current request graph - -Search for: - -- `dataframeAggregate`, `dataframeAggregations`, and `dataframeRows` GraphQL - documents or query builders; -- the code that assigns aliases such as `a0` through `a155`; -- hooks/stores for dataset metadata, total count, rows, and facets; -- Explorer column/filter configuration types; -- the GraphQL client's request deduplication and cancellation support; and -- current performance telemetry and request-ID handling. - -Document which component triggers each current HTTP operation before editing. - -### 2. Add pure policy and canonicalization utilities - -Implement and unit-test: - -- facet mode selection (`eager`, `lazy`, `none`); -- eager facet budget enforcement; -- stable facet spec naming; -- canonical filter signatures; and -- independent facet cache keys. - -Keep these functions framework-independent. - -### 3. Introduce one table-render query builder - -Build one GraphQL operation containing rows, materialization metadata, and -bounded eager facets. Reuse `rows.totalCount` and remove redundant count and -dataset operations for the same state. - -If the frontend uses generated GraphQL artifacts, regenerate them using the -repository's normal generator. Do not hand-edit generated files. - -### 4. Replace eager all-column facet loading - -Stop mapping every dataset column to a legacy aliased aggregate. Request only -the bounded eager set on initial render. Mark remaining eligible controls lazy. - -### 5. Implement lazy batched facet loading - -Add open/visibility-driven loading, the 10-25 ms batching window, request -deduplication, cancellation, and revision/filter race guards. - -### 6. Add cache integration - -Store normalized results per facet key. Ensure results returned together can -be read and invalidated independently. - -### 7. Instrument and compare - -Record at least: - -- initial GraphQL POST count; -- initial requested facet count; -- total GraphQL request bytes and response bytes; -- time to first table rows; -- time until eager filters are usable; -- lazy facet cold and cache-hit latency; -- canceled/stale request count; and -- GraphQL error codes grouped by operation. - -Use browser performance marks and the existing telemetry layer. Preserve Loom -request IDs when available so browser measurements can be correlated with -backend logs. - -## Tests - -### Unit tests - -- Identifier/reference/free-text columns are not eager by default. -- Explicit configuration can opt a valid column into or out of faceting. -- The eager budget is deterministic. -- Equivalent filter order and `IN` member order produce the same cache key. -- Different selector, revision, column, size, or effective filter produces a - different key. -- Self-filter exclusion removes only predicates for the facet's own column. -- Duplicate filters are retained. -- Facet response normalization preserves missing counts and truncation. - -### Component/integration tests - -- Initial table mount sends one GraphQL operation containing rows and eager - facets. -- No initial request contains all 156 dataset columns. -- No redundant dataset or same-filter count operation is sent. -- Opening one lazy facet requests only that facet. -- Opening several controls together produces one batched request. -- Reopening an unchanged facet uses cache without a network request. -- Changing an unrelated filter refetches the facet with the correct effective - filters. -- Changing only a facet's self-filter does not fragment its cache when - self-filter exclusion makes the effective predicate set identical. -- A response from an older filter/revision snapshot is ignored. -- Pagination changes rows without refetching unaffected facets. -- Partial/truncated results are visibly distinguished from a complete list. -- GraphQL alias-specific errors do not erase successful rows or other facets. - -### End-to-end test - -Use the `HTAN_INT-BForePC` Patient selector and a schema with approximately 156 -columns: - -1. Load the Explorer table. -2. Assert one initial `/loom/graphql/graph` POST. -3. Assert the initial facet spec count is at most the configured eager budget. -4. Assert rows and count render correctly. -5. Open a lazy categorical facet and verify its values against the legacy - implementation. -6. Open a high-cardinality identifier filter and verify it does not preload an - unbounded distribution. -7. Apply and remove filters, paginate, and change sort while checking for stale - responses. -8. Capture performance and payload metrics for comparison with the baseline. - -## Acceptance criteria - -- Initial render uses one GraphQL POST for rows, row materialization metadata, - filtered total count, and eager facets sharing one selector/filter snapshot. -- Initial render never eagerly requests all 156 facets. -- Initial eager facets are bounded to 12 by default, or another explicitly - documented product limit no greater than 20. -- Every facet request uses bounded `TERMS` with `size <= 100` unless a reviewed - use case explicitly requires another aggregation kind. -- Identifier/reference/free-text distributions are lazy or disabled by - default. -- Opening multiple facets in the same render interval produces one batched - request, not one request per facet. -- Cache keys include selector, revision, column, size, and canonical effective - filters. -- Stale requests cannot overwrite newer table state. -- Requested facet values, counts, missing counts, filters, pagination, and - sorting match the existing UI for the same bounded result set. -- Browser tests show at least a 75% reduction in initially requested logical - facet jobs and at least a 50% reduction in GraphQL HTTP operations for one - table render. -- Record p50/p95 time-to-first-rows before and after. The change is accepted - only if time-to-first-rows improves materially without moving the delay to a - blocking loading state elsewhere in the UI. - -## Non-goals - -- Do not change Loom's GraphQL schema or generated backend files. -- Do not add a frontend-specific Loom endpoint. -- Do not replace aliases with 156 separate HTTP requests. -- Do not preload every facet into a global cache. -- Do not claim a truncated `TERMS` response is the complete domain. -- Do not make physical ClickHouse table names part of frontend state. - -## Separate backend follow-up - -This frontend work removes unnecessary demand and allows Loom's existing -request-scoped cache to work as designed. A separate Loom task should then: - -1. make active project releases the authoritative source-selection path; -2. remove the legacy source-discovery fallback after existing projects are - migrated to active releases; -3. batch active-release/execution metadata lookup instead of resolving projects - sequentially; and -4. consider a bounded release-revision-aware metadata/result cache. - -That backend follow-up targets the remaining approximately 650 ms metadata -cost. It should not block the frontend changes in this plan. - -## Definition of done handoff - -The frontend pull request should include: - -- a short before/after request diagram; -- the old and new initial GraphQL POST counts; -- old and new eager facet job counts; -- representative browser performance traces; -- unit, component, and end-to-end coverage described above; and -- a note confirming that Loom routes and schemas were unchanged. diff --git a/docs/FRONTEND_EXPLORER_V2_MIGRATION.md b/docs/FRONTEND_EXPLORER_V2_MIGRATION.md deleted file mode 100644 index 91615fe4..00000000 --- a/docs/FRONTEND_EXPLORER_V2_MIGRATION.md +++ /dev/null @@ -1,484 +0,0 @@ -# Historical: Frontend Explorer V2 Migration - -> This document describes the superseded V2 recipe/config packet. It is kept -> for compatibility and ETL migration context. New Builder work must use the -> [current Explorer authoring V2 contract](EXPLORER_AUTHORING.md), which sends -> intent-only documents and receipt-bound preview/save/publish requests. Do not -> copy the V2 request shapes below into new frontend code. - -This guide records the former frontend contract for Loom's REST Explorer -lifecycle. It explains the V2 packet for compatibility and migration work; it -is not a recommendation for new Builder code. The current intent-only contract -is documented in [`EXPLORER_AUTHORING.md`](EXPLORER_AUTHORING.md). - -## The important model change - -Loom now has two Explorer ownership modes: - -| Explorer | Owner | Config returned by Loom | Frontend behavior | -| --- | --- | --- | --- | -| `default` | Repository / ETL initially; Builder may edit and publish | `baselineConfig` contains a presentation-free projection; `draftConfig` and `activeConfig` contain the editable/published packet | Render and edit `draftConfig`; use `activeConfig` for the published view and fall back to `baselineConfig`/dataset metadata when needed. | -| Custom ID | User / Builder | `draftConfig` and, after publication, `activeConfig` contain the complete V2 packet | Render and edit the lossless presentation config. | - -Repository packets may be baseline-only or may include a complete presentation -layer. When ETL includes `views`, filters, charts, shared filters, or file -actions, Loom preserves them losslessly and exposes the published packet as -`default.activeConfig`. `default.baselineConfig` remains presentation-free. - -The default Explorer response is still useful for readiness and publication -state. Its `dataset.outputs[].columns` and `emittedColumns` describe the live -materialization. The frontend should derive the default table from those -columns and apply local presentation hints such as labels and ordering. - -Custom packets may contain all V2 presentation fields, but Loom remains -authoritative for schema, readiness, publication state, and materialization -metadata. Treat a custom config as invalid or stale when its referenced output -or column is not present in the live dataset. - -## API base URL - -The routes are rooted at: - -```text -/api/v1/projects/:project/explorers -``` - -In the deployed Calypr frontend this is normally reached through the Loom -reverse-proxy prefix, for example: - -```text -/loom/api/v1/projects/HTAN_INT-BForePC/explorers -``` - -Keep the prefix configurable. Do not hard-code the training host or a port -forward into frontend code. - -All requests use the application's existing authenticated session. Preserve -cookies, bearer headers, and the project authorization context used by the -rest of the frontend. - -## Explorer state - -The frontend should model the response as server state, not as a GraphQL model: - -```ts -type ExplorerManagement = "REPOSITORY" | "INTERACTIVE"; - -interface ExplorerState { - project: string; - explorerId: string; - management: ExplorerManagement; - - // Present for the repository default. It is always the presentation-free - // recipe/schema baseline. - baselineConfig?: ExplorerConfigV2; - - // The published packet is renderable. Edit draftConfig and publish it to - // replace activeConfig. - activeConfig?: ExplorerConfigV2; - - // Present for custom Explorers and for the repository default. - draftConfig?: ExplorerConfigV2; - - draftVersion: number; - draftDigest: string; - activeRevisionId?: string; - recipeDigest?: string; - resolvedSchemaDigest?: string; - sourceGeneration?: string; - emittedColumns?: EmittedColumn[]; - materializations?: Materialization[]; - dataset?: DatasetMetadata; - publication?: PublicationMetadata; - diagnostics?: Diagnostic[]; - publicationState?: string; - activeUrl: string; - updatedBy?: string; - updatedAt: string; -} - -interface DatasetMetadata { - generation?: string; - schemaDigest?: string; - outputs: DatasetOutput[]; -} - -interface DatasetOutput { - name: string; - state: string; - queryable: boolean; - columns?: PhysicalColumn[]; -} - -interface PublicationMetadata { - state: string; - generation?: string; - executionId?: string; - revisionId?: string; - updatedAt?: string; -} - -interface Diagnostic { - severity: string; - code: string; - fieldPath?: string; - message: string; - retryable?: boolean; - requestId?: string; -} -``` - -`activeUrl` is Loom's resource URL for the Explorer lifecycle record. It is -not necessarily the browser route used to render the Builder page. - -## REST lifecycle - -### Read the Explorer list - -```http -GET /api/v1/projects/:project/explorers -``` - -Returns an array of `ExplorerState` values. The default is ordered first, -followed by custom IDs. Use this route for the Explorer picker and then fetch -the selected detail record. - -### Read one Explorer - -```http -GET /api/v1/projects/:project/explorers/:explorerId -``` - -The `default` Explorer is editable. Render `draftConfig` in the Builder and -use `activeConfig` for the currently published view. If either packet is -absent or has no views, use `baselineConfig` and derive the layout from -`dataset`. - -### Create a custom Explorer - -```http -POST /api/v1/projects/:project/explorers -Content-Type: application/json - -{ - "name": "Cohort Explorer", - "title": "Cohort Explorer", - "source": "default" -} -``` - -The server derives the stable ID (`cohort-explorer`) from the name. The ID is -durable and becomes part of the URL. Do not generate a random browser ID or -send a client-selected ID as the identity source. - -To create an empty custom packet instead: - -```json -{ - "name": "Scratch Explorer", - "blank": true -} -``` - -Creation saves a draft only. It does not compile, materialize, or publish. -The response is the new `ExplorerState`. - -### Save a draft - -```http -PUT /api/v1/projects/:project/explorers/:explorerId/draft -Content-Type: application/json - -{ - "config": { "...complete ExplorerConfig V2...": "..." }, - "expectedDraftVersion": 3, - "expectedDraftDigest": "sha256:..." -} -``` - -This endpoint validates and canonicalizes the packet, computes its digest, and -saves only the draft. It does not compile, materialize, or change the active -revision. `expectedDraftVersion` is required; send `expectedDraftDigest` when -available. - -The same endpoint applies to `default`. Keep `explorer.id` as `default` and -keep `explorer.management` as `repository`; the repository identity describes -where the config originated, not whether Builder edits are allowed. - -On conflict, Loom returns HTTP 409: - -```json -{ - "error": { - "code": "DRAFT_CONFLICT", - "message": "Explorer draft changed; refresh before saving", - "currentVersion": 4, - "currentDigest": "sha256:...", - "updatedAt": "2026-08-17T19:00:00Z" - } -} -``` - -The frontend must refresh and reconcile the user's edits. Do not silently -overwrite, retry with the new version, or attempt a client-side merge unless -the user explicitly confirms it. - -### Compile authoring selections - -```http -POST /api/v1/projects/:project/explorers/:explorerId/authoring/compile -Content-Type: application/json - -{ - "output": "DocumentReference", - "config": { "...complete ExplorerConfig V2...": "..." }, - "snapshotToken": "loom:generation-token", - "selectedCandidateIdsByNode": { - "root": ["opaque-candidate-id"] - }, - "expectedDraftVersion": 3 -} -``` - -The response contains: - -```json -{ - "project": "HTAN_INT-BForePC", - "explorerId": "cohort-explorer", - "config": { "...canonical V2 packet...": "..." }, - "draftDigest": "sha256:...", - "snapshotToken": "loom:generation-token", - "recipeDigest": "sha256:...", - "resolvedSchemaDigest": "sha256:...", - "sourceGeneration": "generation-id", - "emittedColumns": [], - "diagnostics": [] -} -``` - -Compile is a validation/authoring operation. It does not save the draft or -publish data. The server resolves opaque candidate IDs through Loom's catalog; -the browser must not send AST nodes, physical table names, or browser-generated -selector IDs. - -The snapshot token and expected draft version protect against compiling against -a stale dataset or stale draft. Refresh the Explorer and discovery state when -Loom returns a conflict or an incomplete/unresolved catalog diagnostic. - -### Preview without publication - -```http -POST /api/v1/projects/:project/explorers/:explorerId/preview -Content-Type: application/json - -{ - "config": { "...complete ExplorerConfig V2...": "..." }, - "output": "DocumentReference", - "limit": 25, - "draftDigest": "sha256:..." -} -``` - -A successful response is shaped like: - -```json -{ - "project": "HTAN_INT-BForePC", - "explorerId": "cohort-explorer", - "output": "DocumentReference", - "columns": ["id", "subject_id"], - "rows": [{"id": "...", "subject_id": "..."}], - "rowCount": 1, - "digest": "sha256:...", - "diagnostics": [] -} -``` - -`limit` defaults to 25 and must be between 1 and 1000. Preview is scoped to -the requested output and never changes draft, revision, materialization, or -active-pointer state. - -Preview failures are terminal responses, not an indefinite loading state. They -return HTTP 422 with empty `columns`/`rows` and a diagnostic such as -`PREVIEW_FAILED`: - -```json -{ - "columns": [], - "rows": [], - "rowCount": 0, - "digest": "sha256:...", - "diagnostics": [{ - "severity": "ERROR", - "code": "PREVIEW_FAILED", - "message": "..." - }] -} -``` - -### Publish an Explorer - -```http -POST /api/v1/projects/:project/explorers/:explorerId/publish -Content-Type: application/json - -{ - "expectedDraftVersion": 3, - "expectedDraftDigest": "sha256:..." -} -``` - -Publish reads the server-owned draft. The frontend does not send a config in -this request. Loom recompiles the draft against the current active dataset -generation, reuses outputs whose generation and output fingerprint still -match, and materializes only missing or changed outputs. Loom then atomically -activates the matching dataset release, persists its materialization metadata, -inserts an immutable Explorer revision, and activates that revision. This -applies to both custom Explorers and `default`. - -The generation resolved during compilation is authoritative for the entire -publish operation. Loom validates that its immutable snapshot is staged before -starting materialization, so a stale or incomplete generation does not leave -behind an expensive partial build. A failed publish leaves the previous -Explorer revision and dataset release active. - -The authoring UI exposes Preview and Publish; it does not expose separate -create-release, save-release, or activate-release controls. Release records are -internal visibility and audit metadata managed by the ingestion/deployment -pipeline. - -Publish failures use stable frontend-safe error codes and do not expose raw -database errors. `DATASET_GENERATION_UNAVAILABLE` and -`DATASET_GENERATION_NOT_READY` mean data loading has not produced an activatable -generation; `DATASET_RELEASE_CONFLICT` means the active generation changed -during publish. These responses set `retryable: true` and include `requestId` -when available. Clear the Publishing state, retain the draft, show the friendly -`message`, and offer Retry; include `requestId` in support diagnostics. - -On success, update the local store from the returned `state` rather than -manually inferring active metadata: - -```json -{ - "project": "HTAN_INT-BForePC", - "explorerId": "cohort-explorer", - "publicationId": "interactive_...", - "activeUrl": "/api/v1/projects/HTAN_INT-BForePC/explorers/cohort-explorer", - "state": { "...ExplorerState...": "..." }, - "materializations": [], - "diagnostics": [] -} -``` - -## ExplorerConfig V2 rules - -Every config sent to a custom Explorer endpoint must be a complete packet: - -```json -{ - "apiVersion": "loom.calypr.org/explorer-config/v2", - "kind": "ExplorerConfig", - "project": "HTAN_INT-BForePC", - "explorer": { - "id": "cohort-explorer", - "title": "Cohort Explorer", - "management": "interactive" - }, - "recipe": { "...valid Loom recipe bundle...": "..." }, - "views": [ - { - "id": "document-reference", - "title": "DocumentReference", - "output": "DocumentReference", - "table": { - "columns": [ - {"column": "id", "label": "ID", "visible": true} - ] - } - } - ] -} -``` - -The `project`, `explorer.id`, and `explorer.management` values must match the -URL and operation. Interactive packets require at least one view. View output -names must exist in the recipe, and each view must have table columns. -Unknown fields are rejected. - -The recipe is executable data, not a frontend AST. Presentation fields are -losslessly retained in the packet but are not reconstructed from the recipe. -Keep them in the config object when editing; do not rebuild a config from -`recipe` alone. - -## Recommended frontend structure - -Split the implementation into three layers: - -1. `explorerApi` — typed REST calls and error decoding. -2. `explorerStore` — the selected project/Explorer, draft version/digest, - active revision, and request status. -3. Presenters: - - `DefaultExplorerPresenter`: renders `draftConfig` while editing, then - `activeConfig` after publication, and derives views from `dataset.outputs` - and `columns` when no complete packet is available. - - `InteractiveExplorerPresenter`: renders `draftConfig.views` and validates - referenced outputs/columns against live metadata. - -The default presenter should tolerate missing optional presentation hints and -should drop a hint for a column that is no longer emitted. A stale custom -config should produce an actionable validation diagnostic and allow the user -to repair it; it should not be treated as the repository default. - -The minimum request flow is: - -```text -GET explorers - -> GET selected Explorer - -> edit draft (including default) and PUT /draft - -> POST /authoring/compile when discovery changes - -> POST /preview for the selected output - -> POST /publish after explicit user confirmation - -> replace local state with returned state -``` - -Do not route normal Builder operations through `/graphql/graph`. In particular, -remove dependencies on legacy types such as -`DataframeRecipeColumnCandidatesInput`; candidate discovery and compilation for -the Builder belong behind the REST lifecycle contract. - -## Error handling checklist - -- `400`: malformed request, missing expected version, unsupported limit, or - missing required header/input. Show a request correction message. -- `403`: authorization failure. -- `404`: the Explorer does not exist. Refresh the Explorer list. -- `409` with `DRAFT_CONFLICT`: refresh server state and reconcile edits. -- `409` during publication/activation: keep the current active Explorer and - show the returned diagnostic; do not claim publication succeeded. -- `422`: invalid V2 config, unresolved/incomplete catalog, unsupported output, - materialization failure, or preview failure. Render diagnostics as terminal - Builder feedback. -- `503`: publication capability is temporarily unavailable. Keep the draft - local/server state intact and allow retry. - -Never leave the UI in `Preparing preview` or `Publishing` after a terminal -HTTP response. Clear the pending state in both success and failure handlers. - -## Migration checklist - -- [ ] Add a configurable Loom REST base path. -- [ ] Replace GraphQL Explorer list/detail reads with the REST list/detail routes. -- [ ] Never require `default.draftConfig` for rendering. -- [ ] Render `default.activeConfig` when ETL supplied a complete packet. -- [ ] Generate the default layout from `dataset.outputs[].columns` when no - complete `activeConfig` is available. -- [ ] Preserve complete custom V2 packets, including presentation fields. -- [ ] Send `expectedDraftVersion` on every draft/compile/publish mutation. -- [ ] Send the latest `expectedDraftDigest` when available. -- [ ] Handle `DRAFT_CONFLICT` by refreshing and reconciling, never overwriting. -- [ ] Replace GraphQL candidate input types with opaque REST candidate IDs. -- [ ] Use the REST compile result as the source of emitted columns and digests. -- [ ] Scope preview to one output and clear loading state on 4xx/5xx responses. -- [ ] Publish only after explicit confirmation and consume the returned state. -- [ ] Allow the repository default to use the same draft/compile/publish flow as custom Explorers. diff --git a/docs/GRAPHQL_API.md b/docs/GRAPHQL_API.md index 5aae1412..bae81e93 100644 --- a/docs/GRAPHQL_API.md +++ b/docs/GRAPHQL_API.md @@ -34,7 +34,7 @@ typed FHIR reads, discovery, and recipe control operations. ### Explorer authoring and catalog discovery Explorer authoring is not a GraphQL operation. The Builder uses the versioned -REST V1 intent contract documented in +REST V2 intent contract documented in [`EXPLORER_AUTHORING.md`](EXPLORER_AUTHORING.md). GraphQL Explorer lifecycle and Builder-introspection fields are not part of the current contract; the REST authoring compiler resolves catalog selections and the active dataset diff --git a/docs/LOOM _CLEANUP.md b/docs/LOOM _CLEANUP.md deleted file mode 100644 index 27d9f79b..00000000 --- a/docs/LOOM _CLEANUP.md +++ /dev/null @@ -1,93 +0,0 @@ -internal/explorer has become a dumping ground, but the deeper issue is not simply its size. It mixes a legitimate Explorer control-plane domain with legacy migration formats, persistence adapters, test - infrastructure, capability discovery, compilation artifacts, and lifecycle orchestration. - - The August 25 “refactor” explains the sudden loss of comprehensibility: it added 13,444 lines across 61 Explorer-related files—roughly 6,369 lines under internal/explorer and another 7,075 under internal/server. - - ## What Explorer is supposed to be - - Explorer is the user-facing control plane over the dataframe system: - - catalog evidence + authorization + active dataset generation - ↓ - explorer/capability - ↓ - Builder document → authoringv2 → explorer/compilation - ↓ - dataframe recipe - ↓ - immutable compilation receipt - ↙ ↘ - dataframe runtime dataframe publication - preview ClickHouse + activation - - Its clean responsibility would be: - - > Own the durable lifecycle of a user-authored view, from mutable intent through an immutable compilation receipt to an active revision. - - The key production path is visible in server/server.go:377: authorize an exact capability snapshot, translate the V2 document, compile through the dataframe engine, and persist a content-addressed receipt. - - Explorer does not—and should not—own physical query planning or AQL: - - - dataframe/recipe defines semantic recipe inputs. - - dataframe/semantic resolves and validates them. - - dataframe/compiler lowers them into physical plans and AQL. - - dataframe/runtime runs previews and queries. - - dataframe/publication materializes outputs. - - dataframe/published reads and federates those published outputs. - - The native translator in explorer/compilation/translate.go:121 is appropriately placed: it translates Explorer-specific intent into a generic dataframe recipe without executing it. - - ## Where the hygiene breaks down - - This subtree is actually seven Go packages, not one package, and some of the new subdivisions are sensible—particularly authoringv2, capability, and compilation. The root explorer package is the real mixed - aggregate. - - The clearest problems are: - - - explorer/types.go:90 combines identity, drafts, active revisions, recipes, physical columns, dataset selectors, materializations, publication state, migration metadata, and diagnostics in one persistence - model. - - - explorer/store.go:71 defines one very broad store interface covering repository config, drafts, receipts, revisions, activation, statistics, and destructive migration cleanup. - - explorer/service.go:31 mixes genuine lifecycle rules with many one-line persistence wrappers and several older lifecycle APIs. - - V1 compatibility occupies explorer/authoring_v1.go:18, explorer/state_v1.go:10, bootstrap, migration commands, and large server adapters even though V1 is no longer an HTTP surface. - - There are parallel domain models: root Compilation/EmittedColumn and explorer/compilation.Result/EmittedColumn. server/server.go:418 manually copies between them. - - authoringv2/migration.go makes the V2 package depend backward on root V1 types. Migration should depend on both versions, rather than V2 depending on legacy. - - Much of the application logic lives in the transport package. There are 6,287 production lines in internal/server/explorer*.go, including the 1,969-line server/explorer_v2_lifecycle.go:1. server is doing - orchestration that belongs in an Explorer application layer. - - So the strongest architectural smell is actually the pair internal/explorer + internal/server/explorer_*, not the Explorer directory in isolation. - - ## Is there dead code? - - Yes—enough to be meaningful, though it is not the main source of the sprawl. - - A whole-program Go reachability pass reported: - - - 79 Explorer functions unreachable from production executables. - - 61 of those become reachable only when tests are included. - - 18 remain unreachable even with tests. - - The strongest deletion candidates include: - - - Unused service methods such as ListConfigs, Config, SaveConfig, InsertAuthoringRevision, InsertReadyRevisionV2, and InsertFailedRevisionV2. - - Compatibility aliases such as ValidateID, NewSnapshotStore, NewMemoryRepository, and Translate. - - Six unused V2 decoder aliases. - - MigrateV1Bundle and bootstrap.Digest. - - Most of the remaining 61 are test infrastructure living in production files, especially the 499-line root MemoryStore, the capability memory repository, ProbeFuncs, and SliceObserver. They should either move to - _test.go/testutil or acquire a demonstrated production/local-deployment entry point. - - This means there is measurable dead/test-only surface, but most of the recent bulk is active code representing overlapping architectures and compatibility layers—not merely forgotten functions. - - ## Recommended boundary cleanup - - In order: - - 1. Delete the 18 genuinely unreachable wrappers and APIs; relocate test-only stores and probes. - 2. Quarantine V1, bootstrap, and migration logic under an explicit explorer/legacy or explorer/migration boundary. - 3. Split Store into focused repositories: drafts/config, receipts, and revisions/activation. - 4. Move compile/preview/publish use cases from internal/server into an Explorer application package; leave Fiber route decoding and response mapping in server. - 5. Make receipt/output-contract types canonical and remove the duplicate compilation DTOs. - - The coherent pieces—capability, authoringv2, native translation, and immutable receipts—should remain. The cleanup should preserve persisted JSON shapes, receipt hashing, Arango collection contracts, revision - IDs, scope semantics, and the offline migration commands. No files were changed during this audit. diff --git a/docs/LOOM_EXPLORER_ARCHITECTURE_POSTMORTEM.md b/docs/LOOM_EXPLORER_ARCHITECTURE_POSTMORTEM.md deleted file mode 100644 index 94ab2be0..00000000 --- a/docs/LOOM_EXPLORER_ARCHITECTURE_POSTMORTEM.md +++ /dev/null @@ -1,1439 +0,0 @@ -# Architecture postmortem: why Loom and the Explorer Builder do not cooperate - -## Executive conclusion - -Your suspicion is justified: Loom needs a substantial restructuring around its Explorer authoring boundary, catalog semantics, lifecycle orchestration, and ingestion jobs. - -It does **not** need a complete rewrite of its FHIR extraction, graph compiler, Arango access, or ClickHouse publication machinery. Those pieces contain useful, tested work. The problem is that they are currently connected through APIs that expose internal complexity directly to the frontend. - -Three architectural mistakes explain most of the behavior: - -1. **Loom exposes observed data as if it were executable capability.** - A resource, relationship, or field appearing in a catalog does not mean the compiler can use it. The frontend nevertheless treats catalog entries as valid choices. - -2. **Editing, validation, compilation, preview, publication, materialization, and activation are mixed together.** - The frontend sends a complete mutable bundle repeatedly, while Loom recompiles it through multiple layers on reconciliation, preview, and publication. - -3. **Graph ingestion is coupled to expensive, dataset-wide metadata profiling.** - The loader streams input rows, but simultaneously builds large in-memory catalogs whose size historically grew with data cardinality. That is why a “streaming” immutable-generation migration reached approximately 4.1 GB RSS. - -The frontend errors are therefore not random in origin. They are deterministic failures from several backend layers, discovered too late and translated inconsistently. They appear random to users because the UI is allowed to construct states that Loom cannot execute, and the backend does not return a stable recovery model. - -No code was modified during this review. - ---- - -# 1. What Loom currently does - -There are really two major systems inside Loom. - -## Graph-generation pipeline - -```text -repair-generation - ├─ audit old fhir_edge generation - ├─ ingest.Load - │ ├─ discover META files - │ ├─ load graph schema - │ ├─ preflight all files - │ ├─ create LOADING generation manifest - │ └─ for each file - │ └─ loadFile - │ ├─ scanner → buffered line queue - │ ├─ parser/profile workers - │ │ ├─ generated or generic row builder - │ │ ├─ generation-key rewrite - │ │ ├─ field profiling - │ │ ├─ vertex batch - │ │ └─ edge batch + relationship counts - │ └─ buffered write queue → Arango writers - ├─ write field catalogs - ├─ write relationship catalog - ├─ mark generation STAGED - ├─ audit new generation - └─ optionally activate generation -``` - -The central orchestration is in [generation_orchestration.go](../internal/ingest/generation_orchestration.go), while the concurrent file pipeline is in [generation_workers.go](../internal/ingest/generation_workers.go). - -## Explorer authoring pipeline - -```text -browser-only draft - │ - ├─ debounce - └─ POST complete bundle to /builder - ├─ validate authoring document - ├─ validate catalog snapshot - ├─ normalize route occurrences - ├─ validate catalog nodes/edges/candidates - ├─ lower authoring document to recipe - ├─ validate recipe - ├─ resolve schema - ├─ build semantic plan - ├─ lower physical plan - ├─ optimize plan - └─ return reconstructed builder state - -Preview: - complete bundle → resolve/compile again → AQL → Arango - -Publish: - complete bundle → resolve/compile again - → materialize outputs - → ClickHouse publication - → dataset release activation - → Explorer revision persistence -``` - -The main authoring compiler is [explorer_authoring_v1.go](../internal/server/explorer_authoring_v1.go), with HTTP lifecycle handling in [explorer_authoring_v1_routes.go](../internal/server/explorer_authoring_v1_routes.go). - -The critical observation is that `/builder` is not a lightweight editing API. It is effectively a full compiler endpoint. - ---- - -# 2. Why the screenshot happens - -The `qualification` failure is a perfect example of the larger architectural defect. - -The historical edge extractor permitted nested/backbone definitions to leak into persisted edge endpoint metadata. It therefore produced relationships resembling: - -```text -Practitioner → qualification -``` - -The Builder catalog intentionally reverses stored reference direction so that a user can start from the referenced resource and traverse toward resources that refer to it: - -```aql -COLLECT - from_type = d.to_type, - label = d.label, - to_type = d.from_type -``` - -That happens in [store.go](../internal/catalog/arango/store.go). - -Consequently, a malformed stored edge becomes: - -```text -qualification → Practitioner -``` - -in the Builder graph. - -The frontend then: - -- renders every catalog node as a resource; -- labels catalog nodes as “Available row start”; -- permits any inspected node to become the row start; -- has no `rootEligible`, `executable`, or `blockedReason` property. - -That behavior is visible in `GuidedGraphWorkspace.tsx` and `RouteExtensionPanel.tsx` in the IDP-Frontend repository. - -Only after the frontend submits the document does Loom reach the compiler’s row-grain check and return `UNSUPPORTED_ROW_GRAIN`. - -This is not a Practitioner-specific or qualification-specific bug. Any backbone element, nested definition, arbitrary schema definition, or invalid endpoint can produce the same failure. - -The general invariant must be enforced at four boundaries: - -- extraction: only concrete FHIR resources may become endpoints; -- persistence/audit: reject non-concrete endpoint metadata; -- catalog construction: never advertise invalid resources; -- authoring capability generation: advertise only operations the compiler has already validated. - -The current dirty Loom tree contains work toward a general `ConcreteResourceType` boundary and catalog filtering. That is the correct direction, but it does not solve the broader observation-versus-capability problem. - ---- - -# 3. The catalog is not a capability contract - -This is the deepest frontend/backend mismatch. - -## What field profiling actually does - -For every resource payload, the profiler recursively observes: - -- paths that occur; -- broad kinds such as scalar, object, or array; -- document counts; -- distinct scalar values; -- CodeableConcept-derived pivot columns; -- FHIR extension URLs and value forms; -- shape fingerprints used to reuse traversal plans. - -The implementation is in [write_profiler.go](../internal/catalog/write_profiler.go). - -The resulting `fhir_field_catalog` is useful for: - -- showing fields that are populated in this particular dataset; -- supplying filter value suggestions; -- discovering dynamic FHIR extensions; -- proposing pivot columns; -- avoiding presenting every theoretical FHIR field; -- enriching recipe schema resolution. - -But it does **not** prove that a field can be compiled. - -The profiler walks observed JSON. The compiler separately applies generated FHIR schema rules such as: - -- whether the path exists in the supported generated schema; -- whether each array segment has the required `[]`; -- whether the terminal value is scalar; -- whether the projection is valid at the selected row grain; -- whether the path can be lowered to AQL; -- whether a pivot or filter operation is supported. - -Those checks occur much later in files such as [selector_validation.go](../internal/dataframe/spec/selector_validation.go). - -Therefore: - -```text -observed in JSON ≠ valid selector -catalog relationship ≠ legal traversal -catalog node ≠ valid row root -``` - -The frontend currently assumes all three equivalences. - -## Where profiling belongs - -Field profiling should not be on the critical path for graph correctness or generation activation. - -A better ownership model is: - -- generated FHIR schema defines legal paths, cardinality, row grains, and operations; -- graph ingestion writes resources and valid relationships; -- an asynchronous enrichment job computes populatedness, approximate counts, extensions, distinct-value suggestions, and pivots; -- a capability compiler intersects schema capability with observed enrichment. - -Separating profiling from graph loading would not lose the graph or its relationships. Loom would temporarily lose only dataset-specific conveniences: - -- knowledge that a legal field is actually populated; -- immediate filter-value suggestions; -- dynamic extension discovery; -- observed pivot values; -- field frequency rankings. - -Those can appear asynchronously or be computed lazily. The UI could initially show valid schema fields and progressively enrich them. - ---- - -# 4. The frontend can construct many invalid states - -The issue is much broader than `UNSUPPORTED_ROW_GRAIN`. - -## Failure families exposed to the frontend - -| Failure family | Representative backend codes | -|---|---| -| Protocol and document shape | `MALFORMED_AUTHORING_REQUEST`, `UNSUPPORTED_AUTHORING_PROTOCOL`, `UNSUPPORTED_DOCUMENT_VERSION`, `MISSING_AUTHORING_IDENTITY` | -| Identifier integrity | `MISSING_OUTPUT_ID`, `DUPLICATE_OUTPUT_ID`, `DUPLICATE_AUTHORING_DOCUMENTS`, `DUPLICATE_ROUTE_EDGE`, `DUPLICATE_ROUTE_OCCURRENCE`, `DUPLICATE_CANDIDATE_ID`, `DUPLICATE_EMISSION_ID` | -| Catalog lifecycle | `SNAPSHOT_REQUIRED`, `CATALOG_UNAVAILABLE`, `CATALOG_INCOMPLETE`, `CATALOG_SNAPSHOT_FAILED`, `STALE_CATALOG_SNAPSHOT` | -| Route topology | `STALE_ROUTE_NODE`, `STALE_ROUTE_EDGE`, `INVALID_ROUTE_CONTINUITY`, `INVALID_ROUTE_ORIGIN`, `INVALID_ROUTE_OCCURRENCE_ORDER`, `INVALID_ROUTE_TERMINAL_NODE`, `ROUTE_OCCURRENCES_REQUIRED` | -| Selection/candidate integrity | `STALE_CANDIDATE_ID`, `CANDIDATE_REFERENCE_MISSING`, `SELECTION_NODE_MISMATCH`, `CANDIDATE_OCCURRENCE_REQUIRED`, `DUPLICATE_CANDIDATE_OCCURRENCE` | -| Compiler capability | `UNSUPPORTED_ROW_GRAIN`, `UNSUPPORTED_NESTED_TRAVERSAL`, `INVALID_AUTHORING_INTENT`, `INVALID_COMPILED_RECIPE`, `AUTHORING_OUTPUT_LOWERING_FAILED` | -| Presentation capability | `UNSUPPORTED_FILTER_PRESENTATION`, `UNSUPPORTED_CHART_PRESENTATION`, `STALE_EMISSION` | -| Preview | `INVALID_PREVIEW_LIMIT`, `UNKNOWN_AUTHORING_OUTPUT`, `PREVIEW_UNAVAILABLE`, `AUTHORING_PREVIEW_FAILED` | -| Publication | `PUBLICATION_UNAVAILABLE`, `SNAPSHOT_CONFLICT`, `MATERIALIZATION_FAILED`, `MATERIALIZATION_ACTIVATION_FAILED`, `REVISION_STORE_FAILED` | -| Identity and authorization | `AUTHORING_IDENTITY_CONFLICT`, `FORBIDDEN`, `NOT_FOUND` | -| Infrastructure fallback | `AUTHORING_COMPILER_UNAVAILABLE`, `ACTIVE_AUTHORING_BUNDLE_INVALID`, `INTERNAL_ERROR` | - -Many of these are appropriate backend checks. The problem is that the contract does not tell the frontend: - -- which choices are legal before the user selects them; -- which error is attached to which editable object; -- whether the error is recoverable; -- what recovery action should be taken; -- whether an error invalidates the draft, catalog snapshot, compilation, or publication. - -## The frontend discards most diagnostic information - -The API error type can carry status, code, diagnostics, request ID, details, and retryability. But the workspace normally renders only the first diagnostic’s message and code. - -It discards or hides: - -- all subsequent diagnostics; -- diagnostic stage; -- JSON path; -- structured details; -- request ID; -- recovery action; -- whether retrying is safe; -- which table, route occurrence, or candidate failed. - -For the initial Builder load, it can reduce the result even further to a generic “could not be loaded” state. - -## Backend errors are not consistently typed - -Loom has a typed dataframe error package, but the authoring boundary does not consistently preserve it. Generic compiler failures are converted using: - -```go -message := err.Error() -code := "INVALID_AUTHORING_INTENT" -if strings.Contains(strings.ToLower(message), "traversal") { - code = "UNSUPPORTED_NESTED_TRAVERSAL" -} -``` - -That creates three problems: - -- many distinct failures collapse into `INVALID_AUTHORING_INTENT`; -- classification depends on English error text; -- raw internal error wording reaches the user. - -This directly explains the “random backend error” experience. - ---- - -# 5. Frontend state ownership is unstable - -The current hard-cutover frontend is considerably smaller than its predecessor, but several structural problems remain. - -## Browser-only draft - -The editable draft lives primarily in the React reducer. There is no normal server-side saved draft with compare-and-swap semantics. - -Consequences: - -- refresh can lose work; -- another browser cannot continue the draft safely; -- active revision and local draft can diverge; -- backend reconciliation is being used partly as validation and partly as normalization. - -## Whole-bundle reconciliation - -Every semantic edit triggers a debounced POST containing the complete authoring bundle. - -The frontend ignores stale responses by generation number, but it does not cancel obsolete HTTP requests. Loom still performs every obsolete compilation. - -## Frontend and backend sometimes resolve different documents - -`completeDocument` omits incomplete tables from the outgoing bundle. - -Thus the UI may display an incomplete table while the backend successfully resolves a bundle that does not contain that table. The word “reconciled” does not mean the visible workspace was completely validated. - -## Stale-snapshot recovery is unsafe - -On a stale snapshot, the frontend refetches Builder state and then retries the old bundle against the new snapshot. - -That can fail because: - -- catalog IDs are opaque and may have changed; -- the refetch can hydrate active state over local state; -- no semantic mapping exists from old catalog identities to new identities; -- there is no draft revision or merge protocol. - -## Runtime types have already drifted - -A documented failure involved Loom returning `candidateEmissions: null` while the frontend declared it as an array and crashed. Current code guards against that specific case, and the backend now serializes `[]`. - -That incident is evidence of the actual problem: Go and TypeScript separately describe the contract, and no generated or cross-repository conformance boundary guarantees they agree. - ---- - -# 6. Is repair-generation actually streaming? - -No. It is a streaming input pipeline attached to several accumulating data structures. - -The source file is not loaded wholesale, but “does not read the entire file into one slice” is much weaker than constant-memory streaming. - -## Structures retained beyond one row or write batch - -- up to 10,000 buffered input lines in the committed implementation; -- eight parser workers; -- one vertex batch and one edge batch per parser worker; -- up to 100 queued write batches; -- import-request body copies; -- pooled byte buffers retaining their high-water capacity; -- one field profiler per worker for the entire file; -- a shared shape-plan cache for the entire file; -- merged field profiler state; -- merged field profilers retained for every resource type until the full load completes; -- one relationship-count map per writer; -- file-level and generation-level relationship aggregations; -- Arango’s indexes, import transaction state, caches, and compaction memory; -- both old and new generation data and index entries in the same collections. - -Preflight also reads the inputs before ingestion, so the 4.5 GB source is traversed at least twice, although preflight does not retain all rows. - -## Memory budget - -The Go estimates below illustrate the committed pipeline at 500-row batches, eight parser workers, a 10,000-line input queue, and a 100-task write queue. They are formulas and plausible ranges, not heap-profile measurements. Actual FHIR document sizes vary heavily. - -| Component | Approximate budget | Controlling bound | Growth class | -|---|---:|---|---| -| Input line queue | `10,000 × average line size`; roughly 20–60 MB at 2–6 KB/row | Queue length | Bounded by queue | -| Active parser state | Approximately 8 active rows with typed objects, generic maps, edges and temporary buffers; roughly 10–100 MB | Worker count and largest row | Worker-bounded | -| Vertex batches | `8 × 500 × encoded vertex size`; roughly 8–24 MB | Workers × batch size | Batch/worker-bounded | -| Edge batches | `8 × 500 × edge size`, but rows can emit many edges; roughly 1–20+ MB | Workers × batch size and edge fan-out | Batch/worker-bounded | -| Queued write batches | Up to `100 × 500 × encoded document size`; roughly 50–300+ MB | Queue tasks × batch size | Queue/batch-bounded | -| Field distinct values | Historically potentially multiple GB | Number of distinct values across observed paths, duplicated across workers | Dataset-cardinality growth | -| Shape plans | One plan per unique observed structural fingerprint | Unique payload shapes | Dataset-cardinality growth | -| Relationship maps | Usually KB to low MB | Distinct `(project,generation,path,from,label,to)` tuples | Normally schema-bounded | -| JSON copies | Often 50–500+ MB overlapping other rows/batches | Workers, queues, batch sizes and largest documents | Worker/batch-bounded | -| Import request copy | One body copy per active writer; pooled buffers may retain capacity | Writers × batch bytes | Writer/batch-bounded | -| Arango import state | One or more request/transaction batches | Concurrent writers and batch bytes | Writer/batch-bounded | -| Arango persistent indexes | Grows with all documents and generations | Data cardinality × index count | Database-cardinality growth | -| Arango cache/compaction | Can reach GB-scale independently of Go | Working set and database configuration | Database/server policy | - -The field profiler is the best explanation for the observed 4.1 GB Go RSS. - -Each worker retained its own distinct-value maps across the entire file. High-cardinality FHIR fields can include: - -- IDs; -- identifiers; -- references; -- URLs; -- attachment locations; -- hashes; -- timestamps; -- extension values; -- coding combinations. - -After a file completes, Loom creates a merged profiler while worker-local profilers may still exist. It then retains the merged profiler in the generation-wide `catalogs` map until every file is complete. - -The current dirty tree adds finite limits and smaller queues. That is an improvement over unbounded retention, but the defaults are not a credible aggregate memory budget: - -```text -4,096 fields -× 4,096 values per field -× up to 4,096 bytes per value -≈ 64 GiB of raw value bytes per profiler -``` - -That excludes maps, strings, slices, extension observations, pivots, and multiple worker profilers. “Finite” is not synonymous with operationally safe. - -Memory limits should be established by the Kubernetes workload and Go runtime environment, not by adding server-owned memory policy. - ---- - -# 7. Why one writer and 500-row batches still OOMed - -Those controls reduced only part of the memory equation. - -Reducing writers controls: - -- concurrent HTTP import bodies; -- writer-local relationship maps; -- simultaneous Arango requests. - -Reducing batch size controls: - -- vertex batch size; -- edge batch size; -- each queued task’s payload; -- each import body. - -Neither controls: - -- field distinct-value accumulation; -- shape-plan accumulation; -- worker-local catalog duplication; -- merged catalogs retained across files; -- the eight parser workers in the committed pipeline; -- the 10,000-line queue; -- the number of queued tasks; -- Arango index growth; -- old and new generations coexisting physically. - -A slower writer can also keep the write queue full for longer. Smaller batches mean each queue slot is smaller, but 100 queued batches plus parser-owned batches remain live. - -So the batch change shaved hundreds of MB at best while the dominant structure continued growing toward dataset cardinality. - ---- - -# 8. JSON amplification - -One input line may exist in several forms during processing: - -1. scanner-owned bytes; -2. queued Go string; -3. `[]byte(line.text)`; -4. generated typed FHIR representation or generic `map[string]any`; -5. vertex envelope; -6. serialized vertex bytes; -7. serialized edge bytes; -8. decoded `map[string]json.RawMessage` for generation namespacing; -9. re-serialized generation-qualified vertex and edges; -10. profiling payload map; -11. concatenated import body; -12. copied import body for HTTP transmission. - -The generation wrapper alone decodes and re-encodes every vertex and edge in [generation_identity.go](../internal/ingest/generation_identity.go). The import path builds a pooled buffer and then makes another copy in [client.go](../internal/store/arango/client.go). - -These copies are mostly bounded by concurrency and buffering, but they amplify every other memory-retention decision. - ---- - -# 9. Generation model evaluation - -| Model | Strengths | Costs and risks | Assessment | -|---|---|---|---| -| Shared collections with generation-qualified keys | Stable collection names; manifest pointer can switch atomically; existing queries can add a generation predicate | Every generation shares every index; all queries must scope correctly; cleanup requires large filtered deletes; collection/index working set grows; old and new coexist during repair | Workable with strict retention and ample Arango capacity, but operationally expensive | -| Separate collections per generation | Strong isolation; old generation cannot be mutated accidentally; activation changes a collection mapping; dropping a generation is cheap and complete | Dynamic collection resolution; many collections and indexes; bootstrap overhead; compiler must never hard-code names | Better immutable isolation, but needs a deliberate collection resolver and retention policy | -| Database-side copy/rewrite | Avoids rereading META; can stream/copy authoritative vertices; much lower Go parse/profile cost | Still writes a second set of documents and indexes; must batch carefully; edge/key rewriting must be exact | Best repair mechanism when stored vertices are trusted | -| Full source re-ingestion | Reproducible from canonical source; exercises current parser, validation and extraction; appropriate after broad transformation changes | Worst I/O, CPU and memory; repeats profiling; duplicates every index entry; can fail hours into the operation | Reserve for cases where resource payloads themselves are suspect | - -For long-term clarity, separate physical collections—or a similarly isolated generation namespace—fit immutable generations better. But this should not be changed casually: Loom’s compiler and query layer need one generation-to-storage resolver first. - -The Explorer restructuring does not need to wait for that storage migration. - ---- - -# 10. Does edge repair require parsing the entire META directory? - -No. - -There are three repair scopes. - -## Relationship catalog only - -If `fhir_edge` is correct but `fhir_relationship_catalog` is contaminated, rebuild the catalog from valid edges. No FHIR source parsing is needed. - -The current rebuild query already has the shape of this approach and filters endpoints against concrete resource types. - -## Remove malformed edges while preserving the graph - -If malformed edges can be identified by invalid endpoint types, a new immutable generation can be constructed by: - -- streaming/copying old-generation vertices into new-generation keys; -- copying valid edges while rewriting their generation-qualified endpoints; -- omitting invalid edges; -- rebuilding relationship counts; -- copying or asynchronously regenerating field enrichment; -- auditing and activating the new generation. - -This inserts new documents and does not mutate the old generation. - -## Regenerate possibly missing or incorrect edges - -If the extractor may also have missed valid edges, edge extraction must run again. But it can run from FHIR payloads already stored in resource vertices. - -It may be sufficient to re-extract only source resources associated with invalid edges. If the faulty extractor’s scope is unknowable, all stored vertices may need to be inspected—but that is still not the same as rereading and fully re-ingesting the entire META source. - -Full META re-ingestion is required only when: - -- stored resource payloads are incomplete or wrong; -- the resource transformation itself changed; -- authoritative provenance requires recreation from source; -- schema validation must be rerun against the original files. - ---- - -# 11. The lifecycle design is unfinished - -The frontend and Loom planning documents describe a safer model: - -- save a draft with compare-and-swap; -- compile to an immutable receipt; -- preview by compilation ID; -- publish by compilation ID; -- protect against external updates; -- expose blocked candidates and diagnostic eligibility. - -The actual implementation instead upgraded the existing Builder endpoint: - -- `/builder` accepts and recompiles the whole bundle; -- `/preview` accepts and recompiles the whole bundle; -- `/publish` accepts and recompiles the whole bundle; -- the compilation receipt exists largely as an internal return structure; -- draft persistence and CAS are absent; -- publication behaves essentially as last-writer-wins. - -This is why small UI actions cross so many backend layers. - -Loom also retains a large legacy Explorer V2 lifecycle/compiler implementation in [explorer_v2_lifecycle.go](../internal/server/explorer_v2_lifecycle.go), alongside the new V1 authoring model and the older repository-upload route in [explorer_config_route.go](../internal/server/explorer_config_route.go). - -Even where the legacy routes are no longer registered, tests and internal machinery keep much of the model alive. The result is multiple overlapping definitions of: - -- Explorer config; -- authoring bundle; -- draft; -- revision; -- recipe; -- compiled config; -- materialization; -- dataset release; -- publication. - -That is genuine architectural sprawl, not just a file-organization problem. - ---- - -# 12. Recommended target architecture - -The restructuring should be radical at the boundary but conservative in proven internals. - -## A. Immutable graph ingestion job - -Responsibilities: - -- validate and load concrete FHIR resources; -- create valid resource-to-resource edges; -- stage an immutable generation; -- audit structural invariants; -- activate only after validation. - -Run it as a dedicated Kubernetes Job, not via `kubectl exec` inside the Loom server pod. - -The Docker image can contain both binaries, but the Job should override the server entrypoint and own: - -- CPU request/limit; -- memory request/limit; -- `GOMEMLIMIT`; -- `GOMAXPROCS`; -- retry/backoff policy; -- temporary-storage limits. - -The Loom server should not decide these policies. - -## B. Capability snapshot compiler - -Create a generation-scoped capability document from: - -```text -generated FHIR schema -∩ valid graph relationships -∩ observed populatedness/enrichment -∩ authorization scope -∩ supported compiler operations -``` - -Every advertised node and candidate should carry explicit semantics such as: - -```json -{ - "resourceType": "Practitioner", - "rowRootEligible": true, - "supportedOperations": ["SELECT", "FILTER"], - "blockedReason": null -} -``` - -Invalid nodes may be retained for audit visibility but must not appear as selectable resources. - -A powerful invariant test then becomes possible: - -> Every advertised row root, route edge, and column candidate must compile successfully under the snapshot that advertised it. - -### The traversal Builder is the product contract - -The Explorer graph in the frontend is intended to be a real authoring surface -over Loom's FHIR graph. Loom must make that vision true. A user should be able -to choose a concrete FHIR resource as the row root, follow relationships Loom -actually stores, select fields from any occurrence along the route, and compile -that construction into an executable Arango query. - -The frontend should not need to reproduce the FHIR schema, understand Arango -edge direction, or predict dataframe cardinality rules. Those are Loom -responsibilities. - -### Current Loom gap - -The current catalog reader assembles Builder nodes, edges, and selections -directly from populated-field and populated-relationship discovery. The public -types carry only: - -- node ID and resource type; -- edge ID, source node, target node, and label; and -- candidate ID, node ID, field reference, logical type, and coarse filter/chart - flags. - -This is enough to draw a graph, but it is not enough to promise that the graph -can be compiled. In particular: - -- a node can be observed without having a supported row grain; -- a relationship can be observed without a valid generated traversal; -- a field can be observed without being a legal generated selector; -- an object or array can require a projection mode the catalog does not - describe; -- repeated resource types require occurrence-specific field binding; -- Builder direction is the inverse of stored FHIR-reference direction and must - be made unambiguous; -- the hard-coded four-hop authoring limit is not represented in the catalog; - and -- catalog completeness currently means discovery completed, not that every - returned capability passed the compiler. - -### Required meaning - -A capability snapshot must be an immutable, generation-scoped, -authorization-scoped, compiler-versioned statement of what Loom promises it can -execute. - -The generated FHIR schema and compiler define validity. Observation data only -annotates valid capabilities with populatedness, edge counts, and suggested -values. An observed fact must never create a capability the schema/compiler do -not support. - -The snapshot identity must cover: - -- canonical project identity; -- immutable dataset generation; -- authorization-scope digest; -- generated FHIR schema digest; -- relationship-catalog digest; -- field-enrichment digest or version; -- authoring protocol version; -- compiler artifact version; -- traversal policy version; and -- the canonical capability payload. - -Changing any of these produces a different snapshot token. A snapshot is never -silently modified in place. - -### Node contract - -Every node offered to the current Builder must represent a concrete FHIR -resource collection with a supported row grain: - -~~~json -{ - "nodeId": "n_...", - "resourceType": "Practitioner", - "rowRootEligible": true, - "rowGrain": "RESOURCE", - "populated": true, - "documentCount": 8124, - "blockedReason": null, - "capabilityVersion": "..." -} -~~~ - -For compatibility with the current frontend, Loom should initially omit -non-root-eligible nodes from the normal nodes array. The UI currently treats -every returned node as a selectable row start. A future frontend may render -blocked nodes through a separate collection or an eligibility property it -explicitly understands. - -Node eligibility must be decided by the same row-grain registry used during -lowering. It must not be inferred from collection existence or profiler rows. - -### Traversal-edge contract - -An advertised Builder edge must mean: - -> From an occurrence of the source node, Loom can follow this exact -> relationship in this authoring direction, under the pinned generation and -> authorization scope, and lower the step into a valid graph traversal whose -> result is an occurrence of the target node. - -The internal capability requires more information than the frontend currently -renders: - -~~~json -{ - "edgeId": "e_...", - "fromNodeId": "n_patient", - "toNodeId": "n_document_reference", - "label": "subject_Patient", - "storageDirection": "INBOUND", - "sourceResourceType": "DocumentReference", - "targetResourceType": "Patient", - "observedEdgeCount": 1002431, - "allowsRepeatedTarget": true, - "blockedReason": null -} -~~~ - -The current frontend can continue consuming only edge ID, source, target, and -label. The additional internal fields let Loom define and test the promise. - -Every edge must pass all of the following before publication: - -- both endpoints canonicalize to concrete generated FHIR resource types; -- both endpoint nodes exist in the same snapshot; -- the label resolves through the generated traversal registry; -- Builder direction maps unambiguously to stored edge direction; -- project, generation, and authorization predicates can be applied; -- the lowerer produces a one-step physical traversal plan; and -- the renderer produces valid AQL for that plan. - -Malformed historical relationships may remain visible to audit tooling, but -must never enter the Builder capability graph. - -The arbitrary four-hop policy requires an explicit decision. The current -frontend presents a traversal graph without explaining that limit. Loom should -either remove the fixed authoring limit and rely on physical plan cost/safety -policy, or publish a route policy the frontend can enforce. Quietly accepting -four steps and rejecting the fifth is not a solid contract. - -### Column-candidate contract - -A profiler record is only input evidence. Before a field becomes a Builder -candidate, Loom must resolve it through generated selector and terminal-type -metadata. - -Each internal candidate should describe: - -- canonical selector; -- owning node; -- terminal FHIR type; -- scalar/object/array cardinality; -- allowed projection modes; -- supported filter operators; -- supported chart aggregations; -- whether the field was observed; -- observed document count; -- bounded value suggestions; and -- any reason it was excluded or restricted. - -~~~json -{ - "candidateId": "s_...", - "nodeId": "n_observation", - "label": "Observation.code.coding[].code", - "logicalType": "string", - "cardinality": "MANY", - "projectionModes": ["FIRST", "ARRAY", "DISTINCT_ARRAY"], - "filterOperators": ["EQUALS", "IN", "EXISTS"], - "filterable": true, - "chartable": true, - "populated": true -} -~~~ - -For the current frontend, Loom should return only candidates safe under the -frontend's existing default projection behavior. Richer candidates can be -exposed when the frontend can choose projection modes explicitly. This ensures -every currently clickable field works while preserving richer future -capabilities. - -Candidates remain attached to node types in the snapshot. The authoring -document binds a candidate to a route occurrence. That preserves the necessary -distinction when one route visits the same resource type more than once. - -### Deterministic snapshot construction - -Loom should build a snapshot in these phases: - -1. Resolve the exact active or requested immutable generation. -2. Resolve the caller's authorization scope for that generation. -3. Enumerate concrete resource collections visible in that scope. -4. Intersect them with the compiler's supported row-grain registry. -5. Read observed relationship classes and reject any class absent from the - generated traversal registry. -6. Normalize Builder direction and create snapshot-local opaque edge IDs. -7. Read observed fields, but validate every path through generated selector and - terminal-type metadata before creating a candidate. -8. Derive projection, filter, and chart operations from compiler semantics. -9. Canonically sort and serialize nodes, edges, candidates, policies, and - version identities. -10. Hash and persist the complete immutable snapshot. - -If a required dependency fails, Loom returns an explicitly unavailable -snapshot. It must not return a partial graph that looks usable. - -### Executable invariants - -The central promise should be tested as: - -- every node compiles as a zero-hop output root; -- every edge compiles as a one-hop extension from its source node; -- every candidate compiles at an occurrence of its node using each advertised - projection mode; -- every advertised filter/chart operation passes semantic validation; -- every compiled output renders valid AQL; -- graph direction and endpoint types agree with the rendered AQL; -- opaque IDs resolve only inside the snapshot that created them; and -- incomplete or truncated snapshots never appear as usable Builder state. - -Representative integration fixtures should also run Arango EXPLAIN on generated -queries. That catches renderer, index, and direction mistakes pure compiler -tests cannot. - -This snapshot is the main mechanism for making the existing traversal UI -trustworthy. Most current Builder errors should become impossible to construct, -not merely better explained after submission. - -## C. Server-owned draft - -Use an immutable or versioned draft: - -```text -PUT draft -If-Match: draftRevision -``` - -The response produces a new draft revision. Refresh, multiple tabs, and conflicts become explicit. - -## D. Immutable compilation receipt - -```text -POST .../authoring/v2/compile - V2 document + exact capability snapshot token - -→ receiptId + normalized Builder state + public output columns -``` - -Compilation is side-effect free with respect to graph data, materialization, -publication, and active pointers. Persisting the immutable receipt is part of -compilation and must finish before Loom returns success. - -### Implemented boundary - -The production compiler now translates V2 intent directly. It does not route -through the V1 compatibility compiler. It authorizes the exact active snapshot, -translates route occurrences and candidate selections into a native recipe, -compiles the already resolved recipe without catalog discovery, creates a -versioned receipt, and persists it through the immutable receipt store. - -Preview and publication accept a receipt ID and execute the receipt's frozen -resolved recipe. They never reinterpret the authoring document, migrate it -through V1, or rediscover fields. - -### Semantic guarantee - -A receipt must mean: - -> Loom accepted this exact authoring intent against this exact capability -> snapshot, resolved every route occurrence and candidate identity, produced -> this exact output schema, and created an executable artifact that can be -> previewed or published without interpreting the authoring document again. - -The receipt must pin: - -- project and Explorer identity; -- canonical intent digest; -- capability snapshot token; -- dataset generation; -- authorization-scope digest; -- compiler and artifact-format version; -- canonical V2 document and normalized route occurrences; -- candidate-to-occurrence bindings; -- resolved recipe and schema; -- resolved-recipe and output-contract digests; -- public output schema and emitted-column identities; -- per-output fingerprint; -- deterministic warnings; and -- creation and retention metadata. - -The receipt does not persist optimized physical IR, AQL, bind variables, or -physical storage names. Those are request-scoped compiler products. Runtime -deterministically lowers the frozen resolved recipe again and verifies its -recipe digest, resolved schema digest, and output fingerprints. This -re-lowering is cheap and does not repeat semantic discovery or authoring -translation. - -### Compile operation behavior - -The compilation operation accepts authoring intent and an exact capability -snapshot. It validates, normalizes, lowers, resolves, optimizes, creates the -public bindings, persists the receipt, and returns the receipt ID. - -Compilation is side-effect free with respect to user data and publication: it -does not materialize rows, create an active Explorer revision, or move an active -pointer. Persisting the immutable receipt is necessary and is not publication. - -Compilation is idempotent. The same canonical intent, snapshot, scope, -generation, schema, receipt format, and compiler contract produces the same -compilation key and content-addressed receipt ID. Explicit compile/recompile -always rebuilds normalized intent; a compilation-key match is not treated as -proof that an old artifact remains reproducible. Arango uses immutable -`INSERT ... overwriteMode: "ignore"` rather than an updating UPSERT, then Loom -reads and re-lowers the stored artifact with the preview verifier before it can -return success. - -The receipt must be stored before Loom returns a successful Builder -reconciliation. Returning success without a retrievable artifact recreates the -current race in which preview has to repeat the work. - -### Compatibility with the current frontend - -The existing frontend can use the boundary without owning compiler internals: - -1. POST /builder compiles and persists the receipt. -2. The response includes the receipt ID and compiler-owned emitted columns. -3. Preview and publish submit that receipt ID. -4. Debounced compile plus compile-before-preview safely handles a missing or - stale local receipt. - -V1 has no production authoring route. It remains available only to migrate old -stored documents. - -### Validity and retention - -A content-addressed receipt never mutates into a different receipt. Execution -eligibility can still change: - -- the caller may lose authorization; -- the pinned generation may be retired; -- the running Loom version may not support the artifact format; -- an operator may invalidate a compromised compiler build; or -- an unreferenced ephemeral receipt may be explicitly purged. - -These cases produce explicit execution diagnostics. Loom must never silently -recompile the receipt against a newer generation or snapshot. - -Receipts referenced by published immutable revisions are retained with those -revisions. Loom exposes receipt size/count statistics and explicit orphan -purge. Automatic TTL is intentionally deferred until deployed storage -measurements justify a policy. - -### Concurrency behavior - -Receipts also make debounced frontend concurrency harmless. If several Builder -requests are in flight, each successful request produces an artifact for its -own content. The frontend may ignore an older response, but the old response -cannot overwrite the newer artifact. Previewing a receipt always refers to one -exact intent. - -## E. Preview by receipt - -```text -POST .../authoring/v2/preview - receiptId + outputId + optional limit -``` - -Preview does not accept fresh mutable intent. - -### Current behavior - -The production V2 route now loads the exact persisted receipt by project, -Explorer, and receipt ID. It does not accept an authoring bundle and does not -call the authoring compiler. - -### Required preview flow - -Receipt-based preview performs only: - -1. Load the immutable receipt. -2. Verify that it belongs to the route's project and Explorer. -3. Re-authorize the caller against the pinned project, generation, and scope. -4. Validate the receipt ID, compilation key, format/compiler versions, resolved - recipe digest, and output-contract digest. -5. Verify that outputId exists in the receipt. -6. Deterministically lower the frozen resolved recipe without catalog - discovery. -7. Verify the resolved schema digest and per-output fingerprints. -8. Apply a bounded preview window to only the requested output. -9. Render and execute with server-owned authorization bind variables. -10. Return the public columns and rows recorded by the receipt. - -It must not: - -- read a new capability snapshot; -- normalize route occurrences; -- resolve candidate IDs; -- lower authoring intent; -- rediscover dynamic fields; -- rediscover or reinterpret semantic inputs; or -- select a different generation. - -### Generation semantics - -The receipt pins an immutable generation. Preview should remain reproducible -against that generation while it is retained and the caller remains authorized, -even after a newer generation becomes active. A generation switch must not -silently change an existing receipt. - -If the pinned generation has been retired, Loom returns a specific -receipt-input-unavailable diagnostic. The frontend can then refresh Builder -capabilities and reconcile again. - -Publication may use a stricter policy and require that the receipt generation -is still the expected active generation. Preview and publication do not need -identical staleness rules. - -### Execution contract - -The receipt already contains: - -- output identity; -- public output schema; -- resolved semantic recipe; -- project, generation, and authorization-scope identity; -- resolved recipe/schema and output fingerprints; and -- deterministic diagnostics. - -Preview rebuilds request-scoped physical IR and AQL because those are compiler -implementation details, then adds the bounded row limit. It does not redo -authoring translation or schema discovery. - -Loom must enforce: - -- default and maximum row limits; -- a ten-second request deadline; -- client cancellation; -- maximum query cost or approved plan class; -- output-specific execution rather than running every output; -- authorization predicates independent of client input; and -- a 32 MiB encoded-response limit with atomic response semantics. - -The static plan gate runs before Arango execution and rejects a plan outside -the approved preview class. Representative generated plans are checked with -Arango `EXPLAIN`; passing the gate is not a promise that Arango will be -available at execution time. If the encoded response would exceed 32 MiB, -Loom returns `PREVIEW_RESPONSE_TOO_LARGE` without a partial row set. If the -deadline expires, it returns `PREVIEW_TIMEOUT`. Receipt-store dependency -failures use `RECEIPT_STORE_UNAVAILABLE`; those and timeouts are retryable. -`PLAN_TOO_EXPENSIVE` and `PREVIEW_RESPONSE_TOO_LARGE` require a smaller -request, while `CLIENT_CANCELED` is not a server outage. - -Fiber/fasthttp does not propagate a browser disconnect through the handler's -context. Preserve `CLIENT_CANCELED` when an explicit cancellable context is -terminated, but assume an aborted browser request may continue until Loom's -ten-second deadline. Never classify an empty or truncated preview by matching -error text. The browser should retain the latest Builder document and branch -on stable diagnostic codes when a response is available. - -Compilation validates lowering for every output, and representative integration -tests should render and run Arango EXPLAIN. Database execution can still fail -because Arango is unavailable, but it should not fail because Loom advertised a -traversal it could never lower. - -### Response - -The response preserves the frontend's public rows-and-columns shape and binds -it to the receipt: - -~~~json -{ - "outputId": "out_...", - "columns": [], - "rows": [], - "rowCount": 0, - "receiptId": "receipt_..." -} -~~~ - -## F. Asynchronous publication - -```text -POST /publications - compilationId - expectedActiveRevision - -→ operationId -``` - -Publication should: - -- materialize outputs; -- verify them; -- persist the immutable Explorer revision; -- atomically activate it; -- retain the previous active revision on any failure. - -The UI should poll or subscribe to an operation with a clear stage. - -## G. Typed diagnostic registry - -Every diagnostic should define: - -- stable code; -- stage; -- affected object ID; -- JSON path; -- user-facing message; -- technical details; -- retryable flag; -- recovery action. - -Recovery actions might include: - -- `REFRESH_CATALOG`; -- `REMOVE_ROUTE_STEP`; -- `CHANGE_ROW_ROOT`; -- `RESELECT_COLUMN`; -- `RECOMPILE`; -- `RETRY_PREVIEW`; -- `CONTACT_OPERATOR`. - -No layer should classify errors by searching `err.Error()`. - -### Diagnostics are a safety net - -Diagnostics are not the primary mechanism for telling the frontend what is -selectable. If the capability snapshot is correct, normal traversal authoring -should not routinely produce unsupported row-grain, stale candidate, invalid -selector, or impossible route errors. - -Failures still occur because of stale state, authorization changes, malformed -clients, query cost, dependency outages, and publication conflicts. Those -failures need one Loom-wide contract. - -### Current Loom gap - -Loom currently has two overlapping mechanisms: - -- Explorer AuthoringError and AuthoringDiagnostic; and -- the more disciplined internal dataframe UserError contract. - -The dataframe contract already provides stable codes, safe details, field -paths, retryability, cause preservation, and normalization without parsing -English text. The Explorer boundary partially bypasses it and sometimes -classifies compiler failures by searching error strings. - -Authoring should use one registry and one adapter. Schema, compiler, planner, -renderer, Arango, and publication errors are normalized once. The original -wrapped cause is retained in server logs only. - -### Wire contract - -For traversal failures, the affected identity should be as specific as -possible: - -- output ID; -- tab ID; -- route occurrence ID; -- edge ID; -- node ID; -- candidate ID; -- emission ID; or -- compilation receipt ID. - -A consistent diagnostic looks like: - -~~~json -{ - "severity": "error", - "stage": "capability|intent|compile|preview|publish", - "code": "INVALID_TRAVERSAL", - "jsonPath": "$.documents[0].routeEdgeIds[2]", - "object": { - "kind": "routeEdge", - "id": "e_..." - }, - "message": "This relationship is no longer available from Observation.", - "details": { - "fromNodeId": "n_observation", - "snapshotToken": "sha256:..." - }, - "retryable": false, - "recoveryAction": "REFRESH_CAPABILITIES", - "requestId": "..." -} -~~~ - -Severity casing must be standardized. The current Go authoring response uses -uppercase values while frontend types expect lowercase values. - -### Ordering for the current frontend - -The current frontend normally displays only the first diagnostic's message and -code. Until that changes, Loom must: - -- sort diagnostics deterministically; -- put the most actionable root cause first; -- make the first message understandable without hidden details; -- never expose a raw Go, Arango, or ClickHouse error as that message; -- attach the request ID to the first diagnostic; and -- avoid returning a generic wrapper when a specific semantic cause exists. - -Loom should still return every diagnostic so the frontend can improve without -another backend redesign. - -### Recovery actions - -Recovery actions describe what state became invalid; Loom should not silently -rewrite user intent. The registry should distinguish at least: - -- REFRESH_CAPABILITIES; -- REMOVE_ROUTE_STEP; -- CHANGE_ROW_ROOT; -- RESELECT_COLUMN; -- RECOMPILE; -- RETRY_PREVIEW; and -- CONTACT_OPERATOR. - -### Error ownership - -Each layer owns its semantic failures: - -- capability compiler: incomplete snapshot, invalid resource or relationship, - schema incompatibility; -- authoring normalizer: malformed occurrence or identity structure; -- compiler: invalid traversal, selector, cardinality, or plan cost; -- receipt store: missing or incompatible receipt; -- preview executor: timeout, cancellation, backend unavailable; -- publication: conflict, materialization failure, activation failure. - -The HTTP adapter maps the normalized error to status and wire diagnostics. It -does not infer semantics from text. - -Suggested status policy: - -- 400 for malformed protocol or JSON; -- 401/403 for authentication or authorization; -- 404 for an absent Explorer, receipt, output, or retained generation; -- 409 for a stale snapshot, revision conflict, or incompatible receipt; -- 422 for well-formed intent violating a declared semantic rule; -- 429 for a cost or concurrency limit; -- 503 for a retryable dependency failure; and -- 500 for an unknown defect with a safe generic message. - -The server log for every failure should include request ID, diagnostic code, -stage, project, Explorer, snapshot or receipt identity, and the full wrapped -cause. The client receives only the safe contract. - -### Diagnostic invariants - -Tests should guarantee: - -- every public failure has a registered code; -- each code has one stable meaning and recovery action; -- no raw backend error reaches the response; -- retryable codes and HTTP statuses agree; -- JSON paths refer to real authoring fields; -- diagnostics are deterministically ordered; -- the first diagnostic remains useful to the current frontend; and -- typed dataframe errors survive the Explorer adapter without collapsing into - INVALID_AUTHORING_INTENT. - -## H. A simple frontend state machine - -The frontend should primarily manage: - -```text -CLEAN -DIRTY -SAVING -VALIDATING -INVALID -COMPILED -PREVIEWING -PUBLISHING -PUBLISHED -CONFLICTED -``` - -A catalog selection should either be executable or visibly disabled. The browser should not need to understand Loom’s schema resolver, semantic planner, physical lowering, Arango, ClickHouse, or release lifecycle. - ---- - -# 13. What to keep, rewrite, and retire - -## Keep - -- generated FHIR schema metadata; -- generated and generic resource extraction; -- graph resource representation; -- immutable generation manifests and atomic activation; -- recipe semantic and physical compiler; -- AQL renderer; -- Arango query client; -- ClickHouse bundle publisher; -- immutable Explorer revisions; -- focused tests around compilation and failure-safe activation. - -## Rewrite or consolidate - -- Explorer authoring HTTP contract; -- capability catalog construction; -- error translation; -- draft ownership; -- compilation receipt lifecycle; -- preview/publication orchestration; -- generation-aware storage resolution; -- field enrichment scheduling. - -## Retire - -- unused legacy Explorer lifecycle/compiler paths; -- separately handwritten Go and TypeScript contract definitions; -- observation catalogs as direct authoring truth; -- endpoints that accept and recompile whole bundles for preview and publish; -- last-writer-wins activation; -- migration execution inside the server pod. - -This can remain a modular monolith. It does not require splitting Loom into a dozen network services. - ---- - -# 14. Recommended sequence - -## Phase 0: Stabilize the existing interface - -- Hide every non-concrete row root. -- Validate catalog candidates through the real selector/compiler logic before advertising them. -- Add `eligible` and `blockedReason`. -- Render all diagnostics, request IDs, stages, and recovery actions. -- Pass request IDs for preview and publication. -- Cancel superseded reconciliation calls. -- Stop silently omitting incomplete visible tables from validation. -- Deploy matching frontend/backend contract versions. - -## Phase 1: Establish a generated shared contract - -- Publish JSON Schema or OpenAPI for authoring documents and responses. -- Generate both Go validation fixtures and TypeScript types. -- Add an explicit protocol version and compiler/schema build digest. -- Fail closed when frontend and Loom do not support the same version. - -## Phase 2: Introduce drafts and compilation receipts - -- Persist drafts with CAS. -- Make compilation side-effect free. -- Preview exclusively by receipt. -- Invalidate receipts when draft or catalog snapshot changes. - -## Phase 3: Make publication asynchronous and transactional - -- Materialize from a receipt. -- Preserve the previous active release on failure. -- Expose publication stage and operation status. -- Make retries idempotent. - -## Phase 4: Separate enrichment from ingestion - -- Keep graph loading bounded. -- Run field profiling asynchronously. -- Use bounded sketches or top-K values rather than exact unbounded distinct sets. -- Never block generation activation on optional UI enrichment. - -## Phase 5: Remove the old architecture - -- Delete inactive V2 lifecycle/compiler code. -- Remove compatibility adapters once the hard cutover is proven. -- Reduce the Explorer store to clear draft, compilation, revision, publication, and active-pointer concepts. - ---- - -# 15. Testing assessment - -The focused Loom test suite passed across the server, Explorer, compiler, publication, catalog, and FHIR-schema packages. - -The targeted frontend checks also passed: - -- 7 Loom API/state tests; -- 2 Explorer contract/runtime tests; -- no-output TypeScript checks for both core and frontend packages. - -Those tests confirm local behavior, not frontend/backend compatibility. Missing coverage includes: - -- every advertised root compiles; -- every advertised relationship extends the route legally; -- every advertised candidate can be selected; -- all backend diagnostics render and identify their target; -- stale snapshot recovery preserves the draft; -- concurrent browser edits produce a conflict rather than overwrite; -- frontend/backend version skew fails clearly; -- preview and publication use the same compiled plan; -- generation activation changes authoring snapshots safely; -- invalid dependency responses such as `null` arrays cannot cross the contract; -- Arango or ClickHouse failures preserve the active Explorer revision. - -A cross-repository conformance suite is more valuable here than adding more isolated unit tests. - ---- - -# Final judgment - -A radical restructuring is warranted, but the target is specific: - -> Loom must stop exposing storage observations and compiler internals as a frontend authoring API. - -The frontend is not fundamentally asking for something unreasonable. It wants to build a dataframe by selecting a row root, walking relationships, choosing columns, previewing, and publishing. Loom currently makes that workflow cross too many partially overlapping abstractions. - -The desired boundary should be: - -```text -The backend advertises only legal actions. -The frontend submits a small versioned intent. -Compilation produces an immutable receipt. -Preview and publish consume that receipt. -Every failure has a stable recovery action. -``` - -Until that boundary exists, fixing individual errors such as `qualification`, stale candidates, null emissions, route continuity, or unsupported selectors will continue to reveal the next failure underneath. diff --git a/docs/PLAN_BACKEND_OWNED_EXPLORER_AUTHORING.md b/docs/PLAN_BACKEND_OWNED_EXPLORER_AUTHORING.md deleted file mode 100644 index a934df09..00000000 --- a/docs/PLAN_BACKEND_OWNED_EXPLORER_AUTHORING.md +++ /dev/null @@ -1,799 +0,0 @@ -# Backend-owned Explorer authoring plan - -## Outcome - -Move Explorer Builder authoring from a browser-owned document model to a -server-owned command model. The browser should describe a user's intent and -render the authoritative result. Loom should create durable identities, apply -defaults, enforce capability and workspace invariants, persist the canonical -draft, and compile that stored draft. - -The first production milestone is deliberately narrow: - -> Starting from a brand-new Explorer with no workspace, selecting an eligible -> catalog node creates a valid table, saves it, compiles it, and returns an -> immutable receipt without the browser constructing an output ID, tab ID, -> route root, or recipe-facing name. - -This removes the current class of failure where `output.id` passes the public -authoring contract but fails later when Loom reuses it as -`recipe.outputs[].name`. - -## Design principles - -1. **Loom owns durable identity.** Output, tab, occurrence, column, emission, - and recipe-facing identifiers are generated or derived by the backend. -2. **The browser sends intent, not canonical documents.** It may keep temporary - component keys and optimistic visual state, but those values never become - persisted identities. -3. **The saved workspace remains the source of truth.** Commands are an input - protocol; they do not become a second durable authoring model. -4. **Every command is capability-scoped and concurrency-safe.** Structural - commands use the exact snapshot token shown to the user, and every mutation - uses draft version/digest compare-and-swap. -5. **Compilation remains receipt-based.** Commands do not weaken the existing - immutable receipt, preview, or publication boundaries. -6. **Invalid intermediate states are prevented at the mutation boundary.** A - client should not be able to construct a document Loom cannot lower. -7. **Migration is incremental.** Existing V2 workspaces, receipts, revisions, - export, preview, and publication continue to work while the UI moves one - operation at a time. - -## Current boundary and failure mode - -Today the browser submits a complete `Workspace` to `PUT /draft` and -`POST /compile` (with `POST /builder` as a compile alias). That makes the -browser responsible for assembling `Document`, `Output`, `Tab`, `RouteNode`, -`Column`, and their cross-references. - -The contract currently accepts any nonblank `output.id`. Compilation copies -that value directly into a recipe output name, whose grammar is stricter: - -```text -^[A-Za-z_][A-Za-z0-9_]*$ -``` - -Consequently, a browser-created UUID, slug containing `-`, label containing a -space, or digit-prefixed value survives authoring validation and fails during -recipe lowering. Debouncing the request only delays the same failure. - -The deeper issue is not just missing validation. A UI implementation should -not have to know recipe identifier rules in order to express “create a table -for this catalog node.” - -## Target request flow - -```text -Browser Loom - | | - | GET /builder | - |--------------------------->| - | workspace:null + catalog | - | + draft version/digest | - |<---------------------------| - | | - | CREATE_TABLE intent | - | nodeId + title + CAS | - |--------------------------->| - | | load/initialize workspace - | | authorize snapshot - | | generate output/tab IDs - | | resolve node to root type - | | validate + canonicalize - | | save draft with CAS - | authoritative workspace | - | + draft version/digest | - |<---------------------------| - | | - | reconcile stored draft | - |--------------------------->| - | immutable receipt | - |<---------------------------| -``` - -The frontend still owns interaction and presentation decisions. It does not -own durable identities, canonical defaults, cross-document referential -integrity, or compiler-facing names. - -## UI compatibility requirement - -This migration must not redesign the Builder UI. Existing controls, selection -behavior, table layout, loading indicators, preview dialog, publish flow, and -diagnostic panel remain visually and behaviorally equivalent. The change is -below the component boundary: - -```text -existing UI event - | - v -frontend Builder action/store - | - v -typed Loom command API - | - v -authoritative workspace response - | - v -existing UI view model -``` - -Do not make React components construct `Workspace`, `Document`, `Output`, -`Tab`, `RouteNode`, or `Column` wire objects. Components continue to report -events such as “root selected,” “candidate checked,” “column hidden,” and -“preview clicked.” A frontend integration layer maps those events to commands -and maps the returned workspace back into the existing view model. - -Temporary component keys are allowed for rendering a pending optimistic row or -table. They are UI-only, must be clearly typed as temporary, and must be -replaced by the backend response. They must never be sent as `outputId`, -`tabId`, `occurrenceId`, or `column`. - -## Frontend API migration - -The frontend implementation target is the existing IDP frontend Builder. The -first frontend task is to identify its current API module, Builder store, and -event handlers; the migration should modify those seams rather than rewrite -components. - -### Typed API client - -Generate request/response types and runtime validators from the updated -Explorer authoring OpenAPI document. The Builder-facing API module should -expose this small surface: - -```ts -interface ExplorerAuthoringApi { - getCapability(project: string, explorerId: string): Promise; - getBuilder(project: string, explorerId: string): Promise; - applyCommands( - project: string, - explorerId: string, - request: ApplyCommandsRequest, - signal?: AbortSignal, - ): Promise; - reconcile( - project: string, - explorerId: string, - request: ReconcileRequest, - signal?: AbortSignal, - ): Promise; - preview( - project: string, - explorerId: string, - request: PreviewRequest, - signal?: AbortSignal, - ): Promise; - publish( - project: string, - explorerId: string, - request: PublishRequest, - signal?: AbortSignal, - ): Promise; -} -``` - -Ordinary Builder code must stop calling `saveWorkspaceDraft`/`PUT /draft`, -`compileWorkspace`/`POST /builder`, or `POST /compile` with locally assembled -workspace content. Keep any whole-document calls in a separately named import -or compatibility module so a normal UI action cannot accidentally use them. - -### Existing UI event to new call mapping - -| Existing user action | Current client behavior to remove | New frontend call | Authoritative frontend update | -| --- | --- | --- | --- | -| Open Builder | GET Builder and sometimes fabricate an empty workspace | `GET /builder` | Store nullable workspace, catalog, snapshot token, draft version/digest | -| Click first/root node | Construct output/document/tab IDs and POST the workspace | `CREATE_TABLE {rootNodeId, title?}` | Replace workspace and select returned `outputId` | -| Add another table | Clone/build a document and tab locally | `CREATE_TABLE {rootNodeId, title?, afterOutputId?}` | Replace workspace; select returned table if current UX does so | -| Delete table | Splice documents/tabs and repair references locally | `DELETE_TABLE {outputId}` | Replace workspace and derive the next selected table from the response | -| Rename table | Patch document and tab titles locally | `RENAME_TABLE {outputId, title}` | Replace workspace while preserving current focus behavior | -| Reorder tables | Rewrite tab order locally | `REORDER_TABLES {outputIds}` | Render backend-normalized order | -| Change root | Rewrite root and clear dependent state locally | `SET_TABLE_ROOT {outputId, rootNodeId}` | Replace workspace and clear selections exactly as returned | -| Add route node | Build route/occurrence IDs locally | `ADD_ROUTE {outputId, parentOccurrenceId, edgeId}` | Expand/select the returned occurrence | -| Remove route node | Delete route subtree and dependent references locally | `REMOVE_ROUTE {outputId, occurrenceId}` | Replace route, columns, filters, and actions from the response | -| Check/add field | Construct a typed/physical column locally | `ADD_COLUMN {outputId, occurrenceId, candidateId, projectionMode?}` | Render the returned backend-created column | -| Uncheck/remove field | Splice column and dependent state locally | `REMOVE_COLUMN {outputId, columnId}` | Replace workspace from the response | -| Change visibility/order/label | Patch presentation object and autosave complete workspace | `UPDATE_COLUMN_PRESENTATION` (batchable) | Replace normalized presentation state | -| Autosave fires | PUT complete workspace | No separate call; every successful command is already persisted | Update saved indicator from returned draft version/digest | -| Preview clicked | Compile current local workspace if receipt is missing, then preview | Reconcile the current stored draft if needed, then `POST /preview` | Cache receipt by draft digest; render existing preview UI | -| Publish clicked | Compile local workspace if needed, then publish | Reconcile the current stored draft if needed, then `POST /publish {receiptId}` | Replace publication/active state from the response | -| Reload/reset | Rehydrate local document edits | `GET /builder` | Replace the Builder store with authoritative server state | - -This table is the frontend work package. A backend command is not considered -delivered until the corresponding existing UI action uses it end to end. - -### Frontend store state - -The frontend store should hold server state and request coordination, not a -second canonical authoring document: - -```ts -interface BuilderServerState { - workspace: Workspace | null; - catalog: CatalogSnapshot; - snapshotToken: string; - draftVersion: number; - draftDigest: string; - pendingCommands: PendingCommand[]; - receiptByDraftDigest: Record; - lastAppliedCommandId?: string; -} -``` - -The workspace is replaced from successful server responses. Do not merge the -response into a locally constructed workspace field by field. Existing UI -selectors may continue to derive selected table, route tree, candidate state, -and presentation from this workspace. - -Component selection state that is not durable—open panels, focus, search text, -scroll position, and temporary optimistic keys—remains local and is reconciled -using backend-returned identities. - -### Command dispatch and ordering - -Mutating commands for one Explorer must be serialized through one frontend -queue because each response advances the draft version and digest: - -1. Read the latest `draftVersion`, `draftDigest`, and `snapshotToken` from the - store when dispatch begins, not when a click handler is created. -2. Assign an ephemeral idempotency `commandId`. This is a request token, not a - domain identity; the backend still creates every durable authoring ID. -3. Send the command with the current CAS values. -4. On success, atomically replace workspace/version/digest and apply the typed - result to ephemeral selection/focus state. -5. Dispatch the next queued command using the returned CAS values. -6. Mark every cached receipt for an older draft digest as stale for preview and - publication purposes; retaining it for request completion is harmless. - -Presentation changes that currently debounce may be coalesced into one command -batch before dispatch. Structural commands should preserve user order and must -not be silently collapsed. - -Reconcile requests may be canceled in the browser when a newer mutation is -queued. Loom may still finish and persist the old immutable receipt; the -frontend ignores it unless its `intentDigest` matches the current draft -digest. This preserves the existing responsive UI without relying on request -timing for correctness. - -### Preview and publish orchestration - -The UI-facing `preview()` action becomes: - -```text -flush pending command queue - -> find receipt for current draftDigest - -> if absent, POST /reconcile for current version/digest - -> verify returned intentDigest == current draftDigest - -> POST /preview with receiptId + selected outputId + limit - -> always clear the existing preview loading state -``` - -The UI-facing `publish()` action uses the same receipt check, then sends only -`{receiptId}` to the existing publish route. It must not publish while commands -are pending or use a receipt associated with an older draft digest. - -This orchestration belongs in the store/action layer so existing Preview and -Publish components keep the same callbacks and visual states. - -### Frontend error behavior - -Use the existing Builder attention/diagnostic surface; this migration does not -require new screens. - -- `DRAFT_CONFLICT`: stop the command queue, GET Builder, replace authoritative - state, retain the rejected high-level command for an explicit retry, and - clear pending indicators. Do not PUT a merged workspace. -- `STALE_CATALOG_SNAPSHOT`: refresh Builder/catalog state. Retry automatically - only if the referenced node/edge/candidate still exists and the user action - has not been superseded; otherwise retain the selection intent and show the - existing diagnostic. -- `INVALID_COMMAND` or a command-specific `422`: leave authoritative workspace - unchanged and bind the diagnostic to the existing control when a JSON path - or entity ID is present. -- `503` or network failure: retain the queued intent and allow retry with the - same `commandId`; do not generate a replacement domain ID or mutate the - canonical workspace locally. -- Canceled reconcile/preview: clear loading state and suppress an error only - when cancellation was caused by a newer local action. -- Older command/reconcile response: ignore it unless its returned draft - version/digest still matches the current store. - -### Capability negotiation and coordinated deployment - -Extend `GET /capability` to advertise command and stored-draft reconcile -support explicitly, for example through `operations: [commands, reconcile]` -and command-family feature flags. The frontend must not discover support by -issuing a request and interpreting `404`. - -Deploy in this order: - -1. Backend ships schemas, command/reconcile routes, and capability flags with - flags disabled or unavailable until ready. -2. Frontend ships the new API/store adapter but continues using the existing - path when the advertised operation is absent during the migration window. -3. Enable the command path for coordinated environments and verify the shared - contract suite. -4. Make commands mandatory for supported browser versions. -5. Remove the browser fallback only after deployment telemetry shows the - supported backend fleet advertises the new operations. - -Fallback is temporary compatibility, not route probing. A partially supported -command family must remain disabled in the UI adapter until every operation -needed by that existing UI workflow is advertised. - -### Shared backend/frontend contract suite - -Check request/response fixtures generated from the OpenAPI contract into a -location consumable by both repositories. At minimum, share fixtures for: - -- nullable blank Builder state; -- successful `CREATE_TABLE` including backend-owned output/tab IDs; -- idempotent replay of the same create command; -- stale draft version conflict; -- stale snapshot rejection; -- add/remove column with backend-owned column identity; -- reconcile of an exact stored draft digest; -- ignored stale reconcile response; and -- preview/publish using the receipt for the current draft. - -The backend runs producer contract tests. The frontend runs consumer tests -through its real API adapter and Builder store, plus its existing component -tests to prove the rendered controls and interactions did not change. - -## Proposed additive API - -Keep the existing V2 namespace and add an operation-oriented surface. The -workspace schema remains V2 and the new routes are additive. - -### Read authoritative Builder state - -Extend `GET /builder` so its response includes the CAS metadata required by -the next command: - -```json -{ - "apiVersion": "loom.calypr.org/explorer-authoring/v2", - "kind": "ExplorerBuilderState", - "lifecycleState": "NEW", - "workspace": null, - "draftVersion": 0, - "draftDigest": "", - "catalog": {} -} -``` - -For a saved draft, return that draft's version and digest. When Builder falls -back to an active revision because no draft body exists, still return the -Explorer owner's current draft CAS values; the first command creates a new -draft from the active workspace against those values. The frontend must never -guess a version based on whether `workspace` is null. - -### Apply commands - -```http -POST /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/commands -Content-Type: application/json -``` - -```json -{ - "commandId": "01K...", - "snapshotToken": "...", - "expectedDraftVersion": 0, - "expectedDraftDigest": "", - "commands": [ - { - "type": "CREATE_TABLE", - "rootNodeId": "catalog-node-id", - "title": "Patients" - } - ] -} -``` - -Response: - -```json -{ - "commandId": "01K...", - "workspace": {}, - "draftVersion": 1, - "draftDigest": "sha256:...", - "results": [ - { - "type": "TABLE_CREATED", - "outputId": "out_6d1936f0...", - "tabId": "tab_6d1936f0..." - } - ], - "diagnostics": [] -} -``` - -Use an array so one user gesture can atomically express related changes. The -backend applies every command or none of them. - -### Reconcile the stored draft - -```http -POST /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/reconcile -Content-Type: application/json -``` - -```json -{ - "snapshotToken": "...", - "draftVersion": 1, - "draftDigest": "sha256:..." -} -``` - -Loom loads the referenced canonical draft and compiles it. The browser no -longer resubmits mutable workspace content to compile. The response is the -existing immutable compilation receipt response, optionally accompanied by -the authoritative workspace metadata used for compilation. - -Preview and publish remain unchanged and continue to accept a receipt ID. - -## Command model - -Implement commands as a closed, tagged union in the OpenAPI schema and as a -pure authoring-domain reducer. Do not put HTTP, storage, recipe, or publication -logic in the reducer. - -Initial command set: - -| Command | Browser declares | Loom owns | -| --- | --- | --- | -| `CREATE_TABLE` | catalog root node and display title | workspace initialization, output ID, tab ID, root route, order, visibility, defaults | -| `DELETE_TABLE` | output ID | tab removal, shared-filter cleanup, ordering normalization | -| `RENAME_TABLE` | output ID and title | synchronized document/tab presentation | -| `REORDER_TABLES` | ordered output IDs | contiguous authoritative tab ordering | -| `SET_TABLE_ROOT` | output ID and catalog node ID | root resolution and clearing/reconciling invalid routes, columns, filters, and actions | -| `ADD_ROUTE` | output ID, parent occurrence ID, catalog edge ID | occurrence ID, relationship/resource resolution, route insertion | -| `REMOVE_ROUTE` | output ID and occurrence ID | subtree, dependent column/filter/action cleanup | -| `ADD_COLUMN` | output ID, occurrence ID, candidate ID, projection intent | typed `Column`, physical column name, label/type/capabilities, presentation defaults | -| `REMOVE_COLUMN` | output ID and column identity | dependent filters/actions/shared bindings cleanup | -| `UPDATE_COLUMN_PRESENTATION` | visibility/order/label/pinning/chart/filter intent | validation and normalized order | -| `SET_FIXED_FILTER` | output ID, column identity, values | typed validation and canonical filter replacement | -| `SET_ACTIONS` | output ID and action intent | valid column references and canonical action representation | - -Start with `CREATE_TABLE`, `DELETE_TABLE`, `ADD_COLUMN`, and `REMOVE_COLUMN`. -They cover the first useful end-to-end Builder without prematurely designing -every presentation operation. - -## Identity policy - -Durable IDs must be opaque to the browser and stable across title changes. -They must not be derived only from user-visible labels. - -For the first implementation, generate recipe-safe IDs directly: - -```text -output: out_ -tab: tab_ -occurrence: occ_ (root remains "base") -column: col_ -``` - -The generator lives in `internal/explorer/authoringv2`, validates its own -output against the downstream recipe/physical-name grammar, and is covered by -property tests. The browser treats every returned ID as an opaque string. - -Use `commandId` as an idempotency key. A retry after a lost response must -return the prior result rather than create a second table. The durable design -should store a small command result keyed by project, Explorer, and command ID. -A deterministic ID derived from that tuple can simplify the first vertical -slice, but it does not replace command replay records for non-create commands. - -Longer term, consider separating opaque authoring identity from recipe-facing -physical names. That is not required for this migration and should not block -backend ownership. - -## Backend structure - -Add these boundaries: - -```text -internal/explorer/authoringv2/ - command_types.go closed command/result types - command_apply.go pure Apply(workspace, snapshot, commands) - identity.go server-owned ID generation - command_errors.go stable command diagnostics and paths - -internal/explorer/ - service.go orchestration: load, initialize, apply, CAS-save - -internal/server/ - explorer_authoring_v2_routes.go - HTTP authorization, strict decoding, response mapping -``` - -The service operation should perform: - -1. Load the Explorer identity and current draft. -2. If no draft exists, load the active workspace or initialize an empty - workspace using server-owned Explorer metadata. -3. Resolve and authorize the exact capability snapshot token. -4. Apply all commands to an in-memory copy. -5. Validate and canonicalize the resulting workspace. -6. Save with expected version and digest. -7. Persist the idempotency result. -8. Return the stored workspace and its new version/digest. - -The existing Arango draft write already performs compare-and-swap. Before -building commands on it, correct the `Store.SaveDraft` interface comment that -currently describes last-write-wins behavior and add adapter conformance tests -so every implementation has the same CAS semantics. - -## Validation ownership - -Even after the frontend stops creating IDs, close the current validation gap: - -- define one reusable backend predicate for recipe-safe output identity; -- apply it in `Document.Validate`, not only after lowering; -- add the same pattern to the OpenAPI schema as documentation and generated - client guidance, not as the source of truth; -- return an authoring diagnostic at - `$.workspace.documents[n].output.id` rather than wrapping it only as - `DOCUMENT_COMPILE_FAILED` at the document level; and -- audit tab, occurrence, and column identity constraints for the same kind of - authoring/compiler mismatch. - -Backend validation remains mandatory even when all known clients use commands. -Import, repository, migration, and older-client paths can still submit complete -documents during the transition. - -## Concurrency and idempotency - -- Require `expectedDraftVersion`; accept `expectedDraftDigest` as an additional - guard. -- Return `409 DRAFT_CONFLICT` with the current version/digest when CAS fails. -- Do not silently apply a command to a different draft revision. -- Do not let the frontend retry by replacing the entire workspace. -- Make exact `commandId` replay return the original result. -- Reject reuse of one `commandId` with different command content. -- Keep command application atomic for command arrays. -- Add a bounded command-result retention policy only after published usage data - exists; correctness comes before automatic cleanup. - -Automatic semantic rebasing can be considered later for operations proven to -commute. It should not be part of the initial cutover. - -## Compilation behavior - -Do not merge mutable authoring and immutable execution concepts: - -- commands mutate and save the draft; -- reconcile compiles one exact stored draft version into an immutable receipt; -- preview executes a receipt; -- publish materializes and activates a receipt. - -The UI may debounce reconcile requests, but correctness must not depend on the -debounce. Concurrent reconciliations remain safe because receipts are -content-addressed. A reconcile request for a stale draft version returns a -conflict instead of compiling newer state than the user intended. - -## Delivery phases - -### Phase 0: close the contract hole - -Backend: - -- Add backend output-ID validation at the authoring boundary. -- Add the OpenAPI pattern and precise diagnostic path. -- Add regression tests showing that authoring validation and recipe validation - accept and reject the same output identifiers. -- Add structured logging of command/type and diagnostic code, never complete - workspace bodies. - -Frontend: - -- Identify and document the existing API module, Builder store, UI event - handlers, and workspace-construction helpers that will be replaced. -- Add generated V2 types/runtime response validation and central error-code - decoding without changing components. -- Add characterization tests for the current UI interactions and rendered - states so the call migration can prove visual/behavioral equivalence. - -This improves correctness and diagnosis but does not by itself fix new-table -creation in the current frontend. - -### Phase 1: blank Explorer to server-created table - -Backend: - -- Add command types, pure reducer, identity generator, and command endpoint. -- Extend `GET /builder` with authoritative draft version/digest and advertise - the new operations through `GET /capability`. -- Implement empty-workspace initialization and `CREATE_TABLE`. -- Resolve `rootNodeId` only through the supplied capability snapshot and - require `RowRootEligible`. -- Create the output, root route, and tab together. -- Save through draft CAS and return the authoritative workspace. -- Add `POST /reconcile` to compile a stored draft version. - -Frontend: - -- Add `applyCommands` and `reconcile` to the typed API client. -- Route the existing first-node-click action through `CREATE_TABLE`; remove - output/tab/document construction from that handler. -- Replace the Builder store workspace/version/digest from the command response - and map the returned output ID into the existing selected-table state. -- Route the existing debounced compile action through stored-draft reconcile. -- Preserve the current loading, success, and Builder-attention UI states. -- Run the shared blank-state/create/reconcile fixtures against a coordinated - backend deployment. - -Exit criterion: the exact blank-config scenario that motivated this plan works -without any frontend-generated durable ID. - -### Phase 2: useful table construction - -Backend: - -- Implement `DELETE_TABLE`, `ADD_COLUMN`, and `REMOVE_COLUMN`. -- Resolve catalog candidates into complete typed columns on the backend. -- Generate physical column identities and compiler-owned defaults on the - backend. -- Cover compile, preview, export, reload, and publish for the resulting table. - -Frontend: - -- Route the existing table-delete and candidate checkbox handlers through - commands without changing their components. -- Remove local typed-column generation and dependent-reference repair. -- Add the serialized command queue and receipt-by-draft-digest cache. -- Change existing Preview and Publish callbacks to flush commands, reconcile - when needed, then call the unchanged receipt endpoints. -- Verify existing preview/publish dialogs and status indicators are unchanged. - -Exit criterion: a user can create, populate, preview, save, reload, and publish -a single table using commands only. - -### Phase 3: routes and multi-table workspaces - -Backend: - -- Implement route add/remove and root replacement with dependency cleanup. -- Implement table reorder/rename and multiple output handling. -- Ensure shared-filter bindings and tab order remain valid after every command. -- Add repeated-edge, self-loop, and route-subtree tests. - -Frontend: - -- Route existing root, route, rename, reorder, create-table, and delete-table - events through their commands. -- Remove occurrence-ID generation, route-tree mutation, tab-order repair, and - cross-table reference cleanup from frontend helpers. -- Preserve expansion, focus, selected table, and route-node selection as - ephemeral UI state keyed by backend-returned identities. - -Exit criterion: all structural Builder actions use server-owned commands. - -### Phase 4: presentation, filters, and actions - -Backend: - -- Move presentation normalization, fixed filters, shared filters, charts, and - file actions behind typed commands. -- Batch high-frequency presentation changes where appropriate. - -Frontend: - -- Route existing presentation/filter/chart/action controls through command - batches while retaining their current debounce behavior. -- Keep local optimistic UI state disposable and reconcile it against every - authoritative response. -- Delete the remaining ordinary-edit whole-workspace serializer and autosave - call path after the command coverage matrix is complete. - -Exit criterion: the browser no longer constructs or patches canonical -workspace objects. - -### Phase 5: compatibility retirement - -Backend and operations: - -- Measure use of full-workspace `PUT /draft`, `POST /compile`, and the - `POST /builder` compile alias by client version and caller class. -- Retain full-document import/export and repository ingestion as explicit - trusted workflows. -- Mark browser-oriented whole-workspace writes deprecated. -- Remove them only after supported frontends use commands and stored artifacts - have passed migration/audit checks. - -Frontend: - -- Remove the temporary legacy browser fallback and capability branch. -- Keep whole-document import/export in an explicitly separate workflow. -- Verify production bundles contain no ordinary Builder call site for - `PUT /draft`, workspace-bearing `POST /builder`, or `POST /compile`. - -## Test strategy - -### Domain tests - -- Every command either produces a fully valid workspace or leaves the input - unchanged. -- Generated identities always satisfy downstream grammars. -- Commands cannot reference stale outputs, occurrences, candidates, or edges. -- Removal commands clean every dependent reference. -- Reordering always produces contiguous stable order. -- Applying a command batch is atomic. - -### Service and storage tests - -- Empty, draft-backed, and active-revision-backed initialization paths. -- Version and digest conflict behavior across all store adapters. -- Exact command replay after a lost response. -- Command-ID reuse with different content. -- Concurrent commands from two tabs. -- No partial draft write when validation or persistence fails. - -### HTTP contract tests - -- Strict tagged-union decoding and unknown-field rejection. -- Authorization and capability-token checks. -- Stable diagnostic code, stage, and JSON path for every rejected command. -- Generated OpenAPI client models match the hand-written domain types. - -### End-to-end tests - -At minimum, automate these paths: - -1. blank Explorer -> select root -> server-created table -> reconcile; -2. add column -> reconcile -> preview; -3. reload -> authoritative IDs unchanged; -4. publish -> active revision -> viewer; -5. lost command response -> retry -> exactly one table; -6. two tabs mutate the same draft -> one succeeds, one receives a conflict; -7. snapshot becomes stale between read and command -> explicit stale-snapshot - response with no draft mutation; and -8. old valid V2 workspace -> command mutation -> reconcile -> publish. - -## Observability and rollout - -Record counters and latency for: - -- command type and outcome; -- validation, capability, conflict, and persistence failures; -- command replay hits; -- draft load/apply/validate/save durations; -- reconcile requests by draft version; -- legacy whole-workspace writes by client version; and -- frontend fallbacks to the legacy path. - -Roll out the command capability behind an advertised authoring feature. The -frontend selects the command path only when the server advertises it. Start -with internal projects, then new Explorers, then existing drafts. Do not infer -support from route failure. - -## Completion criteria - -The migration is complete when: - -- no supported browser generates or persists durable authoring IDs; -- no supported browser submits a complete workspace for ordinary editing; -- all browser structural edits are server-applied, capability-validated, and - CAS-persisted; -- compilation reads a specific stored draft revision instead of accepting - browser-supplied workspace content; -- existing Builder components and user-visible workflows remain unchanged, - with characterization/component tests proving the API/store cutover rather - than a UI rewrite; -- blank-to-first-table, retry, conflict, reload, preview, and publication flows - have end-to-end coverage; -- legacy whole-document endpoints are limited to explicit import, - repository/ETL, or compatibility workflows; and -- telemetry shows no supported-client use of the deprecated browser write path - for one full release window. - -## Explicit non-goals - -- Changing immutable receipt, preview, or publication semantics. -- Persisting recipe expressions, AQL, physical collection names, or - authorization predicates in browser intent. -- Automatic conflict merging in the first release. -- Replacing the canonical workspace with an event log. -- Removing V2 import/export or repository-authored configuration. diff --git a/docs/PLAN_EXPLORER_V2_BRANCHED_TRAVERSAL.md b/docs/PLAN_EXPLORER_V2_BRANCHED_TRAVERSAL.md deleted file mode 100644 index e8a066e4..00000000 --- a/docs/PLAN_EXPLORER_V2_BRANCHED_TRAVERSAL.md +++ /dev/null @@ -1,282 +0,0 @@ -# Explorer V2 branched traversal authoring plan - -## Implementation status (2026-08-27) - -Implemented in Loom: - -- the semantic V2 route tree remains the sole backend route contract; -- sibling and nested routes lower recursively and deterministically; -- columns remain bound to their exact authored occurrence; -- compile and preview are covered as non-active receipt operations; -- Publish remains the only activation operation; and -- Explorer authoring documentation now identifies editable route trees as MVP - functionality and dynamic/pivot candidates as future work. - -The coordinated frontend tree editor is implemented in IDP-Frontend. The -remaining activity is live BForePC Kubernetes acceptance and an intentional -test publication; it is an operational verification step, not missing route -contract code. - -## Outcome - -Make the existing Explorer V2 route-tree contract safe for an interactive -Builder that can add, select, and remove traversal branches. Loom remains the -authority for capability edges, route policy, deterministic compilation, -preview execution, and publication. - -The primary implementation is in `IDP-Frontend`. Loom work is deliberately -limited to closing contract and test gaps around behavior that is already -substantially implemented. - -The coordinated frontend plan is: - -`IDP-Frontend/docs/PLAN_explorer-builder-branched-traversal.md` - -## Product boundary - -This work includes: - -- a finite traversal tree rooted at each output's row resource; -- sibling and nested branches; -- repeated resources represented by distinct occurrence IDs; -- adding columns from ordinary primitive catalog fields at any occurrence; -- local branch removal and its dependent-column cleanup; -- compile and preview against non-active receipts; and -- publication as the only operation that changes the active Explorer. - -This work does not include: - -- pivot-family authoring; -- dynamic column discovery or expansion; -- browser-authored recipe expressions; -- V1 decoding or migration; -- automatic draft persistence; or -- a general graph-query language outside the V2 `RouteNode` tree. - -## Current backend capability - -The semantic V2 contract already has the required shape: - -```text -RouteNode - occurrenceId - resourceType - relationship - children[] -``` - -Loom currently: - -- validates the complete recursive tree and globally unique occurrence IDs; -- resolves every child through an exact capability relationship; -- applies maximum-depth, repeated-edge, and self-loop policies; -- sorts siblings by occurrence ID for deterministic lowering; -- attaches columns to exact occurrences; -- recursively emits sibling `recipe.Traversal` values; -- compiles immutable receipts without changing the active revision; -- previews exact receipts without changing the active revision; and -- materializes and switches the active revision only in Publish. - -The existing BForePC V2 workspace is already a production-relevant branch -fixture. Its Specimen output has sibling Observation and Patient children, and -the Patient occurrence owns `HTAN_PARTICIPANT_ID`. - -## Gaps - -1. Explorer compilation tests cover nested routes but do not prove sibling - branches with columns on both siblings. -2. HTTP lifecycle tests do not prove that a branched compile and preview leave - the active revision unchanged. -3. There is no cross-system branch round trip covering repository workspace, - Builder edit, compile, preview, publish, Builder reload, and Viewer output. -4. Row-grain behavior for two populated, repeated sibling branches is not - asserted at the Explorer contract boundary. -5. Branch-specific route-policy errors are not covered with exact diagnostic - paths. -6. Compatibility-only linear fields and helpers in `authoringv2.Document` can - obscure which route model is authoritative. They must not be used by new - branch code. - -## Invariants - -### Authoring identity - -- `Document.Route` is the only durable route source. -- Every occurrence ID is globally unique within one document. -- Columns reference occurrences by exact occurrence ID. -- Sibling order does not change compilation identity. -- Snapshot-local catalog node, edge, and candidate IDs are never persisted as - the semantic route. -- Relationship and resource type are persisted exactly as the V2 contract - requires. - -### Lifecycle - -- Compile may persist an immutable receipt, but it must not save the workspace - as a draft, create a revision, materialize an output, or switch an active - pointer. -- Preview may execute a receipt, but it must not save a draft, create a - revision, materialize a published output, or switch an active pointer. -- Publish is the only browser operation in this feature that may materialize - and activate the edited workspace. -- A failed Publish retains the previously active Explorer revision. - -### Query behavior - -- Adding one sibling cannot change or remove another sibling. -- Removing one subtree removes only that subtree from the compiled recipe. -- Columns on retained occurrences preserve their names, labels, and - presentation contracts. -- Optional sibling traversal lowering must preserve the declared root row - grain. Any multiplicity behavior must be explicit in the output contract, - not an accidental Cartesian expansion. - -## Backend work packages - -### B1. Canonical branch fixtures - -Add a small semantic V2 fixture with this topology: - -```text -ResearchSubject (base) -├── Patient (patient) -│ └── Condition (patient__condition) -└── Specimen (specimen) -``` - -Attach at least one primitive field column to every occurrence. Use readable -column and occurrence identities that exercise the non-root prefix contract. - -Also load the BForePC Specimen route as a contract fixture where practical: - -```text -Specimen (base) -├── Observation (observation) -└── Patient (patient) -``` - -### B2. Semantic compiler coverage - -Add tests in `internal/explorer/compilation` proving: - -- sibling branches lower to sibling recipe traversals; -- nested children remain attached to the correct sibling; -- columns bind to the correct occurrence and physical prefix; -- reversing authored sibling order produces the same deterministic recipe and - receipt identity; -- duplicate occurrence IDs fail before lowering; -- ambiguous and unavailable relationships return exact route paths; -- maximum depth is evaluated per root-to-leaf path; -- repeated-edge and self-loop decisions match the advertised route policy; and -- removing a sibling changes only that sibling's recipe subtree and emissions. - -Do not add a second route representation or translate through compatibility -`RouteSteps`. - -### B3. Row-grain and physical execution coverage - -Add an execution-level fixture with data on two sibling branches. Assert: - -- the root output remains queryable; -- fields from both siblings appear under their frozen public names; -- missing optional children produce null/empty values according to the current - traversal contract; and -- two populated repeated siblings do not create an undocumented root-row - multiplication. - -If this exposes a dataframer defect, fix the existing recursive traversal -lowering. Do not special-case Explorer routes in the renderer. - -### B4. Receipt lifecycle coverage - -Extend the native V2 HTTP contract tests to execute: - -1. Load an Explorer with an existing active revision. -2. Compile a changed branched workspace. -3. Assert that the active revision, publication metadata, and Viewer contract - are unchanged. -4. Preview the compiled receipt. -5. Assert again that active state is unchanged. -6. Publish the receipt. -7. Assert that materialization succeeds and the new branched revision becomes - active atomically. -8. Reload Builder state and verify the exact route tree and occurrence IDs. - -Also assert that a failed materialization or activation retains the prior -active revision. - -### B5. Diagnostics and capability agreement - -Verify that a frontend can decide legal child additions from one capability -snapshot and receive the same decision from compilation: - -- exact source node; -- exact target node; -- exact relationship label; -- repeated-edge policy; -- self-loop policy; and -- maximum path depth. - -Use existing stable authoring diagnostics. Add a new error code only if no -existing code describes a demonstrated failure. Do not add a branch feature -flag unless mixed-version deployment proves it necessary. - -### B6. Documentation cleanup - -Update `docs/EXPLORER_AUTHORING.md` to state that: - -- ordinary catalog fields and editable route trees are part of the MVP; -- pivot/dynamic candidate families remain future work; -- semantic `RouteNode.children` is authoritative; and -- compile/preview receipts are non-active artifacts. - -Mark compatibility-only linear route helpers as non-authoritative. Remove them -only when existing internal tests no longer require them; their removal is not -a prerequisite for shipping branches. - -## Cross-system acceptance scenario - -Use the checked-in BForePC workspace as the acceptance fixture: - -1. Open the Specimen output. -2. Verify both Observation and Patient sibling occurrences are visible. -3. Select Patient and verify `HTAN_PARTICIPANT_ID` is editable. -4. Add one catalog-proven child under either existing occurrence. -5. Add an ordinary primitive field on the new occurrence. -6. Compile and preview successfully. -7. Verify the active Viewer still serves the old revision. -8. Remove or retain the new branch locally and preview again. -9. Publish the intended tree. -10. Reload Builder and Viewer and verify both sibling branches, labels, and - queryable columns. - -## Verification commands - -At minimum, implementation should run: - -```bash -go test ./internal/explorer/authoringv2 ./internal/explorer/compilation ./internal/server -``` - -Then run the existing Explorer conformance suite and the local authenticated -Kubernetes acceptance flow against the BForePC project. - -## Delivery order - -1. Land backend branch fixtures and failing coverage for the existing contract. -2. Implement the frontend tree model and interactions against that contract. -3. Run compile and preview acceptance without publication. -4. Run publication, reload, and Viewer acceptance. -5. Remove the frontend route-editing gate only when lossless branch hydration, - mutation, and reconstruction tests pass. - -## Exit criteria - -- Loom compiles, previews, publishes, and reloads sibling and nested route - branches without migration or fallback logic. -- Compile and Preview provably leave active Explorer state unchanged. -- Publish is the only operation that changes the active revision. -- BForePC Specimen retains both its Observation and Patient branches through a - full Builder round trip. -- Viewer columns and labels from all retained occurrences match the frozen V2 - output contract. diff --git a/docs/QUICKSTART.md b/docs/QUICKSTART.md index 79a1aa75..999495b3 100644 --- a/docs/QUICKSTART.md +++ b/docs/QUICKSTART.md @@ -24,15 +24,10 @@ This starts: - ArangoDB at [http://127.0.0.1:8529](http://127.0.0.1:8529) -If you also want the research/benchmark databases, the larger stack is: - -- [`experimental/docker/docker-compose.full.yml`](../experimental/docker/docker-compose.full.yml) - ## 2. Generate code and build binaries ```bash -make generate-fhir -make generate-graphql +make generate make build ``` @@ -98,17 +93,17 @@ open http://127.0.0.1:8080/apollo ## 5. Inspect and author an Explorer -Current Builder authoring is the versioned REST V1 publish-only workflow. Use -the project Explorer summaries for selection, then load the selected Explorer's -combined `/authoring/v1/builder` model. Edit its canonical bundle locally and -send only that intent plus its snapshot token to preview or publish. Loom owns -catalog resolution, recipe lowering, compilation, materialization, persistence, -and diagnostics; there is no persisted browser draft or receipt protocol. +Current Builder authoring uses the versioned REST V2 workflow. List project +Explorers, then load the selected Explorer's +`/authoring/v2/builder` state. Save canonical drafts with `PUT /draft`, compile +to an immutable receipt with `POST /compile`, preview that receipt with +`POST /preview`, and activate it only with `POST /publish`. Loom owns catalog +resolution, recipe lowering, compilation, materialization, persistence, and +diagnostics. Read [the Explorer authoring guide](EXPLORER_AUTHORING.md) for the current -request/response shapes, route rules, diagnostics, and the offline default -conversion command. The [V2 migration guide](FRONTEND_EXPLORER_V2_MIGRATION.md) -is retained only for legacy packet and ETL migration context. +request/response behavior and the canonical +[OpenAPI contract](../openapi/openapi.yaml) for exact wire schemas. The workflow is deliberately not a GraphQL introspection query: Loom validates catalog selections, dataset generation, recipe compilation, preview, and diff --git a/docs/README.md b/docs/README.md index 4cb8a703..be1638f2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,19 +1,22 @@ # Loom documentation -Use this page to choose the right document. The current runtime contract is -documented separately from migration notes and implementation plans. +This directory contains current product contracts, architecture references, +and operating guides. Completed plans, migration handoffs, and historical +audits do not belong here. ## Start here - [Quickstart](QUICKSTART.md) — run Loom locally, load sample data, and make a first dataframe request. -- [Explorer authoring](EXPLORER_AUTHORING.md) — current V1 Builder contract, +- [HTTP API and OpenAPI contract](../openapi/README.md) — canonical paths, + schemas, generator configuration, generated server package, and validation + commands. The source specification is + [`openapi/openapi.yaml`](../openapi/openapi.yaml). +- [Explorer authoring](EXPLORER_AUTHORING.md) — current V2 Builder contract, compilation pipeline, receipts, draft/publish behavior, diagnostics, and offline default conversion. - [Explorer compilation architecture](EXPLORER_COMPILATION_ARCHITECTURE.md) — the detailed intent-to-recipe-to-physical-plan-to-AQL path. -- [The Explorer recipe boundary](EXPLORER_RECIPE_BOUNDARY.md) — concrete - examples of the compiler and backend behavior the frontend does not own. - [GraphQL API](GRAPHQL_API.md) — graph, FHIR dataframe, and published-data GraphQL contracts. @@ -25,8 +28,8 @@ documented separately from migration notes and implementation plans. repository, ETL, and developer workflows. - [Dataframer recipe reference](DATAFRAMER_RECIPE_REFERENCE.md) — complete recipe language and deployment runbook. -- [Code generation](CODE_GENERATION.md) — generated sources and regeneration - commands. +- [Code generation](CODE_GENERATION.md) — generated sources, source-of-truth + files, and regeneration commands. - [Compiler performance](COMPILER_PERFORMANCE.md) — benchmark and tuning guidance. - [Dataframe federation](DATAFRAME_FEDERATION.md) — published-data source @@ -34,18 +37,7 @@ documented separately from migration notes and implementation plans. - [Reliability contract](loom-reliability-contract.md) — immutable generations, publication, selectors, and error-state guarantees. -## Migration and planning material +## Frontend contract -- [Backend-owned Explorer authoring plan](PLAN_BACKEND_OWNED_EXPLORER_AUTHORING.md) - — phased migration from browser-authored workspaces to server-owned intent - commands, identities, canonical drafts, and stored-draft reconciliation. -- [Historical Explorer V2 migration](FRONTEND_EXPLORER_V2_MIGRATION.md) — - retained for compatibility and ETL migration context. It is not the current - browser authoring contract; use [Explorer authoring](EXPLORER_AUTHORING.md) - for new Builder work. -- [Frontend facet performance plan](FRONTEND_DATAFRAME_FACET_PERFORMANCE_PLAN.md) - — implementation planning material, not a runtime API reference. - -Documents named `PLAN_*`, `*_PLAN`, or similar are planning artifacts when -present in a checkout. They may explain motivation or rollout history, but the -contract documents above are the source of truth for current behavior. +- [Explorer V2 capability and authoring](frontend/explorer-v2-capability-authoring.md) + — exact Builder wire behavior, receipt lifecycle, diagnostics, and recovery. diff --git a/docs/frontend/explorer-v2-capability-authoring.md b/docs/frontend/explorer-v2-capability-authoring.md index 750b7e63..f6220f93 100644 --- a/docs/frontend/explorer-v2-capability-authoring.md +++ b/docs/frontend/explorer-v2-capability-authoring.md @@ -1,9 +1,8 @@ # Explorer V2 capability and authoring handoff -This handoff matches `internal/explorer/authoringv2` and -`RegisterExplorerAuthoringV2Routes`. The older -`docs/FRONTEND_EXPLORER_V2_MIGRATION.md` describes a superseded -`ExplorerConfigV2` packet and must not be used for Builder HTTP work. +This contract matches `internal/explorer/authoringv2` and the generated Loom +OpenAPI routes. The canonical wire specification is +[`openapi/openapi.yaml`](../../openapi/openapi.yaml). ## Hard cutover @@ -188,47 +187,3 @@ output failure, preview timeout, and `503` unavailable dependency or receipt store. Render the safe server message and preserve the request ID; never classify by matching prose or expose wrapped storage errors. - -## Frontend migration work package - -Target repository: `/Users/peterkor/Desktop/FFNEW/IDP-Frontend`. This is a -handoff only; this task does not edit that repository. - -- [ ] Add a configurable V2 base path and typed calls for capability, builder - GET/POST, compile alias, receipt preview, and receipt publish. -- [ ] Remove V1/GraphQL Builder calls and route probing. A missing V2 route is - a coordinated-deployment failure, not a V1 fallback. -- [ ] Generate TypeScript types/runtime validators from - `schemas/explorer-authoring-v2/openapi.yaml`; - reject unknown fields and preserve `nodeId`, `edgeId`, `candidateId`, - `snapshotToken`, and `receiptId` as opaque strings. -- [ ] Treat `workspace` in Builder state as nullable/omitted; render an empty - Builder from catalog state without fabricating a workspace. -- [ ] Author only `rootNodeId`, ordered `routeSteps`, `selections`, and - presentation. Remove `baseNodeId`, `rowNodeId`, `routeEdgeIds`, and - `routeOccurrences` from frontend state and payloads. -- [ ] Derive/display occurrences from route steps. Preserve explicit - `occurrenceId`s, support omitted IDs and the derived `base`/`step-N` - identities, and do not add a hidden route cap or deduplicate repeated - edges/self-loops. -- [ ] Render only uppercase advertised projection modes. Bind selections by - candidate plus exact occurrence and handle omitted occurrence as tail. -- [ ] Render `rowRootEligible`, `rowGrain`, `populated`, and `documentCount` - from nodes; use candidate suggestion metadata to decide whether to show - a suggestions control, then fetch values through the token-pinned - suggestions route. -- [ ] Fail closed when capability is incomplete/truncated or enrichment is - unavailable; never synthesize fields from observed data. -- [ ] Debounce/cancel Builder POSTs, retain the latest document locally, and - store only server-returned receipt/emission identities. -- [ ] Preview exclusively by `{receiptId, outputId, limit?}` and publish - exclusively by `{receiptId}`. Replace local publication state from the - returned response and retain the prior active view on failure. -- [ ] Handle stale snapshot/receipt diagnostics by retaining edits, refreshing - Builder state, and requiring explicit recompile. -- [ ] Add conformance tests for empty Builder state, zero-hop routes, derived - occurrences, long finite repeated/self-loop routes, omitted selection - occurrences, duplicate selections, uppercase projection modes, stale - tokens, receipt reuse, and fail-closed incomplete catalogs. -- [ ] Run typecheck, unit tests, and production build against a coordinated V2 - Loom deployment; verify no V1 authoring HTTP route is registered. diff --git a/generated/fhir/helpers.go b/generated/fhir/helpers.go index 7e05241c..479b092b 100644 --- a/generated/fhir/helpers.go +++ b/generated/fhir/helpers.go @@ -1,6 +1,4 @@ -// Package fhir contains generated FHIR structs, validation, and graph -// edge extraction. It is generated from schemas/graph-fhir.json; do not -// hand-edit generated files in this package. +// Code generated by cmd/generate/main.go. DO NOT EDIT. package fhir import ( diff --git a/generated/graphql/graph/executor/scalars.go b/generated/graphql/graph/executor/scalars.go deleted file mode 100644 index c3bd4287..00000000 --- a/generated/graphql/graph/executor/scalars.go +++ /dev/null @@ -1,24 +0,0 @@ -package executor - -import ( - "context" - "encoding/json" - "io" - - "github.com/99designs/gqlgen/graphql" - "github.com/vektah/gqlparser/v2/ast" -) - -func MarshalJSON(v json.RawMessage) graphql.Marshaler { - return graphql.WriterFunc(func(w io.Writer) { - _, _ = w.Write(v) - }) -} - -func (ec *executionContext) unmarshalInputJSON(ctx context.Context, v any) (json.RawMessage, error) { - return json.Marshal(v) -} - -func (ec *executionContext) _JSON(ctx context.Context, sel ast.SelectionSet, v json.RawMessage) graphql.Marshaler { - return MarshalJSON(v) -} diff --git a/generated/graphql/graph/executor/schema.generated.go b/generated/graphql/graph/executor/schema.generated.go index 3362e1e1..e3cbdf5a 100644 --- a/generated/graphql/graph/executor/schema.generated.go +++ b/generated/graphql/graph/executor/schema.generated.go @@ -6,6 +6,7 @@ import ( "context" "encoding/json" "errors" + "io" "math" "strconv" "sync/atomic" @@ -16568,3 +16569,20 @@ func (ec *executionContext) unmarshalOFhirTraversalStepInput2ᚕᚖgithubᚗcom } // endregion ***************************** type.gotpl ***************************** + + +// JSON scalar support is appended by cmd/gqlgenfix because gqlgen does not +// emit helpers for the encoding/json.RawMessage model mapping. +func MarshalJSON(v json.RawMessage) graphql.Marshaler { + return graphql.WriterFunc(func(w io.Writer) { + _, _ = w.Write(v) + }) +} + +func (ec *executionContext) unmarshalInputJSON(ctx context.Context, v any) (json.RawMessage, error) { + return json.Marshal(v) +} + +func (ec *executionContext) _JSON(ctx context.Context, sel ast.SelectionSet, v json.RawMessage) graphql.Marshaler { + return MarshalJSON(v) +} diff --git a/generated/loomapi/api.gen.go b/generated/loomapi/api.gen.go new file mode 100644 index 00000000..52c6562d --- /dev/null +++ b/generated/loomapi/api.gen.go @@ -0,0 +1,7538 @@ +// Package loomapi provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.8.0 DO NOT EDIT. +package loomapi + +import ( + "bytes" + "compress/flate" + "context" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/url" + "path" + "strings" + + authoringv2 "github.com/calypr/loom/internal/explorer/authoringv2" + "github.com/getkin/kin-openapi/openapi3" + "github.com/gofiber/fiber/v3" + "github.com/oapi-codegen/runtime" + openapi_types "github.com/oapi-codegen/runtime/types" +) + +// Defines values for APIVersion. +const ( + LoomCalyprOrgexplorerAuthoringv2 APIVersion = "loom.calypr.org/explorer-authoring/v2" +) + +// Valid indicates whether the value is a known member of the APIVersion enum. +func (e APIVersion) Valid() bool { + switch e { + case LoomCalyprOrgexplorerAuthoringv2: + return true + default: + return false + } +} + +// Defines values for AuthoringCapabilityKind. +const ( + ExplorerAuthoringCapabilities AuthoringCapabilityKind = "ExplorerAuthoringCapabilities" +) + +// Valid indicates whether the value is a known member of the AuthoringCapabilityKind enum. +func (e AuthoringCapabilityKind) Valid() bool { + switch e { + case ExplorerAuthoringCapabilities: + return true + default: + return false + } +} + +// Defines values for AuthoringCapabilityOperations. +const ( + Builder AuthoringCapabilityOperations = "builder" + Commands AuthoringCapabilityOperations = "commands" + Compile AuthoringCapabilityOperations = "compile" + Draft AuthoringCapabilityOperations = "draft" + Export AuthoringCapabilityOperations = "export" + Preview AuthoringCapabilityOperations = "preview" + Publish AuthoringCapabilityOperations = "publish" + Reconcile AuthoringCapabilityOperations = "reconcile" + Suggestions AuthoringCapabilityOperations = "suggestions" +) + +// Valid indicates whether the value is a known member of the AuthoringCapabilityOperations enum. +func (e AuthoringCapabilityOperations) Valid() bool { + switch e { + case Builder: + return true + case Commands: + return true + case Compile: + return true + case Draft: + return true + case Export: + return true + case Preview: + return true + case Publish: + return true + case Reconcile: + return true + case Suggestions: + return true + default: + return false + } +} + +// Defines values for AuthoringCommandInitialPresentation. +const ( + CHART AuthoringCommandInitialPresentation = "CHART" + FILTER AuthoringCommandInitialPresentation = "FILTER" + TABLE AuthoringCommandInitialPresentation = "TABLE" +) + +// Valid indicates whether the value is a known member of the AuthoringCommandInitialPresentation enum. +func (e AuthoringCommandInitialPresentation) Valid() bool { + switch e { + case CHART: + return true + case FILTER: + return true + case TABLE: + return true + default: + return false + } +} + +// Defines values for AuthoringCommandType. +const ( + ADDCOLUMN AuthoringCommandType = "ADD_COLUMN" + ADDROUTE AuthoringCommandType = "ADD_ROUTE" + CREATETABLE AuthoringCommandType = "CREATE_TABLE" + DELETETABLE AuthoringCommandType = "DELETE_TABLE" + DUPLICATETABLE AuthoringCommandType = "DUPLICATE_TABLE" + REMOVECOLUMN AuthoringCommandType = "REMOVE_COLUMN" + REMOVEROUTE AuthoringCommandType = "REMOVE_ROUTE" + RENAMETABLE AuthoringCommandType = "RENAME_TABLE" + REORDERTABLES AuthoringCommandType = "REORDER_TABLES" + SETTABLEROOT AuthoringCommandType = "SET_TABLE_ROOT" + UPDATECOLUMN AuthoringCommandType = "UPDATE_COLUMN" +) + +// Valid indicates whether the value is a known member of the AuthoringCommandType enum. +func (e AuthoringCommandType) Valid() bool { + switch e { + case ADDCOLUMN: + return true + case ADDROUTE: + return true + case CREATETABLE: + return true + case DELETETABLE: + return true + case DUPLICATETABLE: + return true + case REMOVECOLUMN: + return true + case REMOVEROUTE: + return true + case RENAMETABLE: + return true + case REORDERTABLES: + return true + case SETTABLEROOT: + return true + case UPDATECOLUMN: + return true + default: + return false + } +} + +// Defines values for BuilderStateKind. +const ( + ExplorerBuilderState BuilderStateKind = "ExplorerBuilderState" +) + +// Valid indicates whether the value is a known member of the BuilderStateKind enum. +func (e BuilderStateKind) Valid() bool { + switch e { + case ExplorerBuilderState: + return true + default: + return false + } +} + +// Defines values for BuilderStateLifecycleState. +const ( + NEW BuilderStateLifecycleState = "NEW" + READY BuilderStateLifecycleState = "READY" +) + +// Valid indicates whether the value is a known member of the BuilderStateLifecycleState enum. +func (e BuilderStateLifecycleState) Valid() bool { + switch e { + case NEW: + return true + case READY: + return true + default: + return false + } +} + +// Defines values for CandidateSearchResponseKind. +const ( + ExplorerBuilderCandidateSuggestions CandidateSearchResponseKind = "ExplorerBuilderCandidateSuggestions" +) + +// Valid indicates whether the value is a known member of the CandidateSearchResponseKind enum. +func (e CandidateSearchResponseKind) Valid() bool { + switch e { + case ExplorerBuilderCandidateSuggestions: + return true + default: + return false + } +} + +// Defines values for CandidateSuggestionsKind. +const ( + ExplorerCandidateSuggestions CandidateSuggestionsKind = "ExplorerCandidateSuggestions" +) + +// Valid indicates whether the value is a known member of the CandidateSuggestionsKind enum. +func (e CandidateSuggestionsKind) Valid() bool { + switch e { + case ExplorerCandidateSuggestions: + return true + default: + return false + } +} + +// Defines values for ColumnSourceKind. +const ( + CodingBySystem ColumnSourceKind = "codingBySystem" + ExtensionByUrl ColumnSourceKind = "extensionByUrl" + Field ColumnSourceKind = "field" + IdentifierBySystem ColumnSourceKind = "identifierBySystem" + ObservationComponentByCode ColumnSourceKind = "observationComponentByCode" + ProjectId ColumnSourceKind = "projectId" +) + +// Valid indicates whether the value is a known member of the ColumnSourceKind enum. +func (e ColumnSourceKind) Valid() bool { + switch e { + case CodingBySystem: + return true + case ExtensionByUrl: + return true + case Field: + return true + case IdentifierBySystem: + return true + case ObservationComponentByCode: + return true + case ProjectId: + return true + default: + return false + } +} + +// Defines values for ColumnSourceProjectionMode. +const ( + ColumnSourceProjectionModeALL ColumnSourceProjectionMode = "ALL" + ColumnSourceProjectionModeDISTINCT ColumnSourceProjectionMode = "DISTINCT" + ColumnSourceProjectionModeFIRST ColumnSourceProjectionMode = "FIRST" + ColumnSourceProjectionModeVALUE ColumnSourceProjectionMode = "VALUE" +) + +// Valid indicates whether the value is a known member of the ColumnSourceProjectionMode enum. +func (e ColumnSourceProjectionMode) Valid() bool { + switch e { + case ColumnSourceProjectionModeALL: + return true + case ColumnSourceProjectionModeDISTINCT: + return true + case ColumnSourceProjectionModeFIRST: + return true + case ColumnSourceProjectionModeVALUE: + return true + default: + return false + } +} + +// Defines values for CommandResultType. +const ( + COLUMNADDED CommandResultType = "COLUMN_ADDED" + ROUTEADDED CommandResultType = "ROUTE_ADDED" + TABLECHANGED CommandResultType = "TABLE_CHANGED" + TABLECREATED CommandResultType = "TABLE_CREATED" +) + +// Valid indicates whether the value is a known member of the CommandResultType enum. +func (e CommandResultType) Valid() bool { + switch e { + case COLUMNADDED: + return true + case ROUTEADDED: + return true + case TABLECHANGED: + return true + case TABLECREATED: + return true + default: + return false + } +} + +// Defines values for CompileResponseKind. +const ( + ExplorerBuilderReceipt CompileResponseKind = "ExplorerBuilderReceipt" +) + +// Valid indicates whether the value is a known member of the CompileResponseKind enum. +func (e CompileResponseKind) Valid() bool { + switch e { + case ExplorerBuilderReceipt: + return true + default: + return false + } +} + +// Defines values for DocumentKind. +const ( + ExplorerBuilderDocument DocumentKind = "ExplorerBuilderDocument" +) + +// Valid indicates whether the value is a known member of the DocumentKind enum. +func (e DocumentKind) Valid() bool { + switch e { + case ExplorerBuilderDocument: + return true + default: + return false + } +} + +// Defines values for PreviewResponseKind. +const ( + ExplorerBuilderPreview PreviewResponseKind = "ExplorerBuilderPreview" +) + +// Valid indicates whether the value is a known member of the PreviewResponseKind enum. +func (e PreviewResponseKind) Valid() bool { + switch e { + case ExplorerBuilderPreview: + return true + default: + return false + } +} + +// Defines values for ProjectionMode. +const ( + ProjectionModeALL ProjectionMode = "ALL" + ProjectionModeARRAY ProjectionMode = "ARRAY" + ProjectionModeDISTINCT ProjectionMode = "DISTINCT" + ProjectionModeDISTINCTARRAY ProjectionMode = "DISTINCT_ARRAY" + ProjectionModeFIRST ProjectionMode = "FIRST" + ProjectionModeSCALAR ProjectionMode = "SCALAR" + ProjectionModeVALUE ProjectionMode = "VALUE" +) + +// Valid indicates whether the value is a known member of the ProjectionMode enum. +func (e ProjectionMode) Valid() bool { + switch e { + case ProjectionModeALL: + return true + case ProjectionModeARRAY: + return true + case ProjectionModeDISTINCT: + return true + case ProjectionModeDISTINCTARRAY: + return true + case ProjectionModeFIRST: + return true + case ProjectionModeSCALAR: + return true + case ProjectionModeVALUE: + return true + default: + return false + } +} + +// Defines values for PublishResponseKind. +const ( + ExplorerBuilderPublication PublishResponseKind = "ExplorerBuilderPublication" +) + +// Valid indicates whether the value is a known member of the PublishResponseKind enum. +func (e PublishResponseKind) Valid() bool { + switch e { + case ExplorerBuilderPublication: + return true + default: + return false + } +} + +// Defines values for TablePresentationCellRenderer. +const ( + TablePresentationCellRendererFileActions TablePresentationCellRenderer = "fileActions" +) + +// Valid indicates whether the value is a known member of the TablePresentationCellRenderer enum. +func (e TablePresentationCellRenderer) Valid() bool { + switch e { + case TablePresentationCellRendererFileActions: + return true + default: + return false + } +} + +// APIVersion defines model for APIVersion. +type APIVersion string + +// Action defines model for Action. +type Action struct { + Columns *[]ActionColumn `json:"columns,omitempty"` + FileName *string `json:"fileName,omitempty"` + Title string `json:"title"` + Type string `json:"type"` +} + +// ActionColumn defines model for ActionColumn. +type ActionColumn struct { + Column string `json:"column"` + ExportHeader *string `json:"exportHeader,omitempty"` +} + +// ApplyCommandsRequest defines model for ApplyCommandsRequest. +type ApplyCommandsRequest struct { + CommandId string `json:"commandId"` + Commands []AuthoringCommand `json:"commands"` + ExpectedDraftDigest *string `json:"expectedDraftDigest,omitempty"` + ExpectedDraftVersion int64 `json:"expectedDraftVersion"` + SnapshotToken string `json:"snapshotToken"` +} + +// ApplyCommandsResponse defines model for ApplyCommandsResponse. +type ApplyCommandsResponse struct { + CommandId string `json:"commandId"` + Diagnostics []Diagnostic `json:"diagnostics"` + DraftDigest string `json:"draftDigest"` + DraftVersion int64 `json:"draftVersion"` + Results []CommandResult `json:"results"` + Workspace Workspace `json:"workspace"` +} + +// AuthoringCapability defines model for AuthoringCapability. +type AuthoringCapability struct { + ApiVersion APIVersion `json:"apiVersion"` + Features AuthoringFeatures `json:"features"` + Kind AuthoringCapabilityKind `json:"kind"` + Operations []AuthoringCapabilityOperations `json:"operations"` + PreviewLimits []int `json:"previewLimits"` +} + +// AuthoringCapabilityKind defines model for AuthoringCapability.Kind. +type AuthoringCapabilityKind string + +// AuthoringCapabilityOperations defines model for AuthoringCapability.Operations. +type AuthoringCapabilityOperations string + +// AuthoringCommand defines model for AuthoringCommand. +type AuthoringCommand struct { + CandidateId *string `json:"candidateId,omitempty"` + Column *string `json:"column,omitempty"` + ColumnValue *Column `json:"columnValue,omitempty"` + EdgeId *string `json:"edgeId,omitempty"` + InitialPresentation *AuthoringCommandInitialPresentation `json:"initialPresentation,omitempty"` + OccurrenceId *string `json:"occurrenceId,omitempty"` + OutputId *string `json:"outputId,omitempty"` + OutputIds *[]string `json:"outputIds,omitempty"` + ParentOccurrenceId *string `json:"parentOccurrenceId,omitempty"` + ProjectionMode *ProjectionMode `json:"projectionMode,omitempty"` + RootNodeId *string `json:"rootNodeId,omitempty"` + SourceOutputId *string `json:"sourceOutputId,omitempty"` + Title *string `json:"title,omitempty"` + Type AuthoringCommandType `json:"type"` +} + +// AuthoringCommandInitialPresentation defines model for AuthoringCommand.InitialPresentation. +type AuthoringCommandInitialPresentation string + +// AuthoringCommandType defines model for AuthoringCommand.Type. +type AuthoringCommandType string + +// AuthoringFeatures defines model for AuthoringFeatures. +type AuthoringFeatures struct { + DeleteExplorer bool `json:"deleteExplorer"` + EmissionCharts bool `json:"emissionCharts"` + EmissionFilters bool `json:"emissionFilters"` + FileActions bool `json:"fileActions"` + FixedFilters bool `json:"fixedFilters"` + SharedFilters bool `json:"sharedFilters"` +} + +// BuilderState defines model for BuilderState. +type BuilderState struct { + ApiVersion APIVersion `json:"apiVersion"` + Catalog Catalog `json:"catalog"` + DraftDigest string `json:"draftDigest"` + DraftVersion int64 `json:"draftVersion"` + Kind BuilderStateKind `json:"kind"` + LifecycleState BuilderStateLifecycleState `json:"lifecycleState"` + Workspace *Workspace `json:"workspace"` +} + +// BuilderStateKind defines model for BuilderState.Kind. +type BuilderStateKind string + +// BuilderStateLifecycleState defines model for BuilderState.LifecycleState. +type BuilderStateLifecycleState string + +// CandidateSearchRequest defines model for CandidateSearchRequest. +type CandidateSearchRequest struct { + NodeId string `json:"nodeId"` + Query *string `json:"query,omitempty"` + SnapshotToken string `json:"snapshotToken"` +} + +// CandidateSearchResponse defines model for CandidateSearchResponse. +type CandidateSearchResponse struct { + ApiVersion APIVersion `json:"apiVersion"` + Candidates []CatalogCandidate `json:"candidates"` + Diagnostics []Diagnostic `json:"diagnostics"` + Kind CandidateSearchResponseKind `json:"kind"` + NodeId string `json:"nodeId"` + SnapshotToken string `json:"snapshotToken"` +} + +// CandidateSearchResponseKind defines model for CandidateSearchResponse.Kind. +type CandidateSearchResponseKind string + +// CandidateSuggestions defines model for CandidateSuggestions. +type CandidateSuggestions struct { + ApiVersion APIVersion `json:"apiVersion"` + CandidateId string `json:"candidateId"` + Complete bool `json:"complete"` + Kind CandidateSuggestionsKind `json:"kind"` + SnapshotToken string `json:"snapshotToken"` + Truncated bool `json:"truncated"` + Values []string `json:"values"` +} + +// CandidateSuggestionsKind defines model for CandidateSuggestions.Kind. +type CandidateSuggestionsKind string + +// Catalog defines model for Catalog. +type Catalog struct { + AuthorizationScopeDigest string `json:"authorizationScopeDigest"` + Candidates []CatalogCandidate `json:"candidates"` + Complete bool `json:"complete"` + Edges []CatalogEdge `json:"edges"` + Generation string `json:"generation"` + Nodes []CatalogNode `json:"nodes"` + ResolvedSchemaDigest *string `json:"resolvedSchemaDigest,omitempty"` + RoutePolicy RoutePolicy `json:"routePolicy"` + SnapshotToken string `json:"snapshotToken"` +} + +// CatalogCandidate defines model for CatalogCandidate. +type CatalogCandidate struct { + CandidateId string `json:"candidateId"` + Chartable bool `json:"chartable"` + DefaultProjectionMode ProjectionMode `json:"defaultProjectionMode"` + FieldPath string `json:"fieldPath"` + Filterable bool `json:"filterable"` + Label string `json:"label"` + LogicalType string `json:"logicalType"` + NodeId string `json:"nodeId"` + ProjectionModes []ProjectionMode `json:"projectionModes"` + Repeated bool `json:"repeated"` +} + +// CatalogEdge defines model for CatalogEdge. +type CatalogEdge struct { + EdgeId string `json:"edgeId"` + FromNodeId string `json:"fromNodeId"` + Label string `json:"label"` + Populated bool `json:"populated"` + ToNodeId string `json:"toNodeId"` +} + +// CatalogNode defines model for CatalogNode. +type CatalogNode struct { + DocumentCount *int64 `json:"documentCount,omitempty"` + NodeId string `json:"nodeId"` + Populated bool `json:"populated"` + ResourceType string `json:"resourceType"` + RowGrain *string `json:"rowGrain,omitempty"` + RowRootEligible bool `json:"rowRootEligible"` +} + +// ChartPresentation defines model for ChartPresentation. +type ChartPresentation struct { + Order *int `json:"order,omitempty"` + Title *string `json:"title,omitempty"` + Type string `json:"type"` +} + +// Column defines model for Column. +type Column struct { + Chart *ChartPresentation `json:"chart,omitempty"` + Column string `json:"column"` + Filter *FilterPresentation `json:"filter,omitempty"` + Label string `json:"label"` + LogicalType *string `json:"logicalType,omitempty"` + OccurrenceId string `json:"occurrenceId"` + Source ColumnSource `json:"source"` + Table *TablePresentation `json:"table,omitempty"` +} + +// ColumnSource defines model for ColumnSource. +type ColumnSource struct { + FieldPath *string `json:"fieldPath,omitempty"` + Kind ColumnSourceKind `json:"kind"` + Match *string `json:"match,omitempty"` + ProjectionMode *ColumnSourceProjectionMode `json:"projectionMode,omitempty"` +} + +// ColumnSourceKind defines model for ColumnSource.Kind. +type ColumnSourceKind string + +// ColumnSourceProjectionMode defines model for ColumnSource.ProjectionMode. +type ColumnSourceProjectionMode string + +// CommandResult defines model for CommandResult. +type CommandResult struct { + Column *string `json:"column,omitempty"` + OccurrenceId *string `json:"occurrenceId,omitempty"` + OutputId *string `json:"outputId,omitempty"` + TabId *string `json:"tabId,omitempty"` + Type CommandResultType `json:"type"` +} + +// CommandResultType defines model for CommandResult.Type. +type CommandResultType string + +// CompileRequest defines model for CompileRequest. +type CompileRequest struct { + SnapshotToken string `json:"snapshotToken"` + Workspace Workspace `json:"workspace"` +} + +// CompileResponse defines model for CompileResponse. +type CompileResponse struct { + ApiVersion APIVersion `json:"apiVersion"` + Builder Workspace `json:"builder"` + CompilerVersion string `json:"compilerVersion"` + Diagnostics []Diagnostic `json:"diagnostics"` + Generation string `json:"generation"` + IntentDigest string `json:"intentDigest"` + Kind CompileResponseKind `json:"kind"` + Outputs []ReceiptOutput `json:"outputs"` + ReceiptId string `json:"receiptId"` + SnapshotToken string `json:"snapshotToken"` +} + +// CompileResponseKind defines model for CompileResponse.Kind. +type CompileResponseKind string + +// ContractColumn defines model for ContractColumn. +type ContractColumn struct { + Chartable bool `json:"chartable"` + Column string `json:"column"` + Filterable bool `json:"filterable"` + Label string `json:"label"` + LogicalType string `json:"logicalType"` +} + +// Diagnostic defines model for Diagnostic. +type Diagnostic struct { + Code string `json:"code"` + Details *map[string]interface{} `json:"details,omitempty"` + JsonPath *string `json:"jsonPath,omitempty"` + Message string `json:"message"` + RequestId *string `json:"requestId,omitempty"` + Severity string `json:"severity"` + Stage string `json:"stage"` +} + +// Document defines model for Document. +type Document struct { + Actions *[]Action `json:"actions,omitempty"` + Columns []Column `json:"columns"` + FixedFilters *[]FixedFilter `json:"fixedFilters,omitempty"` + Kind DocumentKind `json:"kind"` + Output Output `json:"output"` + RootResourceType string `json:"rootResourceType"` + Route RouteNode `json:"route"` +} + +// DocumentKind defines model for Document.Kind. +type DocumentKind string + +// ErrorBody defines model for ErrorBody. +type ErrorBody struct { + Code string `json:"code"` + Diagnostic *Diagnostic `json:"diagnostic,omitempty"` + Message string `json:"message"` + RequestId *string `json:"requestId,omitempty"` + AdditionalProperties map[string]interface{} `json:"-"` +} + +// ErrorResponse defines model for ErrorResponse. +type ErrorResponse struct { + Diagnostics *[]Diagnostic `json:"diagnostics,omitempty"` + Error ErrorBody `json:"error"` +} + +// ExplorerMetadata defines model for ExplorerMetadata. +type ExplorerMetadata struct { + Description *string `json:"description,omitempty"` + Title string `json:"title"` +} + +// FileActions defines model for FileActions. +type FileActions struct { + Actions map[string]string `json:"actions"` + Extensions map[string][]string `json:"extensions"` +} + +// FilterPresentation defines model for FilterPresentation. +type FilterPresentation struct { + Label *string `json:"label,omitempty"` + Order *int `json:"order,omitempty"` +} + +// FixedFilter defines model for FixedFilter. +type FixedFilter struct { + Column string `json:"column"` + Values []string `json:"values"` +} + +// LegacyErrorBody defines model for LegacyErrorBody. +type LegacyErrorBody struct { + Code string `json:"code"` + Message string `json:"message"` + AdditionalProperties map[string]interface{} `json:"-"` +} + +// LegacyErrorResponse Error envelope retained by legacy Explorer and recipe-execution routes. +type LegacyErrorResponse struct { + // Error Either a legacy message string or a structured code/message object, depending on the route. + Error LegacyErrorResponse_Error `json:"error"` + AdditionalProperties map[string]interface{} `json:"-"` +} + +// LegacyErrorResponseError0 defines model for LegacyErrorResponse.Error.0. +type LegacyErrorResponseError0 = string + +// LegacyErrorResponse_Error Either a legacy message string or a structured code/message object, depending on the route. +type LegacyErrorResponse_Error struct { + union json.RawMessage +} + +// Output defines model for Output. +type Output struct { + Id string `json:"id"` + RowLabel *string `json:"rowLabel,omitempty"` + Title string `json:"title"` +} + +// PreviewRequest defines model for PreviewRequest. +type PreviewRequest struct { + Limit *int `json:"limit,omitempty"` + OutputId string `json:"outputId"` + ReceiptId string `json:"receiptId"` +} + +// PreviewResponse defines model for PreviewResponse. +type PreviewResponse struct { + ApiVersion APIVersion `json:"apiVersion"` + Columns []ContractColumn `json:"columns"` + Diagnostics []Diagnostic `json:"diagnostics"` + Kind PreviewResponseKind `json:"kind"` + OutputId string `json:"outputId"` + ReceiptId string `json:"receiptId"` + RowCount int `json:"rowCount"` + Rows []map[string]interface{} `json:"rows"` +} + +// PreviewResponseKind defines model for PreviewResponse.Kind. +type PreviewResponseKind string + +// ProjectionMode defines model for ProjectionMode. +type ProjectionMode string + +// PublicationOutput defines model for PublicationOutput. +type PublicationOutput struct { + MaterializationId string `json:"materializationId"` + OutputId string `json:"outputId"` + State string `json:"state"` +} + +// PublishRequest defines model for PublishRequest. +type PublishRequest struct { + ReceiptId string `json:"receiptId"` +} + +// PublishResponse defines model for PublishResponse. +type PublishResponse struct { + ApiVersion APIVersion `json:"apiVersion"` + Diagnostics []Diagnostic `json:"diagnostics"` + Kind PublishResponseKind `json:"kind"` + Outputs []PublicationOutput `json:"outputs"` + ReceiptId string `json:"receiptId"` + RevisionId string `json:"revisionId"` + State string `json:"state"` +} + +// PublishResponseKind defines model for PublishResponse.Kind. +type PublishResponseKind string + +// RawJSON JSON whose existing shape is preserved losslessly during route cutover. +type RawJSON map[string]interface{} + +// ReceiptOutput defines model for ReceiptOutput. +type ReceiptOutput struct { + Columns []ContractColumn `json:"columns"` + OutputId string `json:"outputId"` + RowGrain string `json:"rowGrain"` + Title string `json:"title"` +} + +// ReconcileRequest defines model for ReconcileRequest. +type ReconcileRequest struct { + DraftDigest string `json:"draftDigest"` + DraftVersion int64 `json:"draftVersion"` + SnapshotToken string `json:"snapshotToken"` +} + +// RouteNode defines model for RouteNode. +type RouteNode struct { + Children *[]RouteNode `json:"children,omitempty"` + OccurrenceId string `json:"occurrenceId"` + Relationship *string `json:"relationship,omitempty"` + ResourceType string `json:"resourceType"` +} + +// RoutePolicy defines model for RoutePolicy. +type RoutePolicy struct { + AllowRepeatedEdges bool `json:"allowRepeatedEdges"` + AllowSelfLoops bool `json:"allowSelfLoops"` + MaxSteps *int `json:"maxSteps,omitempty"` +} + +// SaveDraftRequest defines model for SaveDraftRequest. +type SaveDraftRequest struct { + ExpectedDraftDigest *string `json:"expectedDraftDigest,omitempty"` + ExpectedDraftVersion int64 `json:"expectedDraftVersion"` + SnapshotToken string `json:"snapshotToken"` + Workspace Workspace `json:"workspace"` +} + +// SaveDraftResponse defines model for SaveDraftResponse. +type SaveDraftResponse struct { + DraftDigest string `json:"draftDigest"` + DraftVersion int64 `json:"draftVersion"` + Workspace Workspace `json:"workspace"` +} + +// ServiceErrorBody defines model for ServiceErrorBody. +type ServiceErrorBody struct { + Code string `json:"code"` + Details *map[string]interface{} `json:"details,omitempty"` + Message string `json:"message"` + RequestId *string `json:"requestId,omitempty"` + Retryable *bool `json:"retryable,omitempty"` +} + +// ServiceErrorResponse Stable error envelope emitted by Loom's shared HTTP error mapper and snapshot routes. +type ServiceErrorResponse struct { + Error ServiceErrorBody `json:"error"` +} + +// SharedFilterBinding defines model for SharedFilterBinding. +type SharedFilterBinding struct { + Column string `json:"column"` + OutputId string `json:"outputId"` +} + +// Tab defines model for Tab. +type Tab struct { + Id string `json:"id"` + Order int `json:"order"` + OutputId string `json:"outputId"` + Title string `json:"title"` + Visible bool `json:"visible"` +} + +// TablePresentation defines model for TablePresentation. +type TablePresentation struct { + CellRenderer *TablePresentationCellRenderer `json:"cellRenderer,omitempty"` + Order *int `json:"order,omitempty"` + Pinned *bool `json:"pinned,omitempty"` + Visible *bool `json:"visible,omitempty"` +} + +// TablePresentationCellRenderer defines model for TablePresentation.CellRenderer. +type TablePresentationCellRenderer string + +// Workspace defines model for Workspace. +type Workspace = authoringv2.Workspace + +// ExplorerId defines model for ExplorerId. +type ExplorerId = string + +// Generation defines model for Generation. +type Generation = string + +// Project defines model for Project. +type Project = string + +// Release defines model for Release. +type Release = string + +// ResourceType defines model for ResourceType. +type ResourceType = string + +// AuthoringBadRequest defines model for AuthoringBadRequest. +type AuthoringBadRequest = ErrorResponse + +// AuthoringClientClosedRequest defines model for AuthoringClientClosedRequest. +type AuthoringClientClosedRequest = ErrorResponse + +// AuthoringConflict defines model for AuthoringConflict. +type AuthoringConflict = ErrorResponse + +// AuthoringForbidden defines model for AuthoringForbidden. +type AuthoringForbidden = ErrorResponse + +// AuthoringGatewayTimeout defines model for AuthoringGatewayTimeout. +type AuthoringGatewayTimeout = ErrorResponse + +// AuthoringInternalError defines model for AuthoringInternalError. +type AuthoringInternalError = ErrorResponse + +// AuthoringNotFound defines model for AuthoringNotFound. +type AuthoringNotFound = ErrorResponse + +// AuthoringPayloadTooLarge defines model for AuthoringPayloadTooLarge. +type AuthoringPayloadTooLarge = ErrorResponse + +// AuthoringTooManyRequests defines model for AuthoringTooManyRequests. +type AuthoringTooManyRequests = ErrorResponse + +// AuthoringUnavailable defines model for AuthoringUnavailable. +type AuthoringUnavailable = ErrorResponse + +// AuthoringUnprocessable defines model for AuthoringUnprocessable. +type AuthoringUnprocessable = ErrorResponse + +// GraphQLBadRequest JSON whose existing shape is preserved losslessly during route cutover. +type GraphQLBadRequest = RawJSON + +// GraphQLInternalError JSON whose existing shape is preserved losslessly during route cutover. +type GraphQLInternalError = RawJSON + +// GraphQLUnprocessable JSON whose existing shape is preserved losslessly during route cutover. +type GraphQLUnprocessable = RawJSON + +// LegacyBadRequest Error envelope retained by legacy Explorer and recipe-execution routes. +type LegacyBadRequest = LegacyErrorResponse + +// LegacyConflict Error envelope retained by legacy Explorer and recipe-execution routes. +type LegacyConflict = LegacyErrorResponse + +// LegacyForbidden Error envelope retained by legacy Explorer and recipe-execution routes. +type LegacyForbidden = LegacyErrorResponse + +// LegacyInternalError Error envelope retained by legacy Explorer and recipe-execution routes. +type LegacyInternalError = LegacyErrorResponse + +// LegacyNotFound Error envelope retained by legacy Explorer and recipe-execution routes. +type LegacyNotFound = LegacyErrorResponse + +// LegacyUnavailable Error envelope retained by legacy Explorer and recipe-execution routes. +type LegacyUnavailable = LegacyErrorResponse + +// LegacyUnprocessable Error envelope retained by legacy Explorer and recipe-execution routes. +type LegacyUnprocessable = LegacyErrorResponse + +// ServiceBadRequest Stable error envelope emitted by Loom's shared HTTP error mapper and snapshot routes. +type ServiceBadRequest = ServiceErrorResponse + +// ServiceConflict Stable error envelope emitted by Loom's shared HTTP error mapper and snapshot routes. +type ServiceConflict = ServiceErrorResponse + +// ServiceForbidden Stable error envelope emitted by Loom's shared HTTP error mapper and snapshot routes. +type ServiceForbidden = ServiceErrorResponse + +// ServiceInternalError Stable error envelope emitted by Loom's shared HTTP error mapper and snapshot routes. +type ServiceInternalError = ServiceErrorResponse + +// ServiceNotFound Stable error envelope emitted by Loom's shared HTTP error mapper and snapshot routes. +type ServiceNotFound = ServiceErrorResponse + +// ServiceUnauthorized Stable error envelope emitted by Loom's shared HTTP error mapper and snapshot routes. +type ServiceUnauthorized = ServiceErrorResponse + +// ServiceUnavailable Stable error envelope emitted by Loom's shared HTTP error mapper and snapshot routes. +type ServiceUnavailable = ServiceErrorResponse + +// ServiceUnprocessable Stable error envelope emitted by Loom's shared HTTP error mapper and snapshot routes. +type ServiceUnprocessable = ServiceErrorResponse + +// ServiceUnsupportedMediaType Stable error envelope emitted by Loom's shared HTTP error mapper and snapshot routes. +type ServiceUnsupportedMediaType = ServiceErrorResponse + +// CreateDatasetGenerationMultipartBody defines parameters for CreateDatasetGeneration. +type CreateDatasetGenerationMultipartBody struct { + AuthResourcePath *string `json:"auth_resource_path,omitempty"` + DeferActivation *bool `json:"defer_activation,omitempty"` + File []openapi_types.File `json:"file"` + Generation string `json:"generation"` + Project string `json:"project"` +} + +// ActivateDatasetGenerationParams defines parameters for ActivateDatasetGeneration. +type ActivateDatasetGenerationParams struct { + DataframeExecutionId string `form:"dataframe_execution_id" json:"dataframe_execution_id"` + AuthResourcePath *string `form:"auth_resource_path,omitempty" json:"auth_resource_path,omitempty"` +} + +// PublishRepositoryExplorerConfigParams defines parameters for PublishRepositoryExplorerConfig. +type PublishRepositoryExplorerConfigParams struct { + AuthResourcePath *string `form:"auth_resource_path,omitempty" json:"auth_resource_path,omitempty"` + XLoomSourceCommit string `json:"X-Loom-Source-Commit"` +} + +// UploadSnapshotResourceParams defines parameters for UploadSnapshotResource. +type UploadSnapshotResourceParams struct { + XContentSHA256 *string `json:"X-Content-SHA256,omitempty"` +} + +// UploadProjectResourceMultipartBody defines parameters for UploadProjectResource. +type UploadProjectResourceMultipartBody struct { + AuthResourcePath *string `json:"auth_resource_path,omitempty"` + File openapi_types.File `json:"file"` +} + +// UploadRawNDJSONParams defines parameters for UploadRawNDJSON. +type UploadRawNDJSONParams struct { + Project *string `form:"project,omitempty" json:"project,omitempty"` + Generation *string `form:"generation,omitempty" json:"generation,omitempty"` + AuthResourcePath *string `form:"auth_resource_path,omitempty" json:"auth_resource_path,omitempty"` +} + +// CreateDatasetGenerationMultipartRequestBody defines body for CreateDatasetGeneration for multipart/form-data ContentType. +type CreateDatasetGenerationMultipartRequestBody CreateDatasetGenerationMultipartBody + +// CreateExplorerJSONRequestBody defines body for CreateExplorer for application/json ContentType. +type CreateExplorerJSONRequestBody = RawJSON + +// CompileExplorerBuilderJSONRequestBody defines body for CompileExplorerBuilder for application/json ContentType. +type CompileExplorerBuilderJSONRequestBody = CompileRequest + +// ApplyExplorerBuilderCommandsJSONRequestBody defines body for ApplyExplorerBuilderCommands for application/json ContentType. +type ApplyExplorerBuilderCommandsJSONRequestBody = ApplyCommandsRequest + +// CompileExplorerJSONRequestBody defines body for CompileExplorer for application/json ContentType. +type CompileExplorerJSONRequestBody = CompileRequest + +// SaveExplorerDraftJSONRequestBody defines body for SaveExplorerDraft for application/json ContentType. +type SaveExplorerDraftJSONRequestBody = SaveDraftRequest + +// PreviewExplorerJSONRequestBody defines body for PreviewExplorer for application/json ContentType. +type PreviewExplorerJSONRequestBody = PreviewRequest + +// PublishExplorerJSONRequestBody defines body for PublishExplorer for application/json ContentType. +type PublishExplorerJSONRequestBody = PublishRequest + +// ReconcileExplorerBuilderJSONRequestBody defines body for ReconcileExplorerBuilder for application/json ContentType. +type ReconcileExplorerBuilderJSONRequestBody = ReconcileRequest + +// SearchExplorerCandidatesJSONRequestBody defines body for SearchExplorerCandidates for application/json ContentType. +type SearchExplorerCandidatesJSONRequestBody = CandidateSearchRequest + +// CreateSnapshotJSONRequestBody defines body for CreateSnapshot for application/json ContentType. +type CreateSnapshotJSONRequestBody = RawJSON + +// PublishRepositoryExplorerConfigJSONRequestBody defines body for PublishRepositoryExplorerConfig for application/json ContentType. +type PublishRepositoryExplorerConfigJSONRequestBody = Workspace + +// CreateReleaseJSONRequestBody defines body for CreateRelease for application/json ContentType. +type CreateReleaseJSONRequestBody = RawJSON + +// ActivateReleaseCompatibilityJSONRequestBody defines body for ActivateReleaseCompatibility for application/json ContentType. +// +// Deprecated: this type has been marked as deprecated upstream, but no `x-deprecated-reason` was set +type ActivateReleaseCompatibilityJSONRequestBody = RawJSON + +// ActivateReleaseJSONRequestBody defines body for ActivateRelease for application/json ContentType. +type ActivateReleaseJSONRequestBody = RawJSON + +// UploadProjectResourceMultipartRequestBody defines body for UploadProjectResource for multipart/form-data ContentType. +type UploadProjectResourceMultipartRequestBody UploadProjectResourceMultipartBody + +// ExecuteDataframeGraphQLJSONRequestBody defines body for ExecuteDataframeGraphQL for application/json ContentType. +type ExecuteDataframeGraphQLJSONRequestBody = RawJSON + +// ExecuteGraphQLJSONRequestBody defines body for ExecuteGraphQL for application/json ContentType. +type ExecuteGraphQLJSONRequestBody = RawJSON + +// Getter for additional properties for ErrorBody. Returns the specified +// element and whether it was found +func (a ErrorBody) Get(fieldName string) (value interface{}, found bool) { + if a.AdditionalProperties != nil { + value, found = a.AdditionalProperties[fieldName] + } + return +} + +// Setter for additional properties for ErrorBody +func (a *ErrorBody) Set(fieldName string, value interface{}) { + if a.AdditionalProperties == nil { + a.AdditionalProperties = make(map[string]interface{}) + } + a.AdditionalProperties[fieldName] = value +} + +// Override default JSON handling for ErrorBody to handle AdditionalProperties +func (a *ErrorBody) UnmarshalJSON(b []byte) error { + object := make(map[string]json.RawMessage) + err := json.Unmarshal(b, &object) + if err != nil { + return err + } + + if raw, found := object["code"]; found { + err = json.Unmarshal(raw, &a.Code) + if err != nil { + return fmt.Errorf("error reading 'code': %w", err) + } + delete(object, "code") + } + + if raw, found := object["diagnostic"]; found { + err = json.Unmarshal(raw, &a.Diagnostic) + if err != nil { + return fmt.Errorf("error reading 'diagnostic': %w", err) + } + delete(object, "diagnostic") + } + + if raw, found := object["message"]; found { + err = json.Unmarshal(raw, &a.Message) + if err != nil { + return fmt.Errorf("error reading 'message': %w", err) + } + delete(object, "message") + } + + if raw, found := object["requestId"]; found { + err = json.Unmarshal(raw, &a.RequestId) + if err != nil { + return fmt.Errorf("error reading 'requestId': %w", err) + } + delete(object, "requestId") + } + + if len(object) != 0 { + a.AdditionalProperties = make(map[string]interface{}) + for fieldName, fieldBuf := range object { + var fieldVal interface{} + err := json.Unmarshal(fieldBuf, &fieldVal) + if err != nil { + return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err) + } + a.AdditionalProperties[fieldName] = fieldVal + } + } + return nil +} + +// Override default JSON handling for ErrorBody to handle AdditionalProperties +func (a ErrorBody) MarshalJSON() ([]byte, error) { + var err error + object := make(map[string]json.RawMessage) + + object["code"], err = json.Marshal(a.Code) + if err != nil { + return nil, fmt.Errorf("error marshaling 'code': %w", err) + } + + if a.Diagnostic != nil { + object["diagnostic"], err = json.Marshal(a.Diagnostic) + if err != nil { + return nil, fmt.Errorf("error marshaling 'diagnostic': %w", err) + } + } + + object["message"], err = json.Marshal(a.Message) + if err != nil { + return nil, fmt.Errorf("error marshaling 'message': %w", err) + } + + if a.RequestId != nil { + object["requestId"], err = json.Marshal(a.RequestId) + if err != nil { + return nil, fmt.Errorf("error marshaling 'requestId': %w", err) + } + } + + for fieldName, field := range a.AdditionalProperties { + object[fieldName], err = json.Marshal(field) + if err != nil { + return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err) + } + } + return json.Marshal(object) +} + +// Getter for additional properties for LegacyErrorBody. Returns the specified +// element and whether it was found +func (a LegacyErrorBody) Get(fieldName string) (value interface{}, found bool) { + if a.AdditionalProperties != nil { + value, found = a.AdditionalProperties[fieldName] + } + return +} + +// Setter for additional properties for LegacyErrorBody +func (a *LegacyErrorBody) Set(fieldName string, value interface{}) { + if a.AdditionalProperties == nil { + a.AdditionalProperties = make(map[string]interface{}) + } + a.AdditionalProperties[fieldName] = value +} + +// Override default JSON handling for LegacyErrorBody to handle AdditionalProperties +func (a *LegacyErrorBody) UnmarshalJSON(b []byte) error { + object := make(map[string]json.RawMessage) + err := json.Unmarshal(b, &object) + if err != nil { + return err + } + + if raw, found := object["code"]; found { + err = json.Unmarshal(raw, &a.Code) + if err != nil { + return fmt.Errorf("error reading 'code': %w", err) + } + delete(object, "code") + } + + if raw, found := object["message"]; found { + err = json.Unmarshal(raw, &a.Message) + if err != nil { + return fmt.Errorf("error reading 'message': %w", err) + } + delete(object, "message") + } + + if len(object) != 0 { + a.AdditionalProperties = make(map[string]interface{}) + for fieldName, fieldBuf := range object { + var fieldVal interface{} + err := json.Unmarshal(fieldBuf, &fieldVal) + if err != nil { + return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err) + } + a.AdditionalProperties[fieldName] = fieldVal + } + } + return nil +} + +// Override default JSON handling for LegacyErrorBody to handle AdditionalProperties +func (a LegacyErrorBody) MarshalJSON() ([]byte, error) { + var err error + object := make(map[string]json.RawMessage) + + object["code"], err = json.Marshal(a.Code) + if err != nil { + return nil, fmt.Errorf("error marshaling 'code': %w", err) + } + + object["message"], err = json.Marshal(a.Message) + if err != nil { + return nil, fmt.Errorf("error marshaling 'message': %w", err) + } + + for fieldName, field := range a.AdditionalProperties { + object[fieldName], err = json.Marshal(field) + if err != nil { + return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err) + } + } + return json.Marshal(object) +} + +// Getter for additional properties for LegacyErrorResponse. Returns the specified +// element and whether it was found +func (a LegacyErrorResponse) Get(fieldName string) (value interface{}, found bool) { + if a.AdditionalProperties != nil { + value, found = a.AdditionalProperties[fieldName] + } + return +} + +// Setter for additional properties for LegacyErrorResponse +func (a *LegacyErrorResponse) Set(fieldName string, value interface{}) { + if a.AdditionalProperties == nil { + a.AdditionalProperties = make(map[string]interface{}) + } + a.AdditionalProperties[fieldName] = value +} + +// Override default JSON handling for LegacyErrorResponse to handle AdditionalProperties +func (a *LegacyErrorResponse) UnmarshalJSON(b []byte) error { + object := make(map[string]json.RawMessage) + err := json.Unmarshal(b, &object) + if err != nil { + return err + } + + if raw, found := object["error"]; found { + err = json.Unmarshal(raw, &a.Error) + if err != nil { + return fmt.Errorf("error reading 'error': %w", err) + } + delete(object, "error") + } + + if len(object) != 0 { + a.AdditionalProperties = make(map[string]interface{}) + for fieldName, fieldBuf := range object { + var fieldVal interface{} + err := json.Unmarshal(fieldBuf, &fieldVal) + if err != nil { + return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err) + } + a.AdditionalProperties[fieldName] = fieldVal + } + } + return nil +} + +// Override default JSON handling for LegacyErrorResponse to handle AdditionalProperties +func (a LegacyErrorResponse) MarshalJSON() ([]byte, error) { + var err error + object := make(map[string]json.RawMessage) + + object["error"], err = json.Marshal(a.Error) + if err != nil { + return nil, fmt.Errorf("error marshaling 'error': %w", err) + } + + for fieldName, field := range a.AdditionalProperties { + object[fieldName], err = json.Marshal(field) + if err != nil { + return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err) + } + } + return json.Marshal(object) +} + +// AsLegacyErrorResponseError0 returns the union data inside the LegacyErrorResponse_Error as a LegacyErrorResponseError0 +func (t LegacyErrorResponse_Error) AsLegacyErrorResponseError0() (LegacyErrorResponseError0, error) { + var body LegacyErrorResponseError0 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromLegacyErrorResponseError0 overwrites any union data inside the LegacyErrorResponse_Error as the provided LegacyErrorResponseError0 +func (t *LegacyErrorResponse_Error) FromLegacyErrorResponseError0(v LegacyErrorResponseError0) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeLegacyErrorResponseError0 performs a merge with any union data inside the LegacyErrorResponse_Error, using the provided LegacyErrorResponseError0 +func (t *LegacyErrorResponse_Error) MergeLegacyErrorResponseError0(v LegacyErrorResponseError0) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsLegacyErrorBody returns the union data inside the LegacyErrorResponse_Error as a LegacyErrorBody +func (t LegacyErrorResponse_Error) AsLegacyErrorBody() (LegacyErrorBody, error) { + var body LegacyErrorBody + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromLegacyErrorBody overwrites any union data inside the LegacyErrorResponse_Error as the provided LegacyErrorBody +func (t *LegacyErrorResponse_Error) FromLegacyErrorBody(v LegacyErrorBody) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeLegacyErrorBody performs a merge with any union data inside the LegacyErrorResponse_Error, using the provided LegacyErrorBody +func (t *LegacyErrorResponse_Error) MergeLegacyErrorBody(v LegacyErrorBody) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +func (t LegacyErrorResponse_Error) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *LegacyErrorResponse_Error) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + +// ServerInterface represents all server handlers. +type ServerInterface interface { + // GetRecipeExecution Read public metadata for a dataframe recipe execution. + // (GET /api/v1/dataframe/recipe-executions/{id}) + GetRecipeExecution(c fiber.Ctx, id string) error + // CreateDatasetGeneration Upload a multipart dataset generation. + // (POST /api/v1/datasets/{project}/generations/{generation}) + CreateDatasetGeneration(c fiber.Ctx, project Project, generation Generation) error + // ActivateDatasetGeneration Activate a generation after dataframe publication. + // (POST /api/v1/datasets/{project}/generations/{generation}/activate) + ActivateDatasetGeneration(c fiber.Ctx, project Project, generation Generation, params ActivateDatasetGenerationParams) error + // GetRepositoryExplorerConfig Read the active repository-owned Explorer config. + // (GET /api/v1/projects/{project}/explorer-config) + GetRepositoryExplorerConfig(c fiber.Ctx, project Project) error + // ListExplorers List Explorer summaries for a project. + // (GET /api/v1/projects/{project}/explorers) + ListExplorers(c fiber.Ctx, project Project) error + // CreateExplorer Create an interactive Explorer. + // (POST /api/v1/projects/{project}/explorers) + CreateExplorer(c fiber.Ctx, project Project) error + // GetExplorer Read an Explorer's active runtime projection. + // (GET /api/v1/projects/{project}/explorers/{explorerId}) + GetExplorer(c fiber.Ctx, project Project, explorerId ExplorerId) error + + // (GET /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/builder) + GetExplorerBuilder(c fiber.Ctx, project Project, explorerId ExplorerId) error + + // (POST /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/builder) + CompileExplorerBuilder(c fiber.Ctx, project Project, explorerId ExplorerId) error + + // (GET /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/capabilities/{snapshotToken}/candidates/{candidateId}/suggestions) + GetExplorerCandidateSuggestions(c fiber.Ctx, project Project, explorerId ExplorerId, snapshotToken string, candidateId string) error + + // (GET /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/capability) + GetExplorerAuthoringCapability(c fiber.Ctx, project Project, explorerId ExplorerId) error + + // (POST /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/commands) + ApplyExplorerBuilderCommands(c fiber.Ctx, project Project, explorerId ExplorerId) error + + // (POST /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/compile) + CompileExplorer(c fiber.Ctx, project Project, explorerId ExplorerId) error + + // (PUT /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/draft) + SaveExplorerDraft(c fiber.Ctx, project Project, explorerId ExplorerId) error + + // (GET /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/export) + ExportExplorerWorkspace(c fiber.Ctx, project Project, explorerId ExplorerId) error + + // (POST /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/preview) + PreviewExplorer(c fiber.Ctx, project Project, explorerId ExplorerId) error + + // (POST /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/publish) + PublishExplorer(c fiber.Ctx, project Project, explorerId ExplorerId) error + + // (POST /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/reconcile) + ReconcileExplorerBuilder(c fiber.Ctx, project Project, explorerId ExplorerId) error + + // (POST /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/suggestions) + SearchExplorerCandidates(c fiber.Ctx, project Project, explorerId ExplorerId) error + // AbortSnapshot Abort a generation snapshot. + // (DELETE /api/v1/projects/{project}/generations/{generation}) + AbortSnapshot(c fiber.Ctx, project Project, generation Generation) error + // GetSnapshot Read generation snapshot status. + // (GET /api/v1/projects/{project}/generations/{generation}) + GetSnapshot(c fiber.Ctx, project Project, generation Generation) error + // CreateSnapshot Create or resume an immutable generation snapshot. + // (POST /api/v1/projects/{project}/generations/{generation}) + CreateSnapshot(c fiber.Ctx, project Project, generation Generation) error + // PublishRepositoryExplorerConfig Compile and publish a repository-owned Explorer workspace. + // (POST /api/v1/projects/{project}/generations/{generation}/explorer-config) + PublishRepositoryExplorerConfig(c fiber.Ctx, project Project, generation Generation, params PublishRepositoryExplorerConfigParams) error + // FinalizeSnapshot Validate and finalize an immutable generation snapshot. + // (POST /api/v1/projects/{project}/generations/{generation}/finalize) + FinalizeSnapshot(c fiber.Ctx, project Project, generation Generation) error + // UploadSnapshotResource Stream one resource type into an immutable snapshot. + // (PUT /api/v1/projects/{project}/generations/{generation}/resources/{resourceType}) + UploadSnapshotResource(c fiber.Ctx, project Project, generation Generation, resourceType ResourceType, params UploadSnapshotResourceParams) error + // CreateRelease Create a durable project release candidate. + // (POST /api/v1/projects/{project}/releases) + CreateRelease(c fiber.Ctx, project Project) error + // ActivateReleaseCompatibility Create and activate a release in one legacy operation. + // (POST /api/v1/projects/{project}/releases/activate) + // + // Deprecated: this operation has been marked as deprecated upstream, but no `x-deprecated-reason` was set + ActivateReleaseCompatibility(c fiber.Ctx, project Project) error + // GetActiveRelease Read the active project release. + // (GET /api/v1/projects/{project}/releases/active) + GetActiveRelease(c fiber.Ctx, project Project) error + // GetRelease Read a project release by ID. + // (GET /api/v1/projects/{project}/releases/{release}) + GetRelease(c fiber.Ctx, project Project, release Release) error + // ActivateRelease Activate an existing durable release. + // (POST /api/v1/projects/{project}/releases/{release}/activate) + ActivateRelease(c fiber.Ctx, project Project, release Release) error + // UploadProjectResource Upload one multipart NDJSON resource file. + // (PUT /api/v1/projects/{project}/resources/{resourceType}) + UploadProjectResource(c fiber.Ctx, project Project, resourceType ResourceType) error + // UploadRawNDJSON Stream raw NDJSON into a generation. + // (PUT /api/v1/raw) + UploadRawNDJSON(c fiber.Ctx, params UploadRawNDJSONParams) error + // GetApolloSandbox Render the Apollo GraphQL sandbox. + // (GET /apollo) + GetApolloSandbox(c fiber.Ctx) error + // ExecuteDataframeGraphQL Execute a dataframe GraphQL operation. + // (POST /graphql/dataframe) + ExecuteDataframeGraphQL(c fiber.Ctx) error + // GetGraphQLPlayground Render the GraphQL playground. + // (GET /graphql/graph) + GetGraphQLPlayground(c fiber.Ctx) error + // ExecuteGraphQL Execute a graph or FHIR GraphQL operation. + // (POST /graphql/graph) + ExecuteGraphQL(c fiber.Ctx) error + // GetHealth Report cached core and dataframe health. + // (GET /health) + GetHealth(c fiber.Ctx) error + // GetLiveness Report process liveness without checking dependencies. + // (GET /livez) + GetLiveness(c fiber.Ctx) error + // GetReadiness Report whether required dependencies are ready. + // (GET /readyz) + GetReadiness(c fiber.Ctx) error +} + +// ServerInterfaceWrapper converts contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface + HandlerMiddlewares []HandlerMiddlewareFunc +} + +type MiddlewareFunc fiber.Handler +type HandlerMiddlewareFunc func(c fiber.Ctx, next fiber.Handler) error + +// GetRecipeExecution operation middleware +func (siw *ServerInterfaceWrapper) GetRecipeExecution(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "id" ------------- + var id string + + err = runtime.BindStyledParameterWithOptions("simple", "id", c.Params("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter id: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.GetRecipeExecution(c, id) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// CreateDatasetGeneration operation middleware +func (siw *ServerInterfaceWrapper) CreateDatasetGeneration(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "generation" ------------- + var generation Generation + + err = runtime.BindStyledParameterWithOptions("simple", "generation", c.Params("generation"), &generation, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter generation: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.CreateDatasetGeneration(c, project, generation) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// ActivateDatasetGeneration operation middleware +func (siw *ServerInterfaceWrapper) ActivateDatasetGeneration(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "generation" ------------- + var generation Generation + + err = runtime.BindStyledParameterWithOptions("simple", "generation", c.Params("generation"), &generation, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter generation: %w", err).Error()) + } + + // Parameter object where we will unmarshal all parameters from the context + var params ActivateDatasetGenerationParams + + var query url.Values + query, err = url.ParseQuery(string(c.Request().URI().QueryString())) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for query string: %w", err).Error()) + } + + // ------------- Required query parameter "dataframe_execution_id" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, true, "dataframe_execution_id", query, ¶ms.DataframeExecutionId, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter dataframe_execution_id: %w", err).Error()) + } + + // ------------- Optional query parameter "auth_resource_path" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "auth_resource_path", query, ¶ms.AuthResourcePath, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter auth_resource_path: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.ActivateDatasetGeneration(c, project, generation, params) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// GetRepositoryExplorerConfig operation middleware +func (siw *ServerInterfaceWrapper) GetRepositoryExplorerConfig(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.GetRepositoryExplorerConfig(c, project) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// ListExplorers operation middleware +func (siw *ServerInterfaceWrapper) ListExplorers(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.ListExplorers(c, project) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// CreateExplorer operation middleware +func (siw *ServerInterfaceWrapper) CreateExplorer(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.CreateExplorer(c, project) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// GetExplorer operation middleware +func (siw *ServerInterfaceWrapper) GetExplorer(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "explorerId" ------------- + var explorerId ExplorerId + + err = runtime.BindStyledParameterWithOptions("simple", "explorerId", c.Params("explorerId"), &explorerId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter explorerId: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.GetExplorer(c, project, explorerId) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// GetExplorerBuilder operation middleware +func (siw *ServerInterfaceWrapper) GetExplorerBuilder(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "explorerId" ------------- + var explorerId ExplorerId + + err = runtime.BindStyledParameterWithOptions("simple", "explorerId", c.Params("explorerId"), &explorerId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter explorerId: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.GetExplorerBuilder(c, project, explorerId) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// CompileExplorerBuilder operation middleware +func (siw *ServerInterfaceWrapper) CompileExplorerBuilder(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "explorerId" ------------- + var explorerId ExplorerId + + err = runtime.BindStyledParameterWithOptions("simple", "explorerId", c.Params("explorerId"), &explorerId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter explorerId: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.CompileExplorerBuilder(c, project, explorerId) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// GetExplorerCandidateSuggestions operation middleware +func (siw *ServerInterfaceWrapper) GetExplorerCandidateSuggestions(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "explorerId" ------------- + var explorerId ExplorerId + + err = runtime.BindStyledParameterWithOptions("simple", "explorerId", c.Params("explorerId"), &explorerId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter explorerId: %w", err).Error()) + } + + // ------------- Path parameter "snapshotToken" ------------- + var snapshotToken string + + err = runtime.BindStyledParameterWithOptions("simple", "snapshotToken", c.Params("snapshotToken"), &snapshotToken, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter snapshotToken: %w", err).Error()) + } + + // ------------- Path parameter "candidateId" ------------- + var candidateId string + + err = runtime.BindStyledParameterWithOptions("simple", "candidateId", c.Params("candidateId"), &candidateId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter candidateId: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.GetExplorerCandidateSuggestions(c, project, explorerId, snapshotToken, candidateId) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// GetExplorerAuthoringCapability operation middleware +func (siw *ServerInterfaceWrapper) GetExplorerAuthoringCapability(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "explorerId" ------------- + var explorerId ExplorerId + + err = runtime.BindStyledParameterWithOptions("simple", "explorerId", c.Params("explorerId"), &explorerId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter explorerId: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.GetExplorerAuthoringCapability(c, project, explorerId) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// ApplyExplorerBuilderCommands operation middleware +func (siw *ServerInterfaceWrapper) ApplyExplorerBuilderCommands(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "explorerId" ------------- + var explorerId ExplorerId + + err = runtime.BindStyledParameterWithOptions("simple", "explorerId", c.Params("explorerId"), &explorerId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter explorerId: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.ApplyExplorerBuilderCommands(c, project, explorerId) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// CompileExplorer operation middleware +func (siw *ServerInterfaceWrapper) CompileExplorer(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "explorerId" ------------- + var explorerId ExplorerId + + err = runtime.BindStyledParameterWithOptions("simple", "explorerId", c.Params("explorerId"), &explorerId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter explorerId: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.CompileExplorer(c, project, explorerId) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// SaveExplorerDraft operation middleware +func (siw *ServerInterfaceWrapper) SaveExplorerDraft(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "explorerId" ------------- + var explorerId ExplorerId + + err = runtime.BindStyledParameterWithOptions("simple", "explorerId", c.Params("explorerId"), &explorerId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter explorerId: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.SaveExplorerDraft(c, project, explorerId) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// ExportExplorerWorkspace operation middleware +func (siw *ServerInterfaceWrapper) ExportExplorerWorkspace(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "explorerId" ------------- + var explorerId ExplorerId + + err = runtime.BindStyledParameterWithOptions("simple", "explorerId", c.Params("explorerId"), &explorerId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter explorerId: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.ExportExplorerWorkspace(c, project, explorerId) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// PreviewExplorer operation middleware +func (siw *ServerInterfaceWrapper) PreviewExplorer(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "explorerId" ------------- + var explorerId ExplorerId + + err = runtime.BindStyledParameterWithOptions("simple", "explorerId", c.Params("explorerId"), &explorerId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter explorerId: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.PreviewExplorer(c, project, explorerId) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// PublishExplorer operation middleware +func (siw *ServerInterfaceWrapper) PublishExplorer(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "explorerId" ------------- + var explorerId ExplorerId + + err = runtime.BindStyledParameterWithOptions("simple", "explorerId", c.Params("explorerId"), &explorerId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter explorerId: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.PublishExplorer(c, project, explorerId) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// ReconcileExplorerBuilder operation middleware +func (siw *ServerInterfaceWrapper) ReconcileExplorerBuilder(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "explorerId" ------------- + var explorerId ExplorerId + + err = runtime.BindStyledParameterWithOptions("simple", "explorerId", c.Params("explorerId"), &explorerId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter explorerId: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.ReconcileExplorerBuilder(c, project, explorerId) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// SearchExplorerCandidates operation middleware +func (siw *ServerInterfaceWrapper) SearchExplorerCandidates(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "explorerId" ------------- + var explorerId ExplorerId + + err = runtime.BindStyledParameterWithOptions("simple", "explorerId", c.Params("explorerId"), &explorerId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter explorerId: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.SearchExplorerCandidates(c, project, explorerId) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// AbortSnapshot operation middleware +func (siw *ServerInterfaceWrapper) AbortSnapshot(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "generation" ------------- + var generation Generation + + err = runtime.BindStyledParameterWithOptions("simple", "generation", c.Params("generation"), &generation, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter generation: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.AbortSnapshot(c, project, generation) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// GetSnapshot operation middleware +func (siw *ServerInterfaceWrapper) GetSnapshot(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "generation" ------------- + var generation Generation + + err = runtime.BindStyledParameterWithOptions("simple", "generation", c.Params("generation"), &generation, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter generation: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.GetSnapshot(c, project, generation) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// CreateSnapshot operation middleware +func (siw *ServerInterfaceWrapper) CreateSnapshot(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "generation" ------------- + var generation Generation + + err = runtime.BindStyledParameterWithOptions("simple", "generation", c.Params("generation"), &generation, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter generation: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.CreateSnapshot(c, project, generation) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// PublishRepositoryExplorerConfig operation middleware +func (siw *ServerInterfaceWrapper) PublishRepositoryExplorerConfig(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "generation" ------------- + var generation Generation + + err = runtime.BindStyledParameterWithOptions("simple", "generation", c.Params("generation"), &generation, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter generation: %w", err).Error()) + } + + // Parameter object where we will unmarshal all parameters from the context + var params PublishRepositoryExplorerConfigParams + + var query url.Values + query, err = url.ParseQuery(string(c.Request().URI().QueryString())) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for query string: %w", err).Error()) + } + + // ------------- Optional query parameter "auth_resource_path" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "auth_resource_path", query, ¶ms.AuthResourcePath, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter auth_resource_path: %w", err).Error()) + } + + headers := c.GetReqHeaders() + + // ------------- Required header parameter "X-Loom-Source-Commit" ------------- + if valueList, found := headers[http.CanonicalHeaderKey("X-Loom-Source-Commit")]; found { + var XLoomSourceCommit string + n := len(valueList) + if n != 1 { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Too many values for ParamName X-Loom-Source-Commit, 1 is required, but %d found", n)) + } + + err = runtime.BindStyledParameterWithOptions("simple", "X-Loom-Source-Commit", valueList[0], &XLoomSourceCommit, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter X-Loom-Source-Commit: %w", err).Error()) + } + + params.XLoomSourceCommit = XLoomSourceCommit + + } else { + return fiber.NewError(fiber.StatusBadRequest, "Header parameter X-Loom-Source-Commit is required, but not found") + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.PublishRepositoryExplorerConfig(c, project, generation, params) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// FinalizeSnapshot operation middleware +func (siw *ServerInterfaceWrapper) FinalizeSnapshot(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "generation" ------------- + var generation Generation + + err = runtime.BindStyledParameterWithOptions("simple", "generation", c.Params("generation"), &generation, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter generation: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.FinalizeSnapshot(c, project, generation) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// UploadSnapshotResource operation middleware +func (siw *ServerInterfaceWrapper) UploadSnapshotResource(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "generation" ------------- + var generation Generation + + err = runtime.BindStyledParameterWithOptions("simple", "generation", c.Params("generation"), &generation, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter generation: %w", err).Error()) + } + + // ------------- Path parameter "resourceType" ------------- + var resourceType ResourceType + + err = runtime.BindStyledParameterWithOptions("simple", "resourceType", c.Params("resourceType"), &resourceType, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter resourceType: %w", err).Error()) + } + + // Parameter object where we will unmarshal all parameters from the context + var params UploadSnapshotResourceParams + + headers := c.GetReqHeaders() + + // ------------- Optional header parameter "X-Content-SHA256" ------------- + if valueList, found := headers[http.CanonicalHeaderKey("X-Content-SHA256")]; found { + var XContentSHA256 string + n := len(valueList) + if n != 1 { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Too many values for ParamName X-Content-SHA256, 1 is required, but %d found", n)) + } + + err = runtime.BindStyledParameterWithOptions("simple", "X-Content-SHA256", valueList[0], &XContentSHA256, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter X-Content-SHA256: %w", err).Error()) + } + + params.XContentSHA256 = &XContentSHA256 + + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.UploadSnapshotResource(c, project, generation, resourceType, params) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// CreateRelease operation middleware +func (siw *ServerInterfaceWrapper) CreateRelease(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.CreateRelease(c, project) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// ActivateReleaseCompatibility operation middleware +func (siw *ServerInterfaceWrapper) ActivateReleaseCompatibility(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.ActivateReleaseCompatibility(c, project) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// GetActiveRelease operation middleware +func (siw *ServerInterfaceWrapper) GetActiveRelease(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.GetActiveRelease(c, project) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// GetRelease operation middleware +func (siw *ServerInterfaceWrapper) GetRelease(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "release" ------------- + var release Release + + err = runtime.BindStyledParameterWithOptions("simple", "release", c.Params("release"), &release, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter release: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.GetRelease(c, project, release) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// ActivateRelease operation middleware +func (siw *ServerInterfaceWrapper) ActivateRelease(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "release" ------------- + var release Release + + err = runtime.BindStyledParameterWithOptions("simple", "release", c.Params("release"), &release, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter release: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.ActivateRelease(c, project, release) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// UploadProjectResource operation middleware +func (siw *ServerInterfaceWrapper) UploadProjectResource(c fiber.Ctx) error { + + var err error + _ = err + + // ------------- Path parameter "project" ------------- + var project Project + + err = runtime.BindStyledParameterWithOptions("simple", "project", c.Params("project"), &project, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Path parameter "resourceType" ------------- + var resourceType ResourceType + + err = runtime.BindStyledParameterWithOptions("simple", "resourceType", c.Params("resourceType"), &resourceType, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter resourceType: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.UploadProjectResource(c, project, resourceType) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// UploadRawNDJSON operation middleware +func (siw *ServerInterfaceWrapper) UploadRawNDJSON(c fiber.Ctx) error { + + var err error + _ = err + + // Parameter object where we will unmarshal all parameters from the context + var params UploadRawNDJSONParams + + var query url.Values + query, err = url.ParseQuery(string(c.Request().URI().QueryString())) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for query string: %w", err).Error()) + } + + // ------------- Optional query parameter "project" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "project", query, ¶ms.Project, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter project: %w", err).Error()) + } + + // ------------- Optional query parameter "generation" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "generation", query, ¶ms.Generation, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter generation: %w", err).Error()) + } + + // ------------- Optional query parameter "auth_resource_path" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "auth_resource_path", query, ¶ms.AuthResourcePath, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter auth_resource_path: %w", err).Error()) + } + + handler := func(c fiber.Ctx) error { + return siw.Handler.UploadRawNDJSON(c, params) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// GetApolloSandbox operation middleware +func (siw *ServerInterfaceWrapper) GetApolloSandbox(c fiber.Ctx) error { + + handler := func(c fiber.Ctx) error { + return siw.Handler.GetApolloSandbox(c) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// ExecuteDataframeGraphQL operation middleware +func (siw *ServerInterfaceWrapper) ExecuteDataframeGraphQL(c fiber.Ctx) error { + + handler := func(c fiber.Ctx) error { + return siw.Handler.ExecuteDataframeGraphQL(c) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// GetGraphQLPlayground operation middleware +func (siw *ServerInterfaceWrapper) GetGraphQLPlayground(c fiber.Ctx) error { + + handler := func(c fiber.Ctx) error { + return siw.Handler.GetGraphQLPlayground(c) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// ExecuteGraphQL operation middleware +func (siw *ServerInterfaceWrapper) ExecuteGraphQL(c fiber.Ctx) error { + + handler := func(c fiber.Ctx) error { + return siw.Handler.ExecuteGraphQL(c) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// GetHealth operation middleware +func (siw *ServerInterfaceWrapper) GetHealth(c fiber.Ctx) error { + + handler := func(c fiber.Ctx) error { + return siw.Handler.GetHealth(c) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// GetLiveness operation middleware +func (siw *ServerInterfaceWrapper) GetLiveness(c fiber.Ctx) error { + + handler := func(c fiber.Ctx) error { + return siw.Handler.GetLiveness(c) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// GetReadiness operation middleware +func (siw *ServerInterfaceWrapper) GetReadiness(c fiber.Ctx) error { + + handler := func(c fiber.Ctx) error { + return siw.Handler.GetReadiness(c) + } + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + m := siw.HandlerMiddlewares[i] + next := handler + handler = func(c fiber.Ctx) error { + return m(c, next) + } + } + + return handler(c) +} + +// FiberServerOptions provides options for the Fiber server. +type FiberServerOptions struct { + BaseURL string + Middlewares []MiddlewareFunc + HandlerMiddlewares []HandlerMiddlewareFunc +} + +// RegisterHandlers creates http.Handler with routing matching OpenAPI spec. +func RegisterHandlers(router fiber.Router, si ServerInterface) { + RegisterHandlersWithOptions(router, si, FiberServerOptions{}) +} + +// RegisterHandlersWithOptions creates http.Handler with additional options +func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) { + wrapper := ServerInterfaceWrapper{ + Handler: si, + HandlerMiddlewares: options.HandlerMiddlewares, + } + + for _, m := range options.Middlewares { + router.Use(fiber.Handler(m)) + } + + router.Get(options.BaseURL+"/api/v1/projects/:project/explorers/:explorerId/authoring/v2/capability", wrapper.GetExplorerAuthoringCapability) + + router.Get(options.BaseURL+"/api/v1/projects/:project/explorers/:explorerId/authoring/v2/capabilities/:snapshotToken/candidates/:candidateId/suggestions", wrapper.GetExplorerCandidateSuggestions) + + router.Post(options.BaseURL+"/api/v1/projects/:project/explorers/:explorerId/authoring/v2/suggestions", wrapper.SearchExplorerCandidates) + + router.Get(options.BaseURL+"/api/v1/projects/:project/explorers/:explorerId/authoring/v2/builder", wrapper.GetExplorerBuilder) + + router.Post(options.BaseURL+"/api/v1/projects/:project/explorers/:explorerId/authoring/v2/builder", wrapper.CompileExplorerBuilder) + + router.Post(options.BaseURL+"/api/v1/projects/:project/explorers/:explorerId/authoring/v2/compile", wrapper.CompileExplorer) + + router.Post(options.BaseURL+"/api/v1/projects/:project/explorers/:explorerId/authoring/v2/commands", wrapper.ApplyExplorerBuilderCommands) + + router.Post(options.BaseURL+"/api/v1/projects/:project/explorers/:explorerId/authoring/v2/reconcile", wrapper.ReconcileExplorerBuilder) + + router.Put(options.BaseURL+"/api/v1/projects/:project/explorers/:explorerId/authoring/v2/draft", wrapper.SaveExplorerDraft) + + router.Get(options.BaseURL+"/api/v1/projects/:project/explorers/:explorerId/authoring/v2/export", wrapper.ExportExplorerWorkspace) + + router.Post(options.BaseURL+"/api/v1/projects/:project/explorers/:explorerId/authoring/v2/preview", wrapper.PreviewExplorer) + + router.Post(options.BaseURL+"/api/v1/projects/:project/explorers/:explorerId/authoring/v2/publish", wrapper.PublishExplorer) + + router.Get(options.BaseURL+"/health", wrapper.GetHealth) + + router.Get(options.BaseURL+"/livez", wrapper.GetLiveness) + + router.Get(options.BaseURL+"/readyz", wrapper.GetReadiness) + + router.Put(options.BaseURL+"/api/v1/projects/:project/resources/:resourceType", wrapper.UploadProjectResource) + + router.Post(options.BaseURL+"/api/v1/datasets/:project/generations/:generation", wrapper.CreateDatasetGeneration) + + router.Post(options.BaseURL+"/api/v1/datasets/:project/generations/:generation/activate", wrapper.ActivateDatasetGeneration) + + router.Put(options.BaseURL+"/api/v1/raw", wrapper.UploadRawNDJSON) + + router.Delete(options.BaseURL+"/api/v1/projects/:project/generations/:generation", wrapper.AbortSnapshot) + + router.Get(options.BaseURL+"/api/v1/projects/:project/generations/:generation", wrapper.GetSnapshot) + + router.Post(options.BaseURL+"/api/v1/projects/:project/generations/:generation", wrapper.CreateSnapshot) + + router.Put(options.BaseURL+"/api/v1/projects/:project/generations/:generation/resources/:resourceType", wrapper.UploadSnapshotResource) + + router.Post(options.BaseURL+"/api/v1/projects/:project/generations/:generation/finalize", wrapper.FinalizeSnapshot) + + router.Post(options.BaseURL+"/api/v1/projects/:project/releases", wrapper.CreateRelease) + + router.Get(options.BaseURL+"/api/v1/projects/:project/releases/active", wrapper.GetActiveRelease) + + router.Get(options.BaseURL+"/api/v1/projects/:project/releases/:release", wrapper.GetRelease) + + router.Post(options.BaseURL+"/api/v1/projects/:project/releases/:release/activate", wrapper.ActivateRelease) + + router.Post(options.BaseURL+"/api/v1/projects/:project/releases/activate", wrapper.ActivateReleaseCompatibility) + + router.Get(options.BaseURL+"/api/v1/dataframe/recipe-executions/:id", wrapper.GetRecipeExecution) + + router.Get(options.BaseURL+"/graphql/graph", wrapper.GetGraphQLPlayground) + + router.Post(options.BaseURL+"/graphql/graph", wrapper.ExecuteGraphQL) + + router.Post(options.BaseURL+"/graphql/dataframe", wrapper.ExecuteDataframeGraphQL) + + router.Get(options.BaseURL+"/apollo", wrapper.GetApolloSandbox) + + router.Get(options.BaseURL+"/api/v1/projects/:project/explorers", wrapper.ListExplorers) + + router.Post(options.BaseURL+"/api/v1/projects/:project/explorers", wrapper.CreateExplorer) + + router.Get(options.BaseURL+"/api/v1/projects/:project/explorers/:explorerId", wrapper.GetExplorer) + + router.Post(options.BaseURL+"/api/v1/projects/:project/generations/:generation/explorer-config", wrapper.PublishRepositoryExplorerConfig) + + router.Get(options.BaseURL+"/api/v1/projects/:project/explorer-config", wrapper.GetRepositoryExplorerConfig) + +} + +type AuthoringBadRequestJSONResponse ErrorResponse + +type AuthoringClientClosedRequestJSONResponse ErrorResponse + +type AuthoringConflictJSONResponse ErrorResponse + +type AuthoringForbiddenJSONResponse ErrorResponse + +type AuthoringGatewayTimeoutJSONResponse ErrorResponse + +type AuthoringInternalErrorJSONResponse ErrorResponse + +type AuthoringNotFoundJSONResponse ErrorResponse + +type AuthoringPayloadTooLargeJSONResponse ErrorResponse + +type AuthoringTooManyRequestsJSONResponse ErrorResponse + +type AuthoringUnavailableJSONResponse ErrorResponse + +type AuthoringUnprocessableJSONResponse ErrorResponse + +type GraphQLBadRequestJSONResponse RawJSON + +type GraphQLInternalErrorJSONResponse RawJSON + +type GraphQLUnprocessableJSONResponse RawJSON + +type HTMLTexthtmlResponse struct { + Body io.Reader + + ContentLength int64 +} + +type LegacyBadRequestJSONResponse LegacyErrorResponse + +type LegacyConflictJSONResponse LegacyErrorResponse + +type LegacyForbiddenJSONResponse LegacyErrorResponse + +type LegacyInternalErrorJSONResponse LegacyErrorResponse + +type LegacyNotFoundJSONResponse LegacyErrorResponse + +type LegacyUnavailableJSONResponse LegacyErrorResponse + +type LegacyUnprocessableJSONResponse LegacyErrorResponse + +type ServiceBadRequestJSONResponse ServiceErrorResponse + +type ServiceConflictJSONResponse ServiceErrorResponse + +type ServiceForbiddenJSONResponse ServiceErrorResponse + +type ServiceInternalErrorJSONResponse ServiceErrorResponse + +type ServiceNotFoundJSONResponse ServiceErrorResponse + +type ServiceUnauthorizedJSONResponse ServiceErrorResponse + +type ServiceUnavailableJSONResponse ServiceErrorResponse + +type ServiceUnprocessableJSONResponse ServiceErrorResponse + +type ServiceUnsupportedMediaTypeJSONResponse ServiceErrorResponse + +type GetRecipeExecutionRequestObject struct { + Id string `json:"id"` +} + +type GetRecipeExecutionResponseObject interface { + VisitGetRecipeExecutionResponse(ctx fiber.Ctx) error +} + +type GetRecipeExecution200JSONResponse RawJSON + +func (response GetRecipeExecution200JSONResponse) VisitGetRecipeExecutionResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type GetRecipeExecution401JSONResponse RawJSON + +func (response GetRecipeExecution401JSONResponse) VisitGetRecipeExecutionResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type GetRecipeExecution403JSONResponse struct{ LegacyForbiddenJSONResponse } + +func (response GetRecipeExecution403JSONResponse) VisitGetRecipeExecutionResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type GetRecipeExecution404JSONResponse struct{ LegacyNotFoundJSONResponse } + +func (response GetRecipeExecution404JSONResponse) VisitGetRecipeExecutionResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type CreateDatasetGenerationRequestObject struct { + Project Project `json:"project"` + Generation Generation `json:"generation"` + Body *multipart.Reader +} + +type CreateDatasetGenerationResponseObject interface { + VisitCreateDatasetGenerationResponse(ctx fiber.Ctx) error +} + +type CreateDatasetGeneration200JSONResponse RawJSON + +func (response CreateDatasetGeneration200JSONResponse) VisitCreateDatasetGenerationResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type CreateDatasetGeneration400JSONResponse struct{ ServiceBadRequestJSONResponse } + +func (response CreateDatasetGeneration400JSONResponse) VisitCreateDatasetGenerationResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type CreateDatasetGeneration401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response CreateDatasetGeneration401JSONResponse) VisitCreateDatasetGenerationResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type CreateDatasetGeneration403JSONResponse struct{ ServiceForbiddenJSONResponse } + +func (response CreateDatasetGeneration403JSONResponse) VisitCreateDatasetGenerationResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type CreateDatasetGeneration409JSONResponse struct{ ServiceConflictJSONResponse } + +func (response CreateDatasetGeneration409JSONResponse) VisitCreateDatasetGenerationResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type CreateDatasetGeneration415JSONResponse struct { + ServiceUnsupportedMediaTypeJSONResponse +} + +func (response CreateDatasetGeneration415JSONResponse) VisitCreateDatasetGenerationResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(415) + + return ctx.JSON(&response) +} + +type CreateDatasetGeneration422JSONResponse struct { + ServiceUnprocessableJSONResponse +} + +func (response CreateDatasetGeneration422JSONResponse) VisitCreateDatasetGenerationResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type CreateDatasetGeneration500JSONResponse struct { + ServiceInternalErrorJSONResponse +} + +func (response CreateDatasetGeneration500JSONResponse) VisitCreateDatasetGenerationResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type CreateDatasetGeneration503JSONResponse struct{ ServiceUnavailableJSONResponse } + +func (response CreateDatasetGeneration503JSONResponse) VisitCreateDatasetGenerationResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type ActivateDatasetGenerationRequestObject struct { + Project Project `json:"project"` + Generation Generation `json:"generation"` + Params ActivateDatasetGenerationParams +} + +type ActivateDatasetGenerationResponseObject interface { + VisitActivateDatasetGenerationResponse(ctx fiber.Ctx) error +} + +type ActivateDatasetGeneration200JSONResponse RawJSON + +func (response ActivateDatasetGeneration200JSONResponse) VisitActivateDatasetGenerationResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type ActivateDatasetGeneration400JSONResponse struct{ ServiceBadRequestJSONResponse } + +func (response ActivateDatasetGeneration400JSONResponse) VisitActivateDatasetGenerationResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type ActivateDatasetGeneration401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response ActivateDatasetGeneration401JSONResponse) VisitActivateDatasetGenerationResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type ActivateDatasetGeneration403JSONResponse struct{ ServiceForbiddenJSONResponse } + +func (response ActivateDatasetGeneration403JSONResponse) VisitActivateDatasetGenerationResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type ActivateDatasetGeneration409JSONResponse struct{ ServiceConflictJSONResponse } + +func (response ActivateDatasetGeneration409JSONResponse) VisitActivateDatasetGenerationResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type ActivateDatasetGeneration500JSONResponse struct { + ServiceInternalErrorJSONResponse +} + +func (response ActivateDatasetGeneration500JSONResponse) VisitActivateDatasetGenerationResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type ActivateDatasetGeneration503JSONResponse struct{ ServiceUnavailableJSONResponse } + +func (response ActivateDatasetGeneration503JSONResponse) VisitActivateDatasetGenerationResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type GetRepositoryExplorerConfigRequestObject struct { + Project Project `json:"project"` +} + +type GetRepositoryExplorerConfigResponseObject interface { + VisitGetRepositoryExplorerConfigResponse(ctx fiber.Ctx) error +} + +type GetRepositoryExplorerConfig200JSONResponse RawJSON + +func (response GetRepositoryExplorerConfig200JSONResponse) VisitGetRepositoryExplorerConfigResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type GetRepositoryExplorerConfig401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response GetRepositoryExplorerConfig401JSONResponse) VisitGetRepositoryExplorerConfigResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type GetRepositoryExplorerConfig403JSONResponse struct{ LegacyForbiddenJSONResponse } + +func (response GetRepositoryExplorerConfig403JSONResponse) VisitGetRepositoryExplorerConfigResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type GetRepositoryExplorerConfig404JSONResponse struct{ LegacyNotFoundJSONResponse } + +func (response GetRepositoryExplorerConfig404JSONResponse) VisitGetRepositoryExplorerConfigResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type GetRepositoryExplorerConfig500JSONResponse struct { + LegacyInternalErrorJSONResponse +} + +func (response GetRepositoryExplorerConfig500JSONResponse) VisitGetRepositoryExplorerConfigResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type ListExplorersRequestObject struct { + Project Project `json:"project"` +} + +type ListExplorersResponseObject interface { + VisitListExplorersResponse(ctx fiber.Ctx) error +} + +type ListExplorers200JSONResponse []map[string]interface{} + +func (response ListExplorers200JSONResponse) VisitListExplorersResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type ListExplorers401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response ListExplorers401JSONResponse) VisitListExplorersResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type ListExplorers403JSONResponse struct{ LegacyForbiddenJSONResponse } + +func (response ListExplorers403JSONResponse) VisitListExplorersResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type ListExplorers500JSONResponse struct { + LegacyInternalErrorJSONResponse +} + +func (response ListExplorers500JSONResponse) VisitListExplorersResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type CreateExplorerRequestObject struct { + Project Project `json:"project"` + Body *CreateExplorerJSONRequestBody +} + +type CreateExplorerResponseObject interface { + VisitCreateExplorerResponse(ctx fiber.Ctx) error +} + +type CreateExplorer201JSONResponse RawJSON + +func (response CreateExplorer201JSONResponse) VisitCreateExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(201) + + return ctx.JSON(&response) +} + +type CreateExplorer400JSONResponse struct{ LegacyBadRequestJSONResponse } + +func (response CreateExplorer400JSONResponse) VisitCreateExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type CreateExplorer401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response CreateExplorer401JSONResponse) VisitCreateExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type CreateExplorer403JSONResponse struct{ LegacyForbiddenJSONResponse } + +func (response CreateExplorer403JSONResponse) VisitCreateExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type CreateExplorer409JSONResponse struct{ LegacyConflictJSONResponse } + +func (response CreateExplorer409JSONResponse) VisitCreateExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type CreateExplorer422JSONResponse struct { + LegacyUnprocessableJSONResponse +} + +func (response CreateExplorer422JSONResponse) VisitCreateExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type CreateExplorer500JSONResponse struct { + LegacyInternalErrorJSONResponse +} + +func (response CreateExplorer500JSONResponse) VisitCreateExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type GetExplorerRequestObject struct { + Project Project `json:"project"` + ExplorerId ExplorerId `json:"explorerId"` +} + +type GetExplorerResponseObject interface { + VisitGetExplorerResponse(ctx fiber.Ctx) error +} + +type GetExplorer200JSONResponse RawJSON + +func (response GetExplorer200JSONResponse) VisitGetExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type GetExplorer401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response GetExplorer401JSONResponse) VisitGetExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type GetExplorer403JSONResponse struct{ LegacyForbiddenJSONResponse } + +func (response GetExplorer403JSONResponse) VisitGetExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type GetExplorer404JSONResponse struct{ LegacyNotFoundJSONResponse } + +func (response GetExplorer404JSONResponse) VisitGetExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type GetExplorer500JSONResponse struct { + LegacyInternalErrorJSONResponse +} + +func (response GetExplorer500JSONResponse) VisitGetExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type GetExplorerBuilderRequestObject struct { + Project Project `json:"project"` + ExplorerId ExplorerId `json:"explorerId"` +} + +type GetExplorerBuilderResponseObject interface { + VisitGetExplorerBuilderResponse(ctx fiber.Ctx) error +} + +type GetExplorerBuilder200JSONResponse BuilderState + +func (response GetExplorerBuilder200JSONResponse) VisitGetExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type GetExplorerBuilder401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response GetExplorerBuilder401JSONResponse) VisitGetExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type GetExplorerBuilder403JSONResponse struct{ AuthoringForbiddenJSONResponse } + +func (response GetExplorerBuilder403JSONResponse) VisitGetExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type GetExplorerBuilder404JSONResponse struct{ AuthoringNotFoundJSONResponse } + +func (response GetExplorerBuilder404JSONResponse) VisitGetExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type GetExplorerBuilder409JSONResponse struct{ AuthoringConflictJSONResponse } + +func (response GetExplorerBuilder409JSONResponse) VisitGetExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type GetExplorerBuilder500JSONResponse struct { + AuthoringInternalErrorJSONResponse +} + +func (response GetExplorerBuilder500JSONResponse) VisitGetExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type GetExplorerBuilder503JSONResponse struct { + AuthoringUnavailableJSONResponse +} + +func (response GetExplorerBuilder503JSONResponse) VisitGetExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type CompileExplorerBuilderRequestObject struct { + Project Project `json:"project"` + ExplorerId ExplorerId `json:"explorerId"` + Body *CompileExplorerBuilderJSONRequestBody +} + +type CompileExplorerBuilderResponseObject interface { + VisitCompileExplorerBuilderResponse(ctx fiber.Ctx) error +} + +type CompileExplorerBuilder200JSONResponse CompileResponse + +func (response CompileExplorerBuilder200JSONResponse) VisitCompileExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type CompileExplorerBuilder400JSONResponse struct { + AuthoringBadRequestJSONResponse +} + +func (response CompileExplorerBuilder400JSONResponse) VisitCompileExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type CompileExplorerBuilder401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response CompileExplorerBuilder401JSONResponse) VisitCompileExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type CompileExplorerBuilder403JSONResponse struct{ AuthoringForbiddenJSONResponse } + +func (response CompileExplorerBuilder403JSONResponse) VisitCompileExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type CompileExplorerBuilder409JSONResponse struct{ AuthoringConflictJSONResponse } + +func (response CompileExplorerBuilder409JSONResponse) VisitCompileExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type CompileExplorerBuilder422JSONResponse struct { + AuthoringUnprocessableJSONResponse +} + +func (response CompileExplorerBuilder422JSONResponse) VisitCompileExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type CompileExplorerBuilder500JSONResponse struct { + AuthoringInternalErrorJSONResponse +} + +func (response CompileExplorerBuilder500JSONResponse) VisitCompileExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type CompileExplorerBuilder503JSONResponse struct { + AuthoringUnavailableJSONResponse +} + +func (response CompileExplorerBuilder503JSONResponse) VisitCompileExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type GetExplorerCandidateSuggestionsRequestObject struct { + Project Project `json:"project"` + ExplorerId ExplorerId `json:"explorerId"` + SnapshotToken string `json:"snapshotToken"` + CandidateId string `json:"candidateId"` +} + +type GetExplorerCandidateSuggestionsResponseObject interface { + VisitGetExplorerCandidateSuggestionsResponse(ctx fiber.Ctx) error +} + +type GetExplorerCandidateSuggestions200JSONResponse CandidateSuggestions + +func (response GetExplorerCandidateSuggestions200JSONResponse) VisitGetExplorerCandidateSuggestionsResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type GetExplorerCandidateSuggestions400JSONResponse struct { + AuthoringBadRequestJSONResponse +} + +func (response GetExplorerCandidateSuggestions400JSONResponse) VisitGetExplorerCandidateSuggestionsResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type GetExplorerCandidateSuggestions401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response GetExplorerCandidateSuggestions401JSONResponse) VisitGetExplorerCandidateSuggestionsResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type GetExplorerCandidateSuggestions403JSONResponse struct{ AuthoringForbiddenJSONResponse } + +func (response GetExplorerCandidateSuggestions403JSONResponse) VisitGetExplorerCandidateSuggestionsResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type GetExplorerCandidateSuggestions404JSONResponse struct{ AuthoringNotFoundJSONResponse } + +func (response GetExplorerCandidateSuggestions404JSONResponse) VisitGetExplorerCandidateSuggestionsResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type GetExplorerCandidateSuggestions409JSONResponse struct{ AuthoringConflictJSONResponse } + +func (response GetExplorerCandidateSuggestions409JSONResponse) VisitGetExplorerCandidateSuggestionsResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type GetExplorerCandidateSuggestions500JSONResponse struct { + AuthoringInternalErrorJSONResponse +} + +func (response GetExplorerCandidateSuggestions500JSONResponse) VisitGetExplorerCandidateSuggestionsResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type GetExplorerCandidateSuggestions503JSONResponse struct { + AuthoringUnavailableJSONResponse +} + +func (response GetExplorerCandidateSuggestions503JSONResponse) VisitGetExplorerCandidateSuggestionsResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type GetExplorerAuthoringCapabilityRequestObject struct { + Project Project `json:"project"` + ExplorerId ExplorerId `json:"explorerId"` +} + +type GetExplorerAuthoringCapabilityResponseObject interface { + VisitGetExplorerAuthoringCapabilityResponse(ctx fiber.Ctx) error +} + +type GetExplorerAuthoringCapability200JSONResponse AuthoringCapability + +func (response GetExplorerAuthoringCapability200JSONResponse) VisitGetExplorerAuthoringCapabilityResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type GetExplorerAuthoringCapability401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response GetExplorerAuthoringCapability401JSONResponse) VisitGetExplorerAuthoringCapabilityResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type GetExplorerAuthoringCapability403JSONResponse struct{ AuthoringForbiddenJSONResponse } + +func (response GetExplorerAuthoringCapability403JSONResponse) VisitGetExplorerAuthoringCapabilityResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type GetExplorerAuthoringCapability500JSONResponse struct { + AuthoringInternalErrorJSONResponse +} + +func (response GetExplorerAuthoringCapability500JSONResponse) VisitGetExplorerAuthoringCapabilityResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type ApplyExplorerBuilderCommandsRequestObject struct { + Project Project `json:"project"` + ExplorerId ExplorerId `json:"explorerId"` + Body *ApplyExplorerBuilderCommandsJSONRequestBody +} + +type ApplyExplorerBuilderCommandsResponseObject interface { + VisitApplyExplorerBuilderCommandsResponse(ctx fiber.Ctx) error +} + +type ApplyExplorerBuilderCommands200JSONResponse ApplyCommandsResponse + +func (response ApplyExplorerBuilderCommands200JSONResponse) VisitApplyExplorerBuilderCommandsResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type ApplyExplorerBuilderCommands400JSONResponse struct { + AuthoringBadRequestJSONResponse +} + +func (response ApplyExplorerBuilderCommands400JSONResponse) VisitApplyExplorerBuilderCommandsResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type ApplyExplorerBuilderCommands401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response ApplyExplorerBuilderCommands401JSONResponse) VisitApplyExplorerBuilderCommandsResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type ApplyExplorerBuilderCommands403JSONResponse struct{ AuthoringForbiddenJSONResponse } + +func (response ApplyExplorerBuilderCommands403JSONResponse) VisitApplyExplorerBuilderCommandsResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type ApplyExplorerBuilderCommands409JSONResponse struct{ AuthoringConflictJSONResponse } + +func (response ApplyExplorerBuilderCommands409JSONResponse) VisitApplyExplorerBuilderCommandsResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type ApplyExplorerBuilderCommands422JSONResponse struct { + AuthoringUnprocessableJSONResponse +} + +func (response ApplyExplorerBuilderCommands422JSONResponse) VisitApplyExplorerBuilderCommandsResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type ApplyExplorerBuilderCommands500JSONResponse struct { + AuthoringInternalErrorJSONResponse +} + +func (response ApplyExplorerBuilderCommands500JSONResponse) VisitApplyExplorerBuilderCommandsResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type ApplyExplorerBuilderCommands503JSONResponse struct { + AuthoringUnavailableJSONResponse +} + +func (response ApplyExplorerBuilderCommands503JSONResponse) VisitApplyExplorerBuilderCommandsResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type CompileExplorerRequestObject struct { + Project Project `json:"project"` + ExplorerId ExplorerId `json:"explorerId"` + Body *CompileExplorerJSONRequestBody +} + +type CompileExplorerResponseObject interface { + VisitCompileExplorerResponse(ctx fiber.Ctx) error +} + +type CompileExplorer200JSONResponse CompileResponse + +func (response CompileExplorer200JSONResponse) VisitCompileExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type CompileExplorer400JSONResponse struct { + AuthoringBadRequestJSONResponse +} + +func (response CompileExplorer400JSONResponse) VisitCompileExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type CompileExplorer401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response CompileExplorer401JSONResponse) VisitCompileExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type CompileExplorer403JSONResponse struct{ AuthoringForbiddenJSONResponse } + +func (response CompileExplorer403JSONResponse) VisitCompileExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type CompileExplorer409JSONResponse struct{ AuthoringConflictJSONResponse } + +func (response CompileExplorer409JSONResponse) VisitCompileExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type CompileExplorer422JSONResponse struct { + AuthoringUnprocessableJSONResponse +} + +func (response CompileExplorer422JSONResponse) VisitCompileExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type CompileExplorer500JSONResponse struct { + AuthoringInternalErrorJSONResponse +} + +func (response CompileExplorer500JSONResponse) VisitCompileExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type CompileExplorer503JSONResponse struct { + AuthoringUnavailableJSONResponse +} + +func (response CompileExplorer503JSONResponse) VisitCompileExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type SaveExplorerDraftRequestObject struct { + Project Project `json:"project"` + ExplorerId ExplorerId `json:"explorerId"` + Body *SaveExplorerDraftJSONRequestBody +} + +type SaveExplorerDraftResponseObject interface { + VisitSaveExplorerDraftResponse(ctx fiber.Ctx) error +} + +type SaveExplorerDraft200JSONResponse SaveDraftResponse + +func (response SaveExplorerDraft200JSONResponse) VisitSaveExplorerDraftResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type SaveExplorerDraft400JSONResponse struct { + AuthoringBadRequestJSONResponse +} + +func (response SaveExplorerDraft400JSONResponse) VisitSaveExplorerDraftResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type SaveExplorerDraft401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response SaveExplorerDraft401JSONResponse) VisitSaveExplorerDraftResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type SaveExplorerDraft403JSONResponse struct{ AuthoringForbiddenJSONResponse } + +func (response SaveExplorerDraft403JSONResponse) VisitSaveExplorerDraftResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type SaveExplorerDraft404JSONResponse struct{ AuthoringNotFoundJSONResponse } + +func (response SaveExplorerDraft404JSONResponse) VisitSaveExplorerDraftResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type SaveExplorerDraft409JSONResponse struct{ AuthoringConflictJSONResponse } + +func (response SaveExplorerDraft409JSONResponse) VisitSaveExplorerDraftResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type SaveExplorerDraft422JSONResponse struct { + AuthoringUnprocessableJSONResponse +} + +func (response SaveExplorerDraft422JSONResponse) VisitSaveExplorerDraftResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type SaveExplorerDraft500JSONResponse struct { + AuthoringInternalErrorJSONResponse +} + +func (response SaveExplorerDraft500JSONResponse) VisitSaveExplorerDraftResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type SaveExplorerDraft503JSONResponse struct { + AuthoringUnavailableJSONResponse +} + +func (response SaveExplorerDraft503JSONResponse) VisitSaveExplorerDraftResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type ExportExplorerWorkspaceRequestObject struct { + Project Project `json:"project"` + ExplorerId ExplorerId `json:"explorerId"` +} + +type ExportExplorerWorkspaceResponseObject interface { + VisitExportExplorerWorkspaceResponse(ctx fiber.Ctx) error +} + +type ExportExplorerWorkspace200JSONResponse Workspace + +func (response ExportExplorerWorkspace200JSONResponse) VisitExportExplorerWorkspaceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type ExportExplorerWorkspace401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response ExportExplorerWorkspace401JSONResponse) VisitExportExplorerWorkspaceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type ExportExplorerWorkspace403JSONResponse struct{ AuthoringForbiddenJSONResponse } + +func (response ExportExplorerWorkspace403JSONResponse) VisitExportExplorerWorkspaceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type ExportExplorerWorkspace404JSONResponse struct{ AuthoringNotFoundJSONResponse } + +func (response ExportExplorerWorkspace404JSONResponse) VisitExportExplorerWorkspaceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type ExportExplorerWorkspace409JSONResponse struct{ AuthoringConflictJSONResponse } + +func (response ExportExplorerWorkspace409JSONResponse) VisitExportExplorerWorkspaceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type ExportExplorerWorkspace500JSONResponse struct { + AuthoringInternalErrorJSONResponse +} + +func (response ExportExplorerWorkspace500JSONResponse) VisitExportExplorerWorkspaceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type PreviewExplorerRequestObject struct { + Project Project `json:"project"` + ExplorerId ExplorerId `json:"explorerId"` + Body *PreviewExplorerJSONRequestBody +} + +type PreviewExplorerResponseObject interface { + VisitPreviewExplorerResponse(ctx fiber.Ctx) error +} + +type PreviewExplorer200JSONResponse PreviewResponse + +func (response PreviewExplorer200JSONResponse) VisitPreviewExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type PreviewExplorer400JSONResponse struct { + AuthoringBadRequestJSONResponse +} + +func (response PreviewExplorer400JSONResponse) VisitPreviewExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type PreviewExplorer401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response PreviewExplorer401JSONResponse) VisitPreviewExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type PreviewExplorer403JSONResponse struct{ AuthoringForbiddenJSONResponse } + +func (response PreviewExplorer403JSONResponse) VisitPreviewExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type PreviewExplorer404JSONResponse struct{ AuthoringNotFoundJSONResponse } + +func (response PreviewExplorer404JSONResponse) VisitPreviewExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type PreviewExplorer409JSONResponse struct{ AuthoringConflictJSONResponse } + +func (response PreviewExplorer409JSONResponse) VisitPreviewExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type PreviewExplorer413JSONResponse struct { + AuthoringPayloadTooLargeJSONResponse +} + +func (response PreviewExplorer413JSONResponse) VisitPreviewExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(413) + + return ctx.JSON(&response) +} + +type PreviewExplorer422JSONResponse struct { + AuthoringUnprocessableJSONResponse +} + +func (response PreviewExplorer422JSONResponse) VisitPreviewExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type PreviewExplorer429JSONResponse struct { + AuthoringTooManyRequestsJSONResponse +} + +func (response PreviewExplorer429JSONResponse) VisitPreviewExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(429) + + return ctx.JSON(&response) +} + +type PreviewExplorer499JSONResponse struct { + AuthoringClientClosedRequestJSONResponse +} + +func (response PreviewExplorer499JSONResponse) VisitPreviewExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(499) + + return ctx.JSON(&response) +} + +type PreviewExplorer500JSONResponse struct { + AuthoringInternalErrorJSONResponse +} + +func (response PreviewExplorer500JSONResponse) VisitPreviewExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type PreviewExplorer503JSONResponse struct { + AuthoringUnavailableJSONResponse +} + +func (response PreviewExplorer503JSONResponse) VisitPreviewExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type PreviewExplorer504JSONResponse struct { + AuthoringGatewayTimeoutJSONResponse +} + +func (response PreviewExplorer504JSONResponse) VisitPreviewExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(504) + + return ctx.JSON(&response) +} + +type PublishExplorerRequestObject struct { + Project Project `json:"project"` + ExplorerId ExplorerId `json:"explorerId"` + Body *PublishExplorerJSONRequestBody +} + +type PublishExplorerResponseObject interface { + VisitPublishExplorerResponse(ctx fiber.Ctx) error +} + +type PublishExplorer200JSONResponse PublishResponse + +func (response PublishExplorer200JSONResponse) VisitPublishExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type PublishExplorer400JSONResponse struct { + AuthoringBadRequestJSONResponse +} + +func (response PublishExplorer400JSONResponse) VisitPublishExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type PublishExplorer401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response PublishExplorer401JSONResponse) VisitPublishExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type PublishExplorer403JSONResponse struct{ AuthoringForbiddenJSONResponse } + +func (response PublishExplorer403JSONResponse) VisitPublishExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type PublishExplorer404JSONResponse struct{ AuthoringNotFoundJSONResponse } + +func (response PublishExplorer404JSONResponse) VisitPublishExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type PublishExplorer409JSONResponse struct{ AuthoringConflictJSONResponse } + +func (response PublishExplorer409JSONResponse) VisitPublishExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type PublishExplorer422JSONResponse struct { + AuthoringUnprocessableJSONResponse +} + +func (response PublishExplorer422JSONResponse) VisitPublishExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type PublishExplorer500JSONResponse struct { + AuthoringInternalErrorJSONResponse +} + +func (response PublishExplorer500JSONResponse) VisitPublishExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type PublishExplorer503JSONResponse struct { + AuthoringUnavailableJSONResponse +} + +func (response PublishExplorer503JSONResponse) VisitPublishExplorerResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type ReconcileExplorerBuilderRequestObject struct { + Project Project `json:"project"` + ExplorerId ExplorerId `json:"explorerId"` + Body *ReconcileExplorerBuilderJSONRequestBody +} + +type ReconcileExplorerBuilderResponseObject interface { + VisitReconcileExplorerBuilderResponse(ctx fiber.Ctx) error +} + +type ReconcileExplorerBuilder200JSONResponse CompileResponse + +func (response ReconcileExplorerBuilder200JSONResponse) VisitReconcileExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type ReconcileExplorerBuilder400JSONResponse struct { + AuthoringBadRequestJSONResponse +} + +func (response ReconcileExplorerBuilder400JSONResponse) VisitReconcileExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type ReconcileExplorerBuilder401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response ReconcileExplorerBuilder401JSONResponse) VisitReconcileExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type ReconcileExplorerBuilder403JSONResponse struct{ AuthoringForbiddenJSONResponse } + +func (response ReconcileExplorerBuilder403JSONResponse) VisitReconcileExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type ReconcileExplorerBuilder404JSONResponse struct{ AuthoringNotFoundJSONResponse } + +func (response ReconcileExplorerBuilder404JSONResponse) VisitReconcileExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type ReconcileExplorerBuilder409JSONResponse struct{ AuthoringConflictJSONResponse } + +func (response ReconcileExplorerBuilder409JSONResponse) VisitReconcileExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type ReconcileExplorerBuilder422JSONResponse struct { + AuthoringUnprocessableJSONResponse +} + +func (response ReconcileExplorerBuilder422JSONResponse) VisitReconcileExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type ReconcileExplorerBuilder500JSONResponse struct { + AuthoringInternalErrorJSONResponse +} + +func (response ReconcileExplorerBuilder500JSONResponse) VisitReconcileExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type ReconcileExplorerBuilder503JSONResponse struct { + AuthoringUnavailableJSONResponse +} + +func (response ReconcileExplorerBuilder503JSONResponse) VisitReconcileExplorerBuilderResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type SearchExplorerCandidatesRequestObject struct { + Project Project `json:"project"` + ExplorerId ExplorerId `json:"explorerId"` + Body *SearchExplorerCandidatesJSONRequestBody +} + +type SearchExplorerCandidatesResponseObject interface { + VisitSearchExplorerCandidatesResponse(ctx fiber.Ctx) error +} + +type SearchExplorerCandidates200JSONResponse CandidateSearchResponse + +func (response SearchExplorerCandidates200JSONResponse) VisitSearchExplorerCandidatesResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type SearchExplorerCandidates400JSONResponse struct { + AuthoringBadRequestJSONResponse +} + +func (response SearchExplorerCandidates400JSONResponse) VisitSearchExplorerCandidatesResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type SearchExplorerCandidates401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response SearchExplorerCandidates401JSONResponse) VisitSearchExplorerCandidatesResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type SearchExplorerCandidates403JSONResponse struct{ AuthoringForbiddenJSONResponse } + +func (response SearchExplorerCandidates403JSONResponse) VisitSearchExplorerCandidatesResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type SearchExplorerCandidates409JSONResponse struct{ AuthoringConflictJSONResponse } + +func (response SearchExplorerCandidates409JSONResponse) VisitSearchExplorerCandidatesResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type SearchExplorerCandidates500JSONResponse struct { + AuthoringInternalErrorJSONResponse +} + +func (response SearchExplorerCandidates500JSONResponse) VisitSearchExplorerCandidatesResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type SearchExplorerCandidates503JSONResponse struct { + AuthoringUnavailableJSONResponse +} + +func (response SearchExplorerCandidates503JSONResponse) VisitSearchExplorerCandidatesResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type AbortSnapshotRequestObject struct { + Project Project `json:"project"` + Generation Generation `json:"generation"` +} + +type AbortSnapshotResponseObject interface { + VisitAbortSnapshotResponse(ctx fiber.Ctx) error +} + +type AbortSnapshot200JSONResponse RawJSON + +func (response AbortSnapshot200JSONResponse) VisitAbortSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type AbortSnapshot401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response AbortSnapshot401JSONResponse) VisitAbortSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type AbortSnapshot403JSONResponse struct{ ServiceForbiddenJSONResponse } + +func (response AbortSnapshot403JSONResponse) VisitAbortSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type AbortSnapshot404JSONResponse struct{ ServiceNotFoundJSONResponse } + +func (response AbortSnapshot404JSONResponse) VisitAbortSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type AbortSnapshot409JSONResponse struct{ ServiceConflictJSONResponse } + +func (response AbortSnapshot409JSONResponse) VisitAbortSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type AbortSnapshot500JSONResponse struct { + ServiceInternalErrorJSONResponse +} + +func (response AbortSnapshot500JSONResponse) VisitAbortSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type AbortSnapshot503JSONResponse struct{ ServiceUnavailableJSONResponse } + +func (response AbortSnapshot503JSONResponse) VisitAbortSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type GetSnapshotRequestObject struct { + Project Project `json:"project"` + Generation Generation `json:"generation"` +} + +type GetSnapshotResponseObject interface { + VisitGetSnapshotResponse(ctx fiber.Ctx) error +} + +type GetSnapshot200JSONResponse RawJSON + +func (response GetSnapshot200JSONResponse) VisitGetSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type GetSnapshot401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response GetSnapshot401JSONResponse) VisitGetSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type GetSnapshot403JSONResponse struct{ ServiceForbiddenJSONResponse } + +func (response GetSnapshot403JSONResponse) VisitGetSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type GetSnapshot404JSONResponse struct{ ServiceNotFoundJSONResponse } + +func (response GetSnapshot404JSONResponse) VisitGetSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type GetSnapshot500JSONResponse struct { + ServiceInternalErrorJSONResponse +} + +func (response GetSnapshot500JSONResponse) VisitGetSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type GetSnapshot503JSONResponse struct{ ServiceUnavailableJSONResponse } + +func (response GetSnapshot503JSONResponse) VisitGetSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type CreateSnapshotRequestObject struct { + Project Project `json:"project"` + Generation Generation `json:"generation"` + Body *CreateSnapshotJSONRequestBody +} + +type CreateSnapshotResponseObject interface { + VisitCreateSnapshotResponse(ctx fiber.Ctx) error +} + +type CreateSnapshot200JSONResponse RawJSON + +func (response CreateSnapshot200JSONResponse) VisitCreateSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type CreateSnapshot400JSONResponse struct{ ServiceBadRequestJSONResponse } + +func (response CreateSnapshot400JSONResponse) VisitCreateSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type CreateSnapshot401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response CreateSnapshot401JSONResponse) VisitCreateSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type CreateSnapshot403JSONResponse struct{ ServiceForbiddenJSONResponse } + +func (response CreateSnapshot403JSONResponse) VisitCreateSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type CreateSnapshot409JSONResponse struct{ ServiceConflictJSONResponse } + +func (response CreateSnapshot409JSONResponse) VisitCreateSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type CreateSnapshot500JSONResponse struct { + ServiceInternalErrorJSONResponse +} + +func (response CreateSnapshot500JSONResponse) VisitCreateSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type CreateSnapshot503JSONResponse struct{ ServiceUnavailableJSONResponse } + +func (response CreateSnapshot503JSONResponse) VisitCreateSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type PublishRepositoryExplorerConfigRequestObject struct { + Project Project `json:"project"` + Generation Generation `json:"generation"` + Params PublishRepositoryExplorerConfigParams + Body *PublishRepositoryExplorerConfigJSONRequestBody +} + +type PublishRepositoryExplorerConfigResponseObject interface { + VisitPublishRepositoryExplorerConfigResponse(ctx fiber.Ctx) error +} + +type PublishRepositoryExplorerConfig200JSONResponse RawJSON + +func (response PublishRepositoryExplorerConfig200JSONResponse) VisitPublishRepositoryExplorerConfigResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type PublishRepositoryExplorerConfig400JSONResponse struct{ LegacyBadRequestJSONResponse } + +func (response PublishRepositoryExplorerConfig400JSONResponse) VisitPublishRepositoryExplorerConfigResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type PublishRepositoryExplorerConfig401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response PublishRepositoryExplorerConfig401JSONResponse) VisitPublishRepositoryExplorerConfigResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type PublishRepositoryExplorerConfig403JSONResponse struct{ LegacyForbiddenJSONResponse } + +func (response PublishRepositoryExplorerConfig403JSONResponse) VisitPublishRepositoryExplorerConfigResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type PublishRepositoryExplorerConfig409JSONResponse struct{ LegacyConflictJSONResponse } + +func (response PublishRepositoryExplorerConfig409JSONResponse) VisitPublishRepositoryExplorerConfigResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type PublishRepositoryExplorerConfig422JSONResponse struct { + LegacyUnprocessableJSONResponse +} + +func (response PublishRepositoryExplorerConfig422JSONResponse) VisitPublishRepositoryExplorerConfigResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type PublishRepositoryExplorerConfig500JSONResponse struct { + LegacyInternalErrorJSONResponse +} + +func (response PublishRepositoryExplorerConfig500JSONResponse) VisitPublishRepositoryExplorerConfigResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type PublishRepositoryExplorerConfig503JSONResponse struct{ LegacyUnavailableJSONResponse } + +func (response PublishRepositoryExplorerConfig503JSONResponse) VisitPublishRepositoryExplorerConfigResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type FinalizeSnapshotRequestObject struct { + Project Project `json:"project"` + Generation Generation `json:"generation"` +} + +type FinalizeSnapshotResponseObject interface { + VisitFinalizeSnapshotResponse(ctx fiber.Ctx) error +} + +type FinalizeSnapshot200JSONResponse RawJSON + +func (response FinalizeSnapshot200JSONResponse) VisitFinalizeSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type FinalizeSnapshot400JSONResponse struct{ ServiceBadRequestJSONResponse } + +func (response FinalizeSnapshot400JSONResponse) VisitFinalizeSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type FinalizeSnapshot401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response FinalizeSnapshot401JSONResponse) VisitFinalizeSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type FinalizeSnapshot403JSONResponse struct{ ServiceForbiddenJSONResponse } + +func (response FinalizeSnapshot403JSONResponse) VisitFinalizeSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type FinalizeSnapshot404JSONResponse struct{ ServiceNotFoundJSONResponse } + +func (response FinalizeSnapshot404JSONResponse) VisitFinalizeSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type FinalizeSnapshot409JSONResponse struct{ ServiceConflictJSONResponse } + +func (response FinalizeSnapshot409JSONResponse) VisitFinalizeSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type FinalizeSnapshot422JSONResponse struct { + ServiceUnprocessableJSONResponse +} + +func (response FinalizeSnapshot422JSONResponse) VisitFinalizeSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type FinalizeSnapshot500JSONResponse struct { + ServiceInternalErrorJSONResponse +} + +func (response FinalizeSnapshot500JSONResponse) VisitFinalizeSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type FinalizeSnapshot503JSONResponse struct{ ServiceUnavailableJSONResponse } + +func (response FinalizeSnapshot503JSONResponse) VisitFinalizeSnapshotResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type UploadSnapshotResourceRequestObject struct { + Project Project `json:"project"` + Generation Generation `json:"generation"` + ResourceType ResourceType `json:"resourceType"` + Params UploadSnapshotResourceParams + Body io.Reader +} + +type UploadSnapshotResourceResponseObject interface { + VisitUploadSnapshotResourceResponse(ctx fiber.Ctx) error +} + +type UploadSnapshotResource200JSONResponse RawJSON + +func (response UploadSnapshotResource200JSONResponse) VisitUploadSnapshotResourceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type UploadSnapshotResource400JSONResponse struct{ ServiceBadRequestJSONResponse } + +func (response UploadSnapshotResource400JSONResponse) VisitUploadSnapshotResourceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type UploadSnapshotResource401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response UploadSnapshotResource401JSONResponse) VisitUploadSnapshotResourceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type UploadSnapshotResource403JSONResponse struct{ ServiceForbiddenJSONResponse } + +func (response UploadSnapshotResource403JSONResponse) VisitUploadSnapshotResourceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type UploadSnapshotResource404JSONResponse struct{ ServiceNotFoundJSONResponse } + +func (response UploadSnapshotResource404JSONResponse) VisitUploadSnapshotResourceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type UploadSnapshotResource409JSONResponse struct{ ServiceConflictJSONResponse } + +func (response UploadSnapshotResource409JSONResponse) VisitUploadSnapshotResourceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type UploadSnapshotResource422JSONResponse struct { + ServiceUnprocessableJSONResponse +} + +func (response UploadSnapshotResource422JSONResponse) VisitUploadSnapshotResourceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type UploadSnapshotResource500JSONResponse struct { + ServiceInternalErrorJSONResponse +} + +func (response UploadSnapshotResource500JSONResponse) VisitUploadSnapshotResourceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type UploadSnapshotResource503JSONResponse struct{ ServiceUnavailableJSONResponse } + +func (response UploadSnapshotResource503JSONResponse) VisitUploadSnapshotResourceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type CreateReleaseRequestObject struct { + Project Project `json:"project"` + Body *CreateReleaseJSONRequestBody +} + +type CreateReleaseResponseObject interface { + VisitCreateReleaseResponse(ctx fiber.Ctx) error +} + +type CreateRelease200JSONResponse RawJSON + +func (response CreateRelease200JSONResponse) VisitCreateReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type CreateRelease400JSONResponse struct{ ServiceBadRequestJSONResponse } + +func (response CreateRelease400JSONResponse) VisitCreateReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type CreateRelease401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response CreateRelease401JSONResponse) VisitCreateReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type CreateRelease403JSONResponse struct{ ServiceForbiddenJSONResponse } + +func (response CreateRelease403JSONResponse) VisitCreateReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type CreateRelease404JSONResponse struct{ ServiceNotFoundJSONResponse } + +func (response CreateRelease404JSONResponse) VisitCreateReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type CreateRelease409JSONResponse struct{ ServiceConflictJSONResponse } + +func (response CreateRelease409JSONResponse) VisitCreateReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type CreateRelease422JSONResponse struct { + ServiceUnprocessableJSONResponse +} + +func (response CreateRelease422JSONResponse) VisitCreateReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type CreateRelease500JSONResponse struct { + ServiceInternalErrorJSONResponse +} + +func (response CreateRelease500JSONResponse) VisitCreateReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type CreateRelease503JSONResponse struct{ ServiceUnavailableJSONResponse } + +func (response CreateRelease503JSONResponse) VisitCreateReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type ActivateReleaseCompatibilityRequestObject struct { + Project Project `json:"project"` + Body *ActivateReleaseCompatibilityJSONRequestBody +} + +type ActivateReleaseCompatibilityResponseObject interface { + VisitActivateReleaseCompatibilityResponse(ctx fiber.Ctx) error +} + +type ActivateReleaseCompatibility200JSONResponse RawJSON + +func (response ActivateReleaseCompatibility200JSONResponse) VisitActivateReleaseCompatibilityResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type ActivateReleaseCompatibility400JSONResponse struct{ ServiceBadRequestJSONResponse } + +func (response ActivateReleaseCompatibility400JSONResponse) VisitActivateReleaseCompatibilityResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type ActivateReleaseCompatibility401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response ActivateReleaseCompatibility401JSONResponse) VisitActivateReleaseCompatibilityResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type ActivateReleaseCompatibility403JSONResponse struct{ ServiceForbiddenJSONResponse } + +func (response ActivateReleaseCompatibility403JSONResponse) VisitActivateReleaseCompatibilityResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type ActivateReleaseCompatibility404JSONResponse struct{ ServiceNotFoundJSONResponse } + +func (response ActivateReleaseCompatibility404JSONResponse) VisitActivateReleaseCompatibilityResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type ActivateReleaseCompatibility409JSONResponse struct{ ServiceConflictJSONResponse } + +func (response ActivateReleaseCompatibility409JSONResponse) VisitActivateReleaseCompatibilityResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type ActivateReleaseCompatibility422JSONResponse struct { + ServiceUnprocessableJSONResponse +} + +func (response ActivateReleaseCompatibility422JSONResponse) VisitActivateReleaseCompatibilityResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type ActivateReleaseCompatibility500JSONResponse struct { + ServiceInternalErrorJSONResponse +} + +func (response ActivateReleaseCompatibility500JSONResponse) VisitActivateReleaseCompatibilityResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type ActivateReleaseCompatibility503JSONResponse struct{ ServiceUnavailableJSONResponse } + +func (response ActivateReleaseCompatibility503JSONResponse) VisitActivateReleaseCompatibilityResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type GetActiveReleaseRequestObject struct { + Project Project `json:"project"` +} + +type GetActiveReleaseResponseObject interface { + VisitGetActiveReleaseResponse(ctx fiber.Ctx) error +} + +type GetActiveRelease200JSONResponse RawJSON + +func (response GetActiveRelease200JSONResponse) VisitGetActiveReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type GetActiveRelease401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response GetActiveRelease401JSONResponse) VisitGetActiveReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type GetActiveRelease403JSONResponse struct{ ServiceForbiddenJSONResponse } + +func (response GetActiveRelease403JSONResponse) VisitGetActiveReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type GetActiveRelease404JSONResponse struct{ ServiceNotFoundJSONResponse } + +func (response GetActiveRelease404JSONResponse) VisitGetActiveReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type GetActiveRelease500JSONResponse struct { + ServiceInternalErrorJSONResponse +} + +func (response GetActiveRelease500JSONResponse) VisitGetActiveReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type GetActiveRelease503JSONResponse struct{ ServiceUnavailableJSONResponse } + +func (response GetActiveRelease503JSONResponse) VisitGetActiveReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type GetReleaseRequestObject struct { + Project Project `json:"project"` + Release Release `json:"release"` +} + +type GetReleaseResponseObject interface { + VisitGetReleaseResponse(ctx fiber.Ctx) error +} + +type GetRelease200JSONResponse RawJSON + +func (response GetRelease200JSONResponse) VisitGetReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type GetRelease401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response GetRelease401JSONResponse) VisitGetReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type GetRelease403JSONResponse struct{ ServiceForbiddenJSONResponse } + +func (response GetRelease403JSONResponse) VisitGetReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type GetRelease404JSONResponse struct{ ServiceNotFoundJSONResponse } + +func (response GetRelease404JSONResponse) VisitGetReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type GetRelease500JSONResponse struct { + ServiceInternalErrorJSONResponse +} + +func (response GetRelease500JSONResponse) VisitGetReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type GetRelease503JSONResponse struct{ ServiceUnavailableJSONResponse } + +func (response GetRelease503JSONResponse) VisitGetReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type ActivateReleaseRequestObject struct { + Project Project `json:"project"` + Release Release `json:"release"` + Body *ActivateReleaseJSONRequestBody +} + +type ActivateReleaseResponseObject interface { + VisitActivateReleaseResponse(ctx fiber.Ctx) error +} + +type ActivateRelease200JSONResponse RawJSON + +func (response ActivateRelease200JSONResponse) VisitActivateReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type ActivateRelease400JSONResponse struct{ ServiceBadRequestJSONResponse } + +func (response ActivateRelease400JSONResponse) VisitActivateReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type ActivateRelease401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response ActivateRelease401JSONResponse) VisitActivateReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type ActivateRelease403JSONResponse struct{ ServiceForbiddenJSONResponse } + +func (response ActivateRelease403JSONResponse) VisitActivateReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type ActivateRelease404JSONResponse struct{ ServiceNotFoundJSONResponse } + +func (response ActivateRelease404JSONResponse) VisitActivateReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type ActivateRelease409JSONResponse struct{ ServiceConflictJSONResponse } + +func (response ActivateRelease409JSONResponse) VisitActivateReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(409) + + return ctx.JSON(&response) +} + +type ActivateRelease422JSONResponse struct { + ServiceUnprocessableJSONResponse +} + +func (response ActivateRelease422JSONResponse) VisitActivateReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type ActivateRelease500JSONResponse struct { + ServiceInternalErrorJSONResponse +} + +func (response ActivateRelease500JSONResponse) VisitActivateReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type ActivateRelease503JSONResponse struct{ ServiceUnavailableJSONResponse } + +func (response ActivateRelease503JSONResponse) VisitActivateReleaseResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type UploadProjectResourceRequestObject struct { + Project Project `json:"project"` + ResourceType ResourceType `json:"resourceType"` + Body *multipart.Reader +} + +type UploadProjectResourceResponseObject interface { + VisitUploadProjectResourceResponse(ctx fiber.Ctx) error +} + +type UploadProjectResource200JSONResponse RawJSON + +func (response UploadProjectResource200JSONResponse) VisitUploadProjectResourceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type UploadProjectResource400JSONResponse struct{ ServiceBadRequestJSONResponse } + +func (response UploadProjectResource400JSONResponse) VisitUploadProjectResourceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type UploadProjectResource401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response UploadProjectResource401JSONResponse) VisitUploadProjectResourceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type UploadProjectResource403JSONResponse struct{ ServiceForbiddenJSONResponse } + +func (response UploadProjectResource403JSONResponse) VisitUploadProjectResourceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type UploadProjectResource415JSONResponse struct { + ServiceUnsupportedMediaTypeJSONResponse +} + +func (response UploadProjectResource415JSONResponse) VisitUploadProjectResourceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(415) + + return ctx.JSON(&response) +} + +type UploadProjectResource422JSONResponse struct { + ServiceUnprocessableJSONResponse +} + +func (response UploadProjectResource422JSONResponse) VisitUploadProjectResourceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type UploadProjectResource500JSONResponse struct { + ServiceInternalErrorJSONResponse +} + +func (response UploadProjectResource500JSONResponse) VisitUploadProjectResourceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type UploadProjectResource503JSONResponse struct{ ServiceUnavailableJSONResponse } + +func (response UploadProjectResource503JSONResponse) VisitUploadProjectResourceResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type UploadRawNDJSONRequestObject struct { + Params UploadRawNDJSONParams + Body io.Reader +} + +type UploadRawNDJSONResponseObject interface { + VisitUploadRawNDJSONResponse(ctx fiber.Ctx) error +} + +type UploadRawNDJSON200JSONResponse RawJSON + +func (response UploadRawNDJSON200JSONResponse) VisitUploadRawNDJSONResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type UploadRawNDJSON400JSONResponse struct{ ServiceBadRequestJSONResponse } + +func (response UploadRawNDJSON400JSONResponse) VisitUploadRawNDJSONResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type UploadRawNDJSON401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response UploadRawNDJSON401JSONResponse) VisitUploadRawNDJSONResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type UploadRawNDJSON403JSONResponse struct{ ServiceForbiddenJSONResponse } + +func (response UploadRawNDJSON403JSONResponse) VisitUploadRawNDJSONResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(403) + + return ctx.JSON(&response) +} + +type UploadRawNDJSON415JSONResponse struct { + ServiceUnsupportedMediaTypeJSONResponse +} + +func (response UploadRawNDJSON415JSONResponse) VisitUploadRawNDJSONResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(415) + + return ctx.JSON(&response) +} + +type UploadRawNDJSON422JSONResponse struct { + ServiceUnprocessableJSONResponse +} + +func (response UploadRawNDJSON422JSONResponse) VisitUploadRawNDJSONResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type UploadRawNDJSON500JSONResponse struct { + ServiceInternalErrorJSONResponse +} + +func (response UploadRawNDJSON500JSONResponse) VisitUploadRawNDJSONResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type UploadRawNDJSON503JSONResponse struct{ ServiceUnavailableJSONResponse } + +func (response UploadRawNDJSON503JSONResponse) VisitUploadRawNDJSONResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type GetApolloSandboxRequestObject struct { +} + +type GetApolloSandboxResponseObject interface { + VisitGetApolloSandboxResponse(ctx fiber.Ctx) error +} + +type GetApolloSandbox200TexthtmlResponse struct{ HTMLTexthtmlResponse } + +func (response GetApolloSandbox200TexthtmlResponse) VisitGetApolloSandboxResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "text/html") + if response.ContentLength != 0 { + ctx.Response().Header.Set("Content-Length", fmt.Sprint(response.ContentLength)) + } + ctx.Status(200) + + if closer, ok := response.Body.(io.ReadCloser); ok { + defer closer.Close() + } + _, err := io.Copy(ctx.Response().BodyWriter(), response.Body) + return err +} + +type GetApolloSandbox401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response GetApolloSandbox401JSONResponse) VisitGetApolloSandboxResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type GetApolloSandbox404JSONResponse struct{ ServiceNotFoundJSONResponse } + +func (response GetApolloSandbox404JSONResponse) VisitGetApolloSandboxResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type ExecuteDataframeGraphQLRequestObject struct { + Body *ExecuteDataframeGraphQLJSONRequestBody +} + +type ExecuteDataframeGraphQLResponseObject interface { + VisitExecuteDataframeGraphQLResponse(ctx fiber.Ctx) error +} + +type ExecuteDataframeGraphQL200JSONResponse RawJSON + +func (response ExecuteDataframeGraphQL200JSONResponse) VisitExecuteDataframeGraphQLResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type ExecuteDataframeGraphQL400JSONResponse struct{ GraphQLBadRequestJSONResponse } + +func (response ExecuteDataframeGraphQL400JSONResponse) VisitExecuteDataframeGraphQLResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type ExecuteDataframeGraphQL401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response ExecuteDataframeGraphQL401JSONResponse) VisitExecuteDataframeGraphQLResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type ExecuteDataframeGraphQL422JSONResponse struct { + GraphQLUnprocessableJSONResponse +} + +func (response ExecuteDataframeGraphQL422JSONResponse) VisitExecuteDataframeGraphQLResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type ExecuteDataframeGraphQL500JSONResponse struct { + GraphQLInternalErrorJSONResponse +} + +func (response ExecuteDataframeGraphQL500JSONResponse) VisitExecuteDataframeGraphQLResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type GetGraphQLPlaygroundRequestObject struct { +} + +type GetGraphQLPlaygroundResponseObject interface { + VisitGetGraphQLPlaygroundResponse(ctx fiber.Ctx) error +} + +type GetGraphQLPlayground200TexthtmlResponse struct{ HTMLTexthtmlResponse } + +func (response GetGraphQLPlayground200TexthtmlResponse) VisitGetGraphQLPlaygroundResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "text/html") + if response.ContentLength != 0 { + ctx.Response().Header.Set("Content-Length", fmt.Sprint(response.ContentLength)) + } + ctx.Status(200) + + if closer, ok := response.Body.(io.ReadCloser); ok { + defer closer.Close() + } + _, err := io.Copy(ctx.Response().BodyWriter(), response.Body) + return err +} + +type GetGraphQLPlayground401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response GetGraphQLPlayground401JSONResponse) VisitGetGraphQLPlaygroundResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type GetGraphQLPlayground404JSONResponse struct{ ServiceNotFoundJSONResponse } + +func (response GetGraphQLPlayground404JSONResponse) VisitGetGraphQLPlaygroundResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(404) + + return ctx.JSON(&response) +} + +type ExecuteGraphQLRequestObject struct { + Body *ExecuteGraphQLJSONRequestBody +} + +type ExecuteGraphQLResponseObject interface { + VisitExecuteGraphQLResponse(ctx fiber.Ctx) error +} + +type ExecuteGraphQL200JSONResponse RawJSON + +func (response ExecuteGraphQL200JSONResponse) VisitExecuteGraphQLResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type ExecuteGraphQL400JSONResponse struct{ GraphQLBadRequestJSONResponse } + +func (response ExecuteGraphQL400JSONResponse) VisitExecuteGraphQLResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(400) + + return ctx.JSON(&response) +} + +type ExecuteGraphQL401JSONResponse struct { + ServiceUnauthorizedJSONResponse +} + +func (response ExecuteGraphQL401JSONResponse) VisitExecuteGraphQLResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(401) + + return ctx.JSON(&response) +} + +type ExecuteGraphQL422JSONResponse struct { + GraphQLUnprocessableJSONResponse +} + +func (response ExecuteGraphQL422JSONResponse) VisitExecuteGraphQLResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(422) + + return ctx.JSON(&response) +} + +type ExecuteGraphQL500JSONResponse struct { + GraphQLInternalErrorJSONResponse +} + +func (response ExecuteGraphQL500JSONResponse) VisitExecuteGraphQLResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(500) + + return ctx.JSON(&response) +} + +type GetHealthRequestObject struct { +} + +type GetHealthResponseObject interface { + VisitGetHealthResponse(ctx fiber.Ctx) error +} + +type GetHealth200JSONResponse RawJSON + +func (response GetHealth200JSONResponse) VisitGetHealthResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type GetHealth503JSONResponse RawJSON + +func (response GetHealth503JSONResponse) VisitGetHealthResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +type GetLivenessRequestObject struct { +} + +type GetLivenessResponseObject interface { + VisitGetLivenessResponse(ctx fiber.Ctx) error +} + +type GetLiveness200JSONResponse RawJSON + +func (response GetLiveness200JSONResponse) VisitGetLivenessResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type GetReadinessRequestObject struct { +} + +type GetReadinessResponseObject interface { + VisitGetReadinessResponse(ctx fiber.Ctx) error +} + +type GetReadiness200JSONResponse RawJSON + +func (response GetReadiness200JSONResponse) VisitGetReadinessResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(200) + + return ctx.JSON(&response) +} + +type GetReadiness503JSONResponse RawJSON + +func (response GetReadiness503JSONResponse) VisitGetReadinessResponse(ctx fiber.Ctx) error { + ctx.Response().Header.Set("Content-Type", "application/json") + ctx.Status(503) + + return ctx.JSON(&response) +} + +// StrictServerInterface represents all server handlers. +type StrictServerInterface interface { + // GetRecipeExecution Read public metadata for a dataframe recipe execution. + // (GET /api/v1/dataframe/recipe-executions/{id}) + GetRecipeExecution(ctx context.Context, request GetRecipeExecutionRequestObject) (GetRecipeExecutionResponseObject, error) + // CreateDatasetGeneration Upload a multipart dataset generation. + // (POST /api/v1/datasets/{project}/generations/{generation}) + CreateDatasetGeneration(ctx context.Context, request CreateDatasetGenerationRequestObject) (CreateDatasetGenerationResponseObject, error) + // ActivateDatasetGeneration Activate a generation after dataframe publication. + // (POST /api/v1/datasets/{project}/generations/{generation}/activate) + ActivateDatasetGeneration(ctx context.Context, request ActivateDatasetGenerationRequestObject) (ActivateDatasetGenerationResponseObject, error) + // GetRepositoryExplorerConfig Read the active repository-owned Explorer config. + // (GET /api/v1/projects/{project}/explorer-config) + GetRepositoryExplorerConfig(ctx context.Context, request GetRepositoryExplorerConfigRequestObject) (GetRepositoryExplorerConfigResponseObject, error) + // ListExplorers List Explorer summaries for a project. + // (GET /api/v1/projects/{project}/explorers) + ListExplorers(ctx context.Context, request ListExplorersRequestObject) (ListExplorersResponseObject, error) + // CreateExplorer Create an interactive Explorer. + // (POST /api/v1/projects/{project}/explorers) + CreateExplorer(ctx context.Context, request CreateExplorerRequestObject) (CreateExplorerResponseObject, error) + // GetExplorer Read an Explorer's active runtime projection. + // (GET /api/v1/projects/{project}/explorers/{explorerId}) + GetExplorer(ctx context.Context, request GetExplorerRequestObject) (GetExplorerResponseObject, error) + + // (GET /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/builder) + GetExplorerBuilder(ctx context.Context, request GetExplorerBuilderRequestObject) (GetExplorerBuilderResponseObject, error) + + // (POST /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/builder) + CompileExplorerBuilder(ctx context.Context, request CompileExplorerBuilderRequestObject) (CompileExplorerBuilderResponseObject, error) + + // (GET /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/capabilities/{snapshotToken}/candidates/{candidateId}/suggestions) + GetExplorerCandidateSuggestions(ctx context.Context, request GetExplorerCandidateSuggestionsRequestObject) (GetExplorerCandidateSuggestionsResponseObject, error) + + // (GET /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/capability) + GetExplorerAuthoringCapability(ctx context.Context, request GetExplorerAuthoringCapabilityRequestObject) (GetExplorerAuthoringCapabilityResponseObject, error) + + // (POST /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/commands) + ApplyExplorerBuilderCommands(ctx context.Context, request ApplyExplorerBuilderCommandsRequestObject) (ApplyExplorerBuilderCommandsResponseObject, error) + + // (POST /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/compile) + CompileExplorer(ctx context.Context, request CompileExplorerRequestObject) (CompileExplorerResponseObject, error) + + // (PUT /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/draft) + SaveExplorerDraft(ctx context.Context, request SaveExplorerDraftRequestObject) (SaveExplorerDraftResponseObject, error) + + // (GET /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/export) + ExportExplorerWorkspace(ctx context.Context, request ExportExplorerWorkspaceRequestObject) (ExportExplorerWorkspaceResponseObject, error) + + // (POST /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/preview) + PreviewExplorer(ctx context.Context, request PreviewExplorerRequestObject) (PreviewExplorerResponseObject, error) + + // (POST /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/publish) + PublishExplorer(ctx context.Context, request PublishExplorerRequestObject) (PublishExplorerResponseObject, error) + + // (POST /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/reconcile) + ReconcileExplorerBuilder(ctx context.Context, request ReconcileExplorerBuilderRequestObject) (ReconcileExplorerBuilderResponseObject, error) + + // (POST /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/suggestions) + SearchExplorerCandidates(ctx context.Context, request SearchExplorerCandidatesRequestObject) (SearchExplorerCandidatesResponseObject, error) + // AbortSnapshot Abort a generation snapshot. + // (DELETE /api/v1/projects/{project}/generations/{generation}) + AbortSnapshot(ctx context.Context, request AbortSnapshotRequestObject) (AbortSnapshotResponseObject, error) + // GetSnapshot Read generation snapshot status. + // (GET /api/v1/projects/{project}/generations/{generation}) + GetSnapshot(ctx context.Context, request GetSnapshotRequestObject) (GetSnapshotResponseObject, error) + // CreateSnapshot Create or resume an immutable generation snapshot. + // (POST /api/v1/projects/{project}/generations/{generation}) + CreateSnapshot(ctx context.Context, request CreateSnapshotRequestObject) (CreateSnapshotResponseObject, error) + // PublishRepositoryExplorerConfig Compile and publish a repository-owned Explorer workspace. + // (POST /api/v1/projects/{project}/generations/{generation}/explorer-config) + PublishRepositoryExplorerConfig(ctx context.Context, request PublishRepositoryExplorerConfigRequestObject) (PublishRepositoryExplorerConfigResponseObject, error) + // FinalizeSnapshot Validate and finalize an immutable generation snapshot. + // (POST /api/v1/projects/{project}/generations/{generation}/finalize) + FinalizeSnapshot(ctx context.Context, request FinalizeSnapshotRequestObject) (FinalizeSnapshotResponseObject, error) + // UploadSnapshotResource Stream one resource type into an immutable snapshot. + // (PUT /api/v1/projects/{project}/generations/{generation}/resources/{resourceType}) + UploadSnapshotResource(ctx context.Context, request UploadSnapshotResourceRequestObject) (UploadSnapshotResourceResponseObject, error) + // CreateRelease Create a durable project release candidate. + // (POST /api/v1/projects/{project}/releases) + CreateRelease(ctx context.Context, request CreateReleaseRequestObject) (CreateReleaseResponseObject, error) + // ActivateReleaseCompatibility Create and activate a release in one legacy operation. + // (POST /api/v1/projects/{project}/releases/activate) + // + // Deprecated: this operation has been marked as deprecated upstream, but no `x-deprecated-reason` was set + ActivateReleaseCompatibility(ctx context.Context, request ActivateReleaseCompatibilityRequestObject) (ActivateReleaseCompatibilityResponseObject, error) + // GetActiveRelease Read the active project release. + // (GET /api/v1/projects/{project}/releases/active) + GetActiveRelease(ctx context.Context, request GetActiveReleaseRequestObject) (GetActiveReleaseResponseObject, error) + // GetRelease Read a project release by ID. + // (GET /api/v1/projects/{project}/releases/{release}) + GetRelease(ctx context.Context, request GetReleaseRequestObject) (GetReleaseResponseObject, error) + // ActivateRelease Activate an existing durable release. + // (POST /api/v1/projects/{project}/releases/{release}/activate) + ActivateRelease(ctx context.Context, request ActivateReleaseRequestObject) (ActivateReleaseResponseObject, error) + // UploadProjectResource Upload one multipart NDJSON resource file. + // (PUT /api/v1/projects/{project}/resources/{resourceType}) + UploadProjectResource(ctx context.Context, request UploadProjectResourceRequestObject) (UploadProjectResourceResponseObject, error) + // UploadRawNDJSON Stream raw NDJSON into a generation. + // (PUT /api/v1/raw) + UploadRawNDJSON(ctx context.Context, request UploadRawNDJSONRequestObject) (UploadRawNDJSONResponseObject, error) + // GetApolloSandbox Render the Apollo GraphQL sandbox. + // (GET /apollo) + GetApolloSandbox(ctx context.Context, request GetApolloSandboxRequestObject) (GetApolloSandboxResponseObject, error) + // ExecuteDataframeGraphQL Execute a dataframe GraphQL operation. + // (POST /graphql/dataframe) + ExecuteDataframeGraphQL(ctx context.Context, request ExecuteDataframeGraphQLRequestObject) (ExecuteDataframeGraphQLResponseObject, error) + // GetGraphQLPlayground Render the GraphQL playground. + // (GET /graphql/graph) + GetGraphQLPlayground(ctx context.Context, request GetGraphQLPlaygroundRequestObject) (GetGraphQLPlaygroundResponseObject, error) + // ExecuteGraphQL Execute a graph or FHIR GraphQL operation. + // (POST /graphql/graph) + ExecuteGraphQL(ctx context.Context, request ExecuteGraphQLRequestObject) (ExecuteGraphQLResponseObject, error) + // GetHealth Report cached core and dataframe health. + // (GET /health) + GetHealth(ctx context.Context, request GetHealthRequestObject) (GetHealthResponseObject, error) + // GetLiveness Report process liveness without checking dependencies. + // (GET /livez) + GetLiveness(ctx context.Context, request GetLivenessRequestObject) (GetLivenessResponseObject, error) + // GetReadiness Report whether required dependencies are ready. + // (GET /readyz) + GetReadiness(ctx context.Context, request GetReadinessRequestObject) (GetReadinessResponseObject, error) +} + +type StrictHandlerFunc func(ctx fiber.Ctx, args any) (any, error) + +type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc + +func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface { + return &strictHandler{ssi: ssi, middlewares: middlewares} +} + +type strictHandler struct { + ssi StrictServerInterface + middlewares []StrictMiddlewareFunc +} + +// GetRecipeExecution operation middleware +func (sh *strictHandler) GetRecipeExecution(ctx fiber.Ctx, id string) error { + var request GetRecipeExecutionRequestObject + + request.Id = id + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.GetRecipeExecution(ctx.Context(), request.(GetRecipeExecutionRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetRecipeExecution") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(GetRecipeExecutionResponseObject); ok { + if err := validResponse.VisitGetRecipeExecutionResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// CreateDatasetGeneration operation middleware +func (sh *strictHandler) CreateDatasetGeneration(ctx fiber.Ctx, project Project, generation Generation) error { + var request CreateDatasetGenerationRequestObject + + request.Project = project + request.Generation = generation + + request.Body = multipart.NewReader(bytes.NewReader(ctx.Request().Body()), string(ctx.Request().Header.MultipartFormBoundary())) + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.CreateDatasetGeneration(ctx.Context(), request.(CreateDatasetGenerationRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "CreateDatasetGeneration") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(CreateDatasetGenerationResponseObject); ok { + if err := validResponse.VisitCreateDatasetGenerationResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// ActivateDatasetGeneration operation middleware +func (sh *strictHandler) ActivateDatasetGeneration(ctx fiber.Ctx, project Project, generation Generation, params ActivateDatasetGenerationParams) error { + var request ActivateDatasetGenerationRequestObject + + request.Project = project + request.Generation = generation + request.Params = params + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.ActivateDatasetGeneration(ctx.Context(), request.(ActivateDatasetGenerationRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ActivateDatasetGeneration") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(ActivateDatasetGenerationResponseObject); ok { + if err := validResponse.VisitActivateDatasetGenerationResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// GetRepositoryExplorerConfig operation middleware +func (sh *strictHandler) GetRepositoryExplorerConfig(ctx fiber.Ctx, project Project) error { + var request GetRepositoryExplorerConfigRequestObject + + request.Project = project + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.GetRepositoryExplorerConfig(ctx.Context(), request.(GetRepositoryExplorerConfigRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetRepositoryExplorerConfig") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(GetRepositoryExplorerConfigResponseObject); ok { + if err := validResponse.VisitGetRepositoryExplorerConfigResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// ListExplorers operation middleware +func (sh *strictHandler) ListExplorers(ctx fiber.Ctx, project Project) error { + var request ListExplorersRequestObject + + request.Project = project + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.ListExplorers(ctx.Context(), request.(ListExplorersRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ListExplorers") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(ListExplorersResponseObject); ok { + if err := validResponse.VisitListExplorersResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// CreateExplorer operation middleware +func (sh *strictHandler) CreateExplorer(ctx fiber.Ctx, project Project) error { + var request CreateExplorerRequestObject + + request.Project = project + + var body CreateExplorerJSONRequestBody + if err := ctx.Bind().Body(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.CreateExplorer(ctx.Context(), request.(CreateExplorerRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "CreateExplorer") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(CreateExplorerResponseObject); ok { + if err := validResponse.VisitCreateExplorerResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// GetExplorer operation middleware +func (sh *strictHandler) GetExplorer(ctx fiber.Ctx, project Project, explorerId ExplorerId) error { + var request GetExplorerRequestObject + + request.Project = project + request.ExplorerId = explorerId + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.GetExplorer(ctx.Context(), request.(GetExplorerRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetExplorer") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(GetExplorerResponseObject); ok { + if err := validResponse.VisitGetExplorerResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// GetExplorerBuilder operation middleware +func (sh *strictHandler) GetExplorerBuilder(ctx fiber.Ctx, project Project, explorerId ExplorerId) error { + var request GetExplorerBuilderRequestObject + + request.Project = project + request.ExplorerId = explorerId + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.GetExplorerBuilder(ctx.Context(), request.(GetExplorerBuilderRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetExplorerBuilder") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(GetExplorerBuilderResponseObject); ok { + if err := validResponse.VisitGetExplorerBuilderResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// CompileExplorerBuilder operation middleware +func (sh *strictHandler) CompileExplorerBuilder(ctx fiber.Ctx, project Project, explorerId ExplorerId) error { + var request CompileExplorerBuilderRequestObject + + request.Project = project + request.ExplorerId = explorerId + + var body CompileExplorerBuilderJSONRequestBody + if err := ctx.Bind().Body(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.CompileExplorerBuilder(ctx.Context(), request.(CompileExplorerBuilderRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "CompileExplorerBuilder") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(CompileExplorerBuilderResponseObject); ok { + if err := validResponse.VisitCompileExplorerBuilderResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// GetExplorerCandidateSuggestions operation middleware +func (sh *strictHandler) GetExplorerCandidateSuggestions(ctx fiber.Ctx, project Project, explorerId ExplorerId, snapshotToken string, candidateId string) error { + var request GetExplorerCandidateSuggestionsRequestObject + + request.Project = project + request.ExplorerId = explorerId + request.SnapshotToken = snapshotToken + request.CandidateId = candidateId + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.GetExplorerCandidateSuggestions(ctx.Context(), request.(GetExplorerCandidateSuggestionsRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetExplorerCandidateSuggestions") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(GetExplorerCandidateSuggestionsResponseObject); ok { + if err := validResponse.VisitGetExplorerCandidateSuggestionsResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// GetExplorerAuthoringCapability operation middleware +func (sh *strictHandler) GetExplorerAuthoringCapability(ctx fiber.Ctx, project Project, explorerId ExplorerId) error { + var request GetExplorerAuthoringCapabilityRequestObject + + request.Project = project + request.ExplorerId = explorerId + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.GetExplorerAuthoringCapability(ctx.Context(), request.(GetExplorerAuthoringCapabilityRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetExplorerAuthoringCapability") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(GetExplorerAuthoringCapabilityResponseObject); ok { + if err := validResponse.VisitGetExplorerAuthoringCapabilityResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// ApplyExplorerBuilderCommands operation middleware +func (sh *strictHandler) ApplyExplorerBuilderCommands(ctx fiber.Ctx, project Project, explorerId ExplorerId) error { + var request ApplyExplorerBuilderCommandsRequestObject + + request.Project = project + request.ExplorerId = explorerId + + var body ApplyExplorerBuilderCommandsJSONRequestBody + if err := ctx.Bind().Body(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.ApplyExplorerBuilderCommands(ctx.Context(), request.(ApplyExplorerBuilderCommandsRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ApplyExplorerBuilderCommands") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(ApplyExplorerBuilderCommandsResponseObject); ok { + if err := validResponse.VisitApplyExplorerBuilderCommandsResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// CompileExplorer operation middleware +func (sh *strictHandler) CompileExplorer(ctx fiber.Ctx, project Project, explorerId ExplorerId) error { + var request CompileExplorerRequestObject + + request.Project = project + request.ExplorerId = explorerId + + var body CompileExplorerJSONRequestBody + if err := ctx.Bind().Body(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.CompileExplorer(ctx.Context(), request.(CompileExplorerRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "CompileExplorer") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(CompileExplorerResponseObject); ok { + if err := validResponse.VisitCompileExplorerResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// SaveExplorerDraft operation middleware +func (sh *strictHandler) SaveExplorerDraft(ctx fiber.Ctx, project Project, explorerId ExplorerId) error { + var request SaveExplorerDraftRequestObject + + request.Project = project + request.ExplorerId = explorerId + + var body SaveExplorerDraftJSONRequestBody + if err := ctx.Bind().Body(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.SaveExplorerDraft(ctx.Context(), request.(SaveExplorerDraftRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "SaveExplorerDraft") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(SaveExplorerDraftResponseObject); ok { + if err := validResponse.VisitSaveExplorerDraftResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// ExportExplorerWorkspace operation middleware +func (sh *strictHandler) ExportExplorerWorkspace(ctx fiber.Ctx, project Project, explorerId ExplorerId) error { + var request ExportExplorerWorkspaceRequestObject + + request.Project = project + request.ExplorerId = explorerId + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.ExportExplorerWorkspace(ctx.Context(), request.(ExportExplorerWorkspaceRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ExportExplorerWorkspace") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(ExportExplorerWorkspaceResponseObject); ok { + if err := validResponse.VisitExportExplorerWorkspaceResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// PreviewExplorer operation middleware +func (sh *strictHandler) PreviewExplorer(ctx fiber.Ctx, project Project, explorerId ExplorerId) error { + var request PreviewExplorerRequestObject + + request.Project = project + request.ExplorerId = explorerId + + var body PreviewExplorerJSONRequestBody + if err := ctx.Bind().Body(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.PreviewExplorer(ctx.Context(), request.(PreviewExplorerRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "PreviewExplorer") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(PreviewExplorerResponseObject); ok { + if err := validResponse.VisitPreviewExplorerResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// PublishExplorer operation middleware +func (sh *strictHandler) PublishExplorer(ctx fiber.Ctx, project Project, explorerId ExplorerId) error { + var request PublishExplorerRequestObject + + request.Project = project + request.ExplorerId = explorerId + + var body PublishExplorerJSONRequestBody + if err := ctx.Bind().Body(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.PublishExplorer(ctx.Context(), request.(PublishExplorerRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "PublishExplorer") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(PublishExplorerResponseObject); ok { + if err := validResponse.VisitPublishExplorerResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// ReconcileExplorerBuilder operation middleware +func (sh *strictHandler) ReconcileExplorerBuilder(ctx fiber.Ctx, project Project, explorerId ExplorerId) error { + var request ReconcileExplorerBuilderRequestObject + + request.Project = project + request.ExplorerId = explorerId + + var body ReconcileExplorerBuilderJSONRequestBody + if err := ctx.Bind().Body(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.ReconcileExplorerBuilder(ctx.Context(), request.(ReconcileExplorerBuilderRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ReconcileExplorerBuilder") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(ReconcileExplorerBuilderResponseObject); ok { + if err := validResponse.VisitReconcileExplorerBuilderResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// SearchExplorerCandidates operation middleware +func (sh *strictHandler) SearchExplorerCandidates(ctx fiber.Ctx, project Project, explorerId ExplorerId) error { + var request SearchExplorerCandidatesRequestObject + + request.Project = project + request.ExplorerId = explorerId + + var body SearchExplorerCandidatesJSONRequestBody + if err := ctx.Bind().Body(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.SearchExplorerCandidates(ctx.Context(), request.(SearchExplorerCandidatesRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "SearchExplorerCandidates") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(SearchExplorerCandidatesResponseObject); ok { + if err := validResponse.VisitSearchExplorerCandidatesResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// AbortSnapshot operation middleware +func (sh *strictHandler) AbortSnapshot(ctx fiber.Ctx, project Project, generation Generation) error { + var request AbortSnapshotRequestObject + + request.Project = project + request.Generation = generation + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.AbortSnapshot(ctx.Context(), request.(AbortSnapshotRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "AbortSnapshot") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(AbortSnapshotResponseObject); ok { + if err := validResponse.VisitAbortSnapshotResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// GetSnapshot operation middleware +func (sh *strictHandler) GetSnapshot(ctx fiber.Ctx, project Project, generation Generation) error { + var request GetSnapshotRequestObject + + request.Project = project + request.Generation = generation + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.GetSnapshot(ctx.Context(), request.(GetSnapshotRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetSnapshot") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(GetSnapshotResponseObject); ok { + if err := validResponse.VisitGetSnapshotResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// CreateSnapshot operation middleware +func (sh *strictHandler) CreateSnapshot(ctx fiber.Ctx, project Project, generation Generation) error { + var request CreateSnapshotRequestObject + + request.Project = project + request.Generation = generation + + var body CreateSnapshotJSONRequestBody + if err := ctx.Bind().Body(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.CreateSnapshot(ctx.Context(), request.(CreateSnapshotRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "CreateSnapshot") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(CreateSnapshotResponseObject); ok { + if err := validResponse.VisitCreateSnapshotResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// PublishRepositoryExplorerConfig operation middleware +func (sh *strictHandler) PublishRepositoryExplorerConfig(ctx fiber.Ctx, project Project, generation Generation, params PublishRepositoryExplorerConfigParams) error { + var request PublishRepositoryExplorerConfigRequestObject + + request.Project = project + request.Generation = generation + request.Params = params + + var body PublishRepositoryExplorerConfigJSONRequestBody + if err := ctx.Bind().Body(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.PublishRepositoryExplorerConfig(ctx.Context(), request.(PublishRepositoryExplorerConfigRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "PublishRepositoryExplorerConfig") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(PublishRepositoryExplorerConfigResponseObject); ok { + if err := validResponse.VisitPublishRepositoryExplorerConfigResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// FinalizeSnapshot operation middleware +func (sh *strictHandler) FinalizeSnapshot(ctx fiber.Ctx, project Project, generation Generation) error { + var request FinalizeSnapshotRequestObject + + request.Project = project + request.Generation = generation + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.FinalizeSnapshot(ctx.Context(), request.(FinalizeSnapshotRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "FinalizeSnapshot") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(FinalizeSnapshotResponseObject); ok { + if err := validResponse.VisitFinalizeSnapshotResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// UploadSnapshotResource operation middleware +func (sh *strictHandler) UploadSnapshotResource(ctx fiber.Ctx, project Project, generation Generation, resourceType ResourceType, params UploadSnapshotResourceParams) error { + var request UploadSnapshotResourceRequestObject + + request.Project = project + request.Generation = generation + request.ResourceType = resourceType + request.Params = params + + request.Body = bytes.NewReader(ctx.Request().Body()) + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.UploadSnapshotResource(ctx.Context(), request.(UploadSnapshotResourceRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "UploadSnapshotResource") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(UploadSnapshotResourceResponseObject); ok { + if err := validResponse.VisitUploadSnapshotResourceResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// CreateRelease operation middleware +func (sh *strictHandler) CreateRelease(ctx fiber.Ctx, project Project) error { + var request CreateReleaseRequestObject + + request.Project = project + + var body CreateReleaseJSONRequestBody + if err := ctx.Bind().Body(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.CreateRelease(ctx.Context(), request.(CreateReleaseRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "CreateRelease") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(CreateReleaseResponseObject); ok { + if err := validResponse.VisitCreateReleaseResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// ActivateReleaseCompatibility operation middleware +func (sh *strictHandler) ActivateReleaseCompatibility(ctx fiber.Ctx, project Project) error { + var request ActivateReleaseCompatibilityRequestObject + + request.Project = project + + var body ActivateReleaseCompatibilityJSONRequestBody + if err := ctx.Bind().Body(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.ActivateReleaseCompatibility(ctx.Context(), request.(ActivateReleaseCompatibilityRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ActivateReleaseCompatibility") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(ActivateReleaseCompatibilityResponseObject); ok { + if err := validResponse.VisitActivateReleaseCompatibilityResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// GetActiveRelease operation middleware +func (sh *strictHandler) GetActiveRelease(ctx fiber.Ctx, project Project) error { + var request GetActiveReleaseRequestObject + + request.Project = project + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.GetActiveRelease(ctx.Context(), request.(GetActiveReleaseRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetActiveRelease") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(GetActiveReleaseResponseObject); ok { + if err := validResponse.VisitGetActiveReleaseResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// GetRelease operation middleware +func (sh *strictHandler) GetRelease(ctx fiber.Ctx, project Project, release Release) error { + var request GetReleaseRequestObject + + request.Project = project + request.Release = release + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.GetRelease(ctx.Context(), request.(GetReleaseRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetRelease") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(GetReleaseResponseObject); ok { + if err := validResponse.VisitGetReleaseResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// ActivateRelease operation middleware +func (sh *strictHandler) ActivateRelease(ctx fiber.Ctx, project Project, release Release) error { + var request ActivateReleaseRequestObject + + request.Project = project + request.Release = release + + var body ActivateReleaseJSONRequestBody + if err := ctx.Bind().Body(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.ActivateRelease(ctx.Context(), request.(ActivateReleaseRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ActivateRelease") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(ActivateReleaseResponseObject); ok { + if err := validResponse.VisitActivateReleaseResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// UploadProjectResource operation middleware +func (sh *strictHandler) UploadProjectResource(ctx fiber.Ctx, project Project, resourceType ResourceType) error { + var request UploadProjectResourceRequestObject + + request.Project = project + request.ResourceType = resourceType + + request.Body = multipart.NewReader(bytes.NewReader(ctx.Request().Body()), string(ctx.Request().Header.MultipartFormBoundary())) + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.UploadProjectResource(ctx.Context(), request.(UploadProjectResourceRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "UploadProjectResource") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(UploadProjectResourceResponseObject); ok { + if err := validResponse.VisitUploadProjectResourceResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// UploadRawNDJSON operation middleware +func (sh *strictHandler) UploadRawNDJSON(ctx fiber.Ctx, params UploadRawNDJSONParams) error { + var request UploadRawNDJSONRequestObject + + request.Params = params + + request.Body = bytes.NewReader(ctx.Request().Body()) + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.UploadRawNDJSON(ctx.Context(), request.(UploadRawNDJSONRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "UploadRawNDJSON") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(UploadRawNDJSONResponseObject); ok { + if err := validResponse.VisitUploadRawNDJSONResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// GetApolloSandbox operation middleware +func (sh *strictHandler) GetApolloSandbox(ctx fiber.Ctx) error { + var request GetApolloSandboxRequestObject + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.GetApolloSandbox(ctx.Context(), request.(GetApolloSandboxRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetApolloSandbox") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(GetApolloSandboxResponseObject); ok { + if err := validResponse.VisitGetApolloSandboxResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// ExecuteDataframeGraphQL operation middleware +func (sh *strictHandler) ExecuteDataframeGraphQL(ctx fiber.Ctx) error { + var request ExecuteDataframeGraphQLRequestObject + + var body ExecuteDataframeGraphQLJSONRequestBody + if err := ctx.Bind().Body(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.ExecuteDataframeGraphQL(ctx.Context(), request.(ExecuteDataframeGraphQLRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ExecuteDataframeGraphQL") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(ExecuteDataframeGraphQLResponseObject); ok { + if err := validResponse.VisitExecuteDataframeGraphQLResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// GetGraphQLPlayground operation middleware +func (sh *strictHandler) GetGraphQLPlayground(ctx fiber.Ctx) error { + var request GetGraphQLPlaygroundRequestObject + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.GetGraphQLPlayground(ctx.Context(), request.(GetGraphQLPlaygroundRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetGraphQLPlayground") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(GetGraphQLPlaygroundResponseObject); ok { + if err := validResponse.VisitGetGraphQLPlaygroundResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// ExecuteGraphQL operation middleware +func (sh *strictHandler) ExecuteGraphQL(ctx fiber.Ctx) error { + var request ExecuteGraphQLRequestObject + + var body ExecuteGraphQLJSONRequestBody + if err := ctx.Bind().Body(&body); err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + request.Body = &body + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.ExecuteGraphQL(ctx.Context(), request.(ExecuteGraphQLRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ExecuteGraphQL") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(ExecuteGraphQLResponseObject); ok { + if err := validResponse.VisitExecuteGraphQLResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// GetHealth operation middleware +func (sh *strictHandler) GetHealth(ctx fiber.Ctx) error { + var request GetHealthRequestObject + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.GetHealth(ctx.Context(), request.(GetHealthRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetHealth") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(GetHealthResponseObject); ok { + if err := validResponse.VisitGetHealthResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// GetLiveness operation middleware +func (sh *strictHandler) GetLiveness(ctx fiber.Ctx) error { + var request GetLivenessRequestObject + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.GetLiveness(ctx.Context(), request.(GetLivenessRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetLiveness") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(GetLivenessResponseObject); ok { + if err := validResponse.VisitGetLivenessResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// GetReadiness operation middleware +func (sh *strictHandler) GetReadiness(ctx fiber.Ctx) error { + var request GetReadinessRequestObject + + handler := func(ctx fiber.Ctx, request interface{}) (interface{}, error) { + return sh.ssi.GetReadiness(ctx.Context(), request.(GetReadinessRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetReadiness") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(GetReadinessResponseObject); ok { + if err := validResponse.VisitGetReadinessResponse(ctx); err != nil { + return err + } + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec. +// Stored as a slice of fixed-width chunks rather than one concatenated +// const string: with thousands of chunks the chained `+` fold is several +// times slower for the Go compiler than parsing a slice literal. +var swaggerSpec = []string{ + "7D39b9u4kv8KoXvAAgcnTrt9D9jcT2mStjmkaZ6T7t67Ra5gpLHNV4nUklQSt8j/fuCXRMn6dGwnu/VP", + "rWJKHA7ne8iZ70HIkpRRoFIEh9+DFHOcgASun04f0phx4GeReiI0OAxSLOfBKKA4geAwgGLAKODwR0Y4", + "RMGh5BmMAhHOIcHqzYTQc6AzOQ8OX40CuUjVu0JyQmfB4+MoeA8UOJaE0YZ5ZsWAp8xzydm/IZQNk6T2", + "16fMMIEYsICGGbj99WkzCJbxEK71Lw3TeENWn+tRvSpSRgVoajjK5Jyp397iaAJ/ZCA0JkNGJVD9X5ym", + "MQn1Po3/LcxuFrP9jcM0OAz+Y1yQ3Nj8KsannDM+sbOZuSMQISepoYrgeg7ov68+XaCIhVkCVCIiUILj", + "KeMJRCOkoMCECpTRr5TdUzQlEEdihBhHLCFSIIcGhN06EKFpJveDx1GxtuOYAJXHMRPwPIsMNQAoxDSE", + "GCKUcrgjcI/gAcJMjUO3MGUckJogBvWXygoYncYk3CLYZ0mSSXwbAwpxim9JTORC4Z1DCCSVSEgsQe2X", + "kDgGsyWpJAkRkoQo4ngqx2l268Cz48M5pjOIyot7x/gtiSKg290URTJApZpBbwmhIUlxrHaJMok44Eit", + "KmERmS6QnBOBnOxEVqyU1/EeS7jHi2uSAMu2uFWXS9QEDyFABBFSPCKA3wHfEyQCFAGOYkKhDPgZlcAp", + "jvVM24P7iKKMwkMKofQ5eIRS4IIICTQ0hOXYZYpJnHFALAwzzqtkdMHkO5bRaLtU5EhipOgmIhGWMNJs", + "TGJD+JZhDIfIOSg+sXpvT6QQkikJPfHl5DyKGAikCBEeiKhQ2iVexAxH14ydYz6D7a74ViHZE2IcRBZL", + "S3MCyTmgBD+QJEuQUzVIkG8Vmrtm7COmCyuOxXaXwM2s3iLSGNPSEgzX/CQKrtoLmZAoZTEJF+W1fKb4", + "DpNYScstck+h/AoJPfLkM+MwQgmWwAmOyTdFojiU5M7KY+B3xPLXLQ6/Ao2UNM+KpVTXmHIWghDbXaW3", + "Wwq8OxyTyNgMt5nU4u2e8a8ixaFhuwTTaIRYJtPMsJzPikRDrJUWJFiL/jheIEL1Z/V633Oczv95vgFr", + "aILvFdxNi7QTow/X15f5ioHeQcxSUAuRHFORMi5RYc8jzKEwmPwFbEakt6zBwV8oISWtIXKWDUaU8QTH", + "+UJz2RCyLFbDlFKNsrC8js2QXc+9yM1SA6ISxgpMzAVo00CTjbYepowXK9fwf7j+eF6BV8KDHM9lEpcB", + "rTHRyyCdKgWgdMMtZ/cCOPp8loOm5zqHGQ4XG6BZ8+FeTBrroYWF5DFtTqDanCJCGD1nhVdhr5vZ1m7q", + "DlhEDj2Olfm3MLpXGLs3ZYJIxhcogjRmC00YJatWDSMCERoyauwXf13rt3IHLKzD1sWhYrEWG9dMtRmh", + "0nMZE8CRIhxlDxr7UD1Jf9esxCmMynjhQb92+3AVwipR0h67pxAVP4aMTsksM8YhusfG/psqoL11bMLa", + "6L0HORN4etW3Muwf9DJ1XMS3OYhZkFum4ZiqxeEWuQm5v8qO5faFAtZjfWVFLKhUyzNmhLFNlFliueoW", + "LJYgKhlikXFqlHMs5lbdXRlzbAMy3H55iD2ZYjkfoT8y4IsRSrJYkhRzOdJ2l4b94kSbYHc4znQMwAl1", + "JQA9Y8pOvXaJ3ndJXgzDTFu2gKXx1TIuGHdPbmPKUQu7AIHuiZxrmWPVm7/M9Qv4vutsk/AxDr+KXMAz", + "H3g9Tst4w6/W8RQhS8Ff2GbEfm+6LEUJjFuGQL2VxwH+C0UgMYmNPcwhwiaiQCMUMs4h1ji5XbiFn5XI", + "c+16Yci2FVsRYYkFyBEq4uIjJ0S1W0dSKGxMI2JZJqHYuGWFYSH5TG184Rtsf5VHBWEqjgo5ROoR293C", + "t0JJ03rJsQlVt4I8dNizm6JcazyDESJ0BsL8zRMaemu08GxzrPMVbkLPrUCBbfpMudmKPMu06el4iyml", + "F4Wn/ezSoLKnIkuVHwvRR4gIdjmPrS782Ey2pyZ3ZkkOlpIU2hTO0pjhqIjX7etkjZ1LZ08uz35VtqgB", + "EWiWBIe/BzFjyX6I40XK9xmfjV1CbS+P8o3vXgc3S8mZUXAUunwZjiKi/o/jS67mlwREcDjFsYBRkHp/", + "UoiLs4Tq/xIJiejCkZnkWL+lJrVQYM7xQj1PSQwXOun0fRlCSaSh09Y0k/tDd+aryGP9bn51UxToYbc6", + "g5ejx0K+CpJ6AA4Pigg+AI6A13nnZZDtZ2uBTdN4cWwiUsIz6gYBrd82mdoOuO3YAWRQ5Jb0m+ojCaFn", + "5t1Xy3ThdPAJx1N5QmZ2PXUYLMZ57DFlPMEyOAwIlf94E+jZSKJY5iCfjFAJM+DqM4LiVMyZvGZfgQ4l", + "pQJz1Q81wOchsMdmWsGyud2MCJ5RJiQJ+2/oSf5OHVdH5V3rmr/33r2q2zuTEugPusXsRL9WB33uhHV9", + "6bd8YBtJFJ+rLLWMp2Ih5R2ppZCcnfJg/ED6wCnxMN7KuoXaUfIasMw49Gf4d+6Fx1HwlRjD1+ku5/Yu", + "L0dBWaezcu1Y3m73wduMxEqUagZTvrDiyGxmDSeFWZuCUf8zLrHbhcBJY5871Z6EjIakpCOqiqegHPv1", + "c5KQCkHaJFVw+Org4KCLosufrZCWt3MWoyW0VIHwtqydkqxgHihmXBqyp9roqRfNwF+Vx9/Nzc60gGjW", + "DwxCiXIJLjkobyA/NeSI6Pro7flpMArenZ1fn06CUXD84WhyXU+OxiekYb+JTaZo0NAKFfWxgzxyxByo", + "/DQMSOulE0Y/sqgT/Zfl0YpWGZMXLOo3mXEmP/XHy1CT0G3q8eT06Pr0i9vbk8+X52fHpb+cnp96j5PT", + "i6OP/uOnycnpxDxfBaPg6vTaPHyZfPp0HYyCo5OTL5NPn6/N6I+ffj3NH9VPx5/OP3+8CEbB58sTNW3+", + "bMfa55teZmsrI7/zJPQATo4gBglOInu21i1jMWDDYTr0xujxHHMj35rHvCOxOwS4PEhZ/ca+bhzwAFHr", + "J8Qc89YhFcRV4VpaTfWTFSDKQI+q+KrbkrdGG11JLGFL6jnEEsds1ik07bBlU+0JxlmtYd2k8ku4qROt", + "MZlCuAhjyNHnPnFx+pvmm6OTf9W+WTLfcBx/mgaHv/c25G5GAc1iGwWSPIM++rcCbIed5xuEbsPq6OfY", + "KdcrwDycr+bW0b6iWAeRakngSc5R1SGy8PRa70qez+qsY2cf4EmYzcvhrnWF1u5cdbBUgUXP8K3jk96U", + "8aT9r2OXBpoo7UG3E1S70C3TSt9oSaqURb0ia9rO3vs4bHtGgeQZ1Ymbenh0nq1Mqx2G5go77iMwn9LD", + "lA9l/d7nem7Idvuh9auQpdA7RrEh6dBOGsqjGTzfaTSrnWpWuiLRsVzFkYNnvrAeQHVmDoLFdxBd6eEt", + "toZOMV3qM4+dh6q8oU8VUaW7IY00UkPEBbUafLkdqwgyf1ktxFwQykZ9cGXtuvzPMslFMMVZLC+f6ATq", + "uxOXWAHRCdFUW9jNIMX4FuIe34nZjIQ4vu6TDBig/cr+cH+mWEbKMl+k0CSHq/HEkrzM9WWBZoemMhq8", + "OUp49slgeYVNVNBCu1roDCPb3uGaKWdJ74BCX2JJWZrFzUpQsp4zVr1Ms6gS0N7Xil0q5m/B6oXlvSFu", + "vD2qecwyk94c6K/1Z4t2BPLKJbOOr3F2/55jQhvUwv2EMXkakxlpkBKVbcgZpHqRrfKlzn1QXFKNEw7Y", + "DcZtYq8d6XlQa32ZzdrVrJTLVCjoNACW8FSK9qZYSuA0OAz+7/ejvf/Fe9++3Nj/HOz98uXmP/8WNOqF", + "rqlNfKY694o646kBXkNs/ULWV2as2mSn+9peulaDysusTw8XMqYEfA5cM2Vc5dAPoI+Spl9CSNW50aOD", + "UUD0sZwpAf52cbUQEhKdf5FAld/wdvGZx9rAigideSPYrQBuTtQdOxS9XRwrMZmrsVJwoYAkwTKsh3E5", + "4O2g/fXo/LPJBEyudIz3/DwYBSdnV9dnF8fX3cFavfp6fPspyFUPF3RSa2sCYlnW4NumXyrBdBP4NiH1", + "k2Dknj8cXbzXzzrw/eXo5EQ/mdC2fbx5gvTSGb3VomBDfeQ1pID9KF95+tbVbTXm5fKl/ReZZ1a5N+HW", + "zxcM8mXNRazenn5HeG1irrzVpwM1e/VfpP2WSX/Vewh6wPNE6YrJl13fkstcQvAygYy8tLzDUI/oHqOS", + "41CubrQ0e5S989C9XdMnOaNderzs0TW4cXU49JhoqI4xirBiuGmjrcViswejmycz5SOW4Py3YLTRhEhA", + "CDzr5US4A9f1WQy4A24PynSxkuwzYTXR4b7v3h8ZNBYrqN0i668NFfjh8iGY7mOY9RHIYQc6245ylnO2", + "vT73rnhphVxHjr1madwFQCF8OWNyMtRtzST0ClWa2GidfZgDWgOBm6HYpjoa0geQ37Jo0cV49UzeW3sP", + "09nr4dsl2djJUeXj2AOjJ2u3VMBdY+m8mK43cCmepF+vXablhI8gcYQlHnzcwzuhvvLR66rt3niY+l35", + "wMdqkq7+reb0VDF97lm2fqdvvmtpguqmFbONcvgbsFKNXQxDTrP90Svy9FgLUyGQN3TqvU+GseVweJO5", + "ZD9bh2jvKubqcrLNMnmy1Kq7LNoBZeXevr6kltdw4MoUo+Z6SfW2PKaRveK1VxRQ0IpG7AdLYXonwCrT", + "EV1dBruP27UhgwHE1E9C8iyU+uqtwsDYjTGrHqEIUqDmmjU1VwUVDAoERsGe2qkivfeVWyNOb/oL1E+5", + "uTCA5knUL7h93sioKwlaErVeXbE1mlYLlcQkIXLwkeUBR1v7O7WVVfsOaT5f6/q3e4BosCVd8nBfwtkh", + "i7gWc3rNO6yZI89VtWdJOLsvo2GQjzn4yEottRW7bOHxFtAd07hsjDRfHR+dH038UPNkcvQvL9j8xf3B", + "xaQ7Y9Gj4LK4JrqScKsUWlj3EXfhDnYOkQHeTgh71nIZzFrcm+seq8nENYisVpi2Kqe2L1UKOlxL2HSZ", + "rp8YOlVST/Sl8JXItkvAeBAUhN0/WOpKTA2yGHVVjfs5E2AqDylDTMyxuaOcKqeE30GEYiZEDELECxRl", + "pmqgrgQQZpLdAd8P6uApBbY3e8O4W40O0Vxt5xBWMtU8gWXe9yZpD+tM3NWz1WTWVu9grvWIeMvh+Vo8", + "5fG1oUkCEkfcgNsvXVME8mqIbNhJAV0nhDAq5iStP/QyJBJZpbly4r/0qUYMFucuh+igOGb3E3vG7NQd", + "V11OlOhxVxBPzxlLG8Yk+OFKQip6RC1KonUZhKX56hZ9he9A38pejb1e9AX1DSewG1bVgeXVIrLblGJr", + "RtpAOeaXE2mPUrXm7FbNypVvPdXA1xzu6kq9cZB8gfsd3esRK6utu9KFrLLtc2UqdUE5aAYJkbYkyzlj", + "yU8CmSuBpk6qGZzgNLUxNMcU3bGzvlVkBuYArrwLi2+JDqVtKmbb24ZqNn9aypdc49uVAm+rHSzseSqT", + "rf9WsjLy+7EB8Q1GD4kG9uJLDdisHBUcSBQQxxOgEdiLwMXhvSKJc7M6XlNCaePlo1YELa30t9JVzy24", + "zjbfPMBxdhnqx9oaN/ll69b0YDXVt3yDuuOEbD6021kvUFp716x667ozl9Yq+mrkV3e2TZ9U7D+Jki2r", + "xP/y3fG33c69xHWj4GFvxvbcJO4u/t3r/d88gyAfs0cSXWrk8LvruOK9otSIPgwTzIicZ7f7IUvGpsLX", + "OGYsGRNbIjGv9TX2337UFcgInTLNRUYyBUqfGTV2dHmm5Icj/+DV/sH+ga2tQnFKgsPg5/2D/Z8tGBq/", + "Y5yS8d2rsaK+KccJjKv5IzH+TqJHNXYGel15SRIlQIP3ICf6jVP3QlDpDfP64GAbFbevMl2ccprFeU1w", + "XS/uzcGrbUxfqU9YVDMduYqEpo58XtXO3Z3TRb/l3CvK+JNwVRy9IppvDn5ugi7H9rhaIlq/96bve3kF", + "S12eLksSzBe2YrItTIgSK6g00BjlVLNUWHLfVinJO0b9XtuOiLQ3h6paIDePoxLFCpBi/N0e834cF2cX", + "xfh78fBY7V7VUDOgGOKueDWmJb2hXoOqx5tRkDJRwyXHXDmxJwbk99WOVSCkcws8Ms0r5o6Vs7PnjoIU", + "2Fm+AvvFBQS+pE2H7iKYAv9S1K9tLuNRksO5v3VLqCKLHjVqykd5mw7nd+fYp8S/y1Y+orpsJJXf1mUe", + "Xpo8OuhmyOU6zoUk6/VmqVZrX/GxVIFYv/hL7xfzCs3qvVd/HwBsTS1P9Y3Xrwd8w6+A+jgK/j4Az+XS", + "xPrln4egOq8uW5acn03hT1wUv84Fe0HDphroClJtbJkYtibeRlaGm4IiuRDPtcCXXPx/GSjYG75cI9Na", + "1UOT+D2ymKoXwDvZsGXZ8AJY01EEwh4rIjyVwD2rxivHXGZTy5w+m+bleU1fgnaD2fU/yEuCmHdepOW8", + "OZpal7nak6Lquo/UmLrKFteiFTp7bNRZuX1F700/chKNhHROhDzNRz2RdNZy9OZFU9aaSERhvSAD83cC", + "wjpEfrObVemi3Yc4LYIXza7DmsRElx396sXryqWWVs8m1n7p+17JiO5jANd1ulkfvRuqQ9i0veNWMDoq", + "7K0Vxfh70RC6NZpUIvCdMnxmZYhpvtc/iVwtZlSSBFBxv/4pAq/bB/F6jfdWmyV6G/stE8be3eguInyb", + "32/dGC2W6mXW9ZjQBz6k10AKU9ORl3i9lXVVmTxvuR2Krem83Jdol7vt9hWSy72s+1J8Q5/ivi5FbZtW", + "vV/boftGs8Bcyq6j2PWbB5VSDVuOtlVLKXT06lpqntzfbqjrZ/+cLLUqY/QyIBqa8z4zXz1dzodez4Hx", + "99JBp8dxUcdv/N2rwfY4FuWao10aoraY5yZ5oG6+GkZ4a9trm7tz2j1hFIru4ohQbdTl/FLRHX9CJtnp", + "nQ3onVFt3q56arA50ttxpKj26+WaiKt++2aNEmTRRxTU9W7ZoCSom67WoXH9yPKlFa3IhDYmP58h10rk", + "OS3HJ3HT45/IAfGbbD2v8agbUlXLjPs9ctZvQtY2NNuyIVnfh6vO+cKUURLi2PVgtM33IPL9MZ01wBRh", + "yRISIru96BbLcL6zOX8sm9N2p3p2zq64hTt/cOcP/ui8abrBbZMzsxrGvMJ3OVee2P50m2DNpVtQW2bO", + "5ftBrfrVdOS2adZfX3vqVW/bzivdMXkvJretHpvctVP9s+M//wj3xhjBv1LWwgAKLq2ofOLfBfL/oi6g", + "61b67HaiLQyzYTuxUrdoy6qoWjWoJVxq9wWxqQ6XWkMRmXtaOyU0QAm9GgLuJV7EDEfXjJ1jPoM1aLE3", + "r4dAfs3YR0wXdqv0bao3vwxaekyAyuOYCfA3/Pl0qXp5yK6/xxLu8eKaJMAyuR5d7BoxP7+QM4BsWsiV", + "CxFtW8hVSg7V3VGyh169c4yuPM1OtO3s6148XbRNf3auzsvobOfsw1LVnpcc7XKGi41HRmjKWWKvGeJQ", + "ohS4IEKJgp17vWP//uxfOR3xvALAdBNeOomxqcxVQ9fmbYuBhl7K9cEFe9gjgimhxGR8db8kQmcII8oi", + "c5xQ37v68cLhL5cX264ymwb1NcncW8bllT2Z8aMdn66/n/am94uDdcMLvdemaKB8qa10sKvpDMuObJ5O", + "Ni9g+/WZ/Zq9R0JimYnNHtMfUAmhRG7PfItpd+P3h7jxay8yMa42IEugfPq1Xl6upqPrrgI/L9PlsaHG", + "e8d1pVqedhnfHe2cAzY+uf3M/+ydM5bsmZake8csSYgcVgRmMzKjkqb780uN3d3HFW7A9ZQ2bt5GYWPC", + "Ltq3slFwhFuuk/sJ3xWFzpRQHJNv8PzS5p2F5MXalH8ylbtdJ+bPXnTnVxybmIfiPccUG1T2TiOK8Xe/", + "HPfjNqvydIwudR5sPJhmqhU5pnXvNNgGy1r92LDz3tWHo9d//0ewFg3OQglyT0gOOCnLhM56ZDvLfyeG", + "nlMMXWmitYdIDCshRaKIUMkab961yyAOMWBLvZupLjIxM+zc8h1z/pWZ0xU1QVGm+227ShbIclhxTbY3", + "T66jGp/HnBGkHEIsC4e4vqKdZVjlb2BJvEuHO+7dce9fnHtphHBRxs+xLqFa6drupTnXDGRkaLvwq5mv", + "pCt3GZM/dcbEK/lX0QQbrPCXE9x3+7+OIus7avuLUBteMjduF+jsZLPJOUc/w6lyO3WGC/i6ivjufJSd", + "lfMDWDlFhWJadPF0/kqhnbq4+RmCk0PCjfazXrRx2w0RXKuD7ohiTVuCXf+BjYuNXR8B10dAuTVFJ4GL", + "E93mNw8uKnosywOOzf3CZu6b4HvzmX4nAIoWHIMr+c/8kvtb6APQzzR42KPRMsPtcgs7Hn+ufAHH946z", + "TaKgrlMIi2PWGp/QI64wjW7ZQ4PH2A7uh+uP508nh1UMvoq7RCMw3bHMmtB7jtP5P8+RMIuzKJmpv/4R", + "F13MtNyr9SJMmzLdCUSPtB/ceRN9yMIia40iow/X2llX41r7cluha0sSpX5mjs6q8UNHafrfNh60H7iM", + "8WLGNWn/NfjQISbNF2biFm3MtuOxHY/lPKY5BzGO3n04mzTy2RxwLFsZ7IMZ8bJ22NoCG282iRydI4Mo", + "FEGqeJSGC0QEokwiDjha7C8xsjKdUIjDOUQoZNykUQq5Zz5nNyEmd/CtbQ/OyR1QEOJF7ULdgi1Vo9gC", + "jO6JnLNMonAO4VcdWXEIJLoIqlq+xuC39qA8jsiLQ8DWyPDEwxnCHDrp7n4Ocq6rDljqjapfyN9Wr+uS", + "YMYdzXgcHAbj4PHm8f8DAAD//w==", +} + +// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes, +// after base64-decoding and flate-decompressing the embedded blob. +func decodeSpec() ([]byte, error) { + encoded := strings.Join(swaggerSpec, "") + compressed, err := base64.StdEncoding.DecodeString(encoded) + if err != nil { + return nil, fmt.Errorf("error base64 decoding spec: %w", err) + } + zr := flate.NewReader(bytes.NewReader(compressed)) + var buf bytes.Buffer + if _, err := buf.ReadFrom(zr); err != nil { + return nil, fmt.Errorf("read flate: %w", err) + } + if err := zr.Close(); err != nil { + return nil, fmt.Errorf("close flate reader: %w", err) + } + + return buf.Bytes(), nil +} + +var rawSpec = decodeSpecCached() + +// a naive cache of the decoded OpenAPI spec +func decodeSpecCached() func() ([]byte, error) { + data, err := decodeSpec() + return func() ([]byte, error) { + return data, err + } +} + +// Constructs a synthetic filesystem for resolving external references when loading openapi specifications. +func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) { + res := make(map[string]func() ([]byte, error)) + if len(pathToFile) > 0 { + res[pathToFile] = rawSpec + } + + return res +} + +// GetSpec returns the OpenAPI specification corresponding to the generated +// code in this file. External references in the spec are resolved through +// PathToRawSpec; externally-referenced files must be embedded in their +// corresponding Go packages (via the import-mapping feature). URL-based +// external refs are not supported. +func GetSpec() (swagger *openapi3.T, err error) { + resolvePath := PathToRawSpec("") + + loader := openapi3.NewLoader() + loader.IsExternalRefsAllowed = true + loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) { + pathToFile := url.String() + pathToFile = path.Clean(pathToFile) + getSpec, ok := resolvePath[pathToFile] + if !ok { + err1 := fmt.Errorf("path not found: %s", pathToFile) + return nil, err1 + } + return getSpec() + } + var specData []byte + specData, err = rawSpec() + if err != nil { + return + } + swagger, err = loader.LoadFromData(specData) + if err != nil { + return + } + return +} + +// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI +// specification: decompressed but not unmarshaled. External references +// are not resolved here; the bytes are the spec exactly as embedded by +// codegen. The result is cached at package init time, so repeated calls +// are cheap. +func GetSpecJSON() ([]byte, error) { + return rawSpec() +} + +// GetSwagger returns the OpenAPI specification corresponding to the +// generated code in this file. +// +// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger +// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for +// backwards compatibility. +func GetSwagger() (*openapi3.T, error) { + return GetSpec() +} diff --git a/go.mod b/go.mod index 1170a91c..0022a029 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/bmeg/jsonschema/v6 v6.0.5 github.com/bmeg/jsonschemagraph v0.0.6 github.com/bytedance/sonic v1.15.2 + github.com/getkin/kin-openapi v0.142.0 github.com/gofiber/fiber/v3 v3.4.0 github.com/google/uuid v1.6.0 github.com/oapi-codegen/runtime v1.6.0 @@ -31,6 +32,8 @@ require ( github.com/dchest/siphash v1.2.3 // indirect github.com/go-faster/city v1.0.1 // indirect github.com/go-faster/errors v0.8.0 // indirect + github.com/go-openapi/jsonpointer v0.22.5 // indirect + github.com/go-openapi/swag/jsonname v0.25.5 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/gofiber/schema v1.8.3 // indirect github.com/gofiber/utils/v2 v2.4.1 // indirect @@ -42,11 +45,14 @@ require ( github.com/klauspost/cpuid/v2 v2.4.0 // indirect github.com/mattn/go-colorable v0.1.15 // indirect github.com/mattn/go-isatty v0.0.24 // indirect + github.com/oasdiff/yaml v0.1.1 // indirect + github.com/oasdiff/yaml3 v0.0.14 // indirect github.com/paulmach/orb v0.13.0 // indirect github.com/philhofer/fwd v1.2.0 // indirect github.com/pierrec/lz4/v4 v4.1.27 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/rs/zerolog v1.35.1 // indirect + github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect github.com/segmentio/asm v1.2.1 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/sosodev/duration v1.4.0 // indirect diff --git a/go.sum b/go.sum index 6fe94e7c..d2b41bf4 100644 --- a/go.sum +++ b/go.sum @@ -46,10 +46,18 @@ github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxK github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/fxamacker/cbor/v2 v2.9.2 h1:X4Ksno9+x3cz0TZv69ec1hxP/+tymuR8PXQJyDwfh78= github.com/fxamacker/cbor/v2 v2.9.2/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/getkin/kin-openapi v0.142.0 h1:izj0vBdFprMhitfzaX8sTqztsEQyvwhssBoB6n8NO7w= +github.com/getkin/kin-openapi v0.142.0/go.mod h1:3BH9M9XDe/y9M5DSvEocVYAYq1w0qrhJHjC/vZi0AaY= github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw= github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw= github.com/go-faster/errors v0.8.0 h1:9T9eJrM+72dFk7n4DfhuaDDe6cyuFCSW2oNUkN77Yqc= github.com/go-faster/errors v0.8.0/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo= +github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA= +github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0= +github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo= +github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU= +github.com/go-openapi/testify/v2 v2.4.0 h1:8nsPrHVCWkQ4p8h1EsRVymA2XABB4OT40gcvAu+voFM= +github.com/go-openapi/testify/v2 v2.4.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gofiber/fiber/v3 v3.4.0 h1:F0aND4vwZF7dR7cbvSwFQQEpBU902XHKWxrLsFBkVqw= @@ -76,6 +84,10 @@ github.com/klauspost/compress v1.19.1 h1:VsB4HPswih7mmZ8WleSFQ75c/Ui1M4trX5oAsJn github.com/klauspost/compress v1.19.1/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/cpuid/v2 v2.4.0 h1:S6Hrbc7+ywsr0r+RLapfGBHfyefhCTwEh3A0tV913Dw= github.com/klauspost/cpuid/v2 v2.4.0/go.mod h1:19jmZ9mjzoF//ddRSUsv0zfBTJWh3QJh9FNxZTMrGxU= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI= @@ -84,6 +96,10 @@ github.com/oapi-codegen/nullable v1.1.0 h1:eAh8JVc5430VtYVnq00Hrbpag9PFRGWLjxR1/ github.com/oapi-codegen/nullable v1.1.0/go.mod h1:KUZ3vUzkmEKY90ksAmit2+5juDIhIZhfDl+0PwOQlFY= github.com/oapi-codegen/runtime v1.6.0 h1:7Xx+GlueD6nRuyKoCPzL434Jfi3BetbiJOrzCHp/VPU= github.com/oapi-codegen/runtime v1.6.0/go.mod h1:GwV7hC2hviaMzj+ITfHVRESK5J2W/GefVwIND/bMGvU= +github.com/oasdiff/yaml v0.1.1 h1:6nHx+pn9gBRM6YpBlFZFQGCCd1nuvqOBtTD3KKTgGxY= +github.com/oasdiff/yaml v0.1.1/go.mod h1:EYJNoyktvWMJ0Hmhx+6qTaqMOsalUaRGT8Sj1hNcegU= +github.com/oasdiff/yaml3 v0.0.14 h1:aLJee3hxBK2H5wdXd9iPcIXb93Nty1Ge0pT171eHtkw= +github.com/oasdiff/yaml3 v0.0.14/go.mod h1:csto2xfDjYccdUn/yw/bPjj/cYTdp6HtFA0J4TWG+gg= github.com/paulmach/orb v0.13.0 h1:r7n7mQGGF+cj/CbcivEj9J3HGK+XR+yXnvzRdq9saIw= github.com/paulmach/orb v0.13.0/go.mod h1:6scRWINywA2Jf05dcjOfLfxrUIMECvTSG2MVbRLxu/k= github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= @@ -94,8 +110,12 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI= github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/shamaton/msgpack/v3 v3.2.0 h1:1q2Ms+MWmuRju+PuDMSFDB7p7621npeX4zprJN5Zck8= @@ -152,6 +172,8 @@ golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/internal/api/bulk/load/generation_route.go b/internal/api/bulk/load/generation_route.go index ba56c692..9dda82db 100644 --- a/internal/api/bulk/load/generation_route.go +++ b/internal/api/bulk/load/generation_route.go @@ -14,7 +14,7 @@ import ( "github.com/gofiber/fiber/v3" ) -func (s *Handler) createGeneration(c fiber.Ctx) error { +func (s *Handler) HandleCreateGeneration(c fiber.Ctx) error { if !c.IsMultipart() { return fiber.NewError(fiber.StatusUnsupportedMediaType) } @@ -66,7 +66,7 @@ func (s *Handler) createGeneration(c fiber.Ctx) error { return c.Status(fiber.StatusOK).JSON(result) } -func (s *Handler) activateGeneration(c fiber.Ctx) error { +func (s *Handler) HandleActivateGeneration(c fiber.Ctx) error { project := strings.TrimSpace(c.Params("project")) generation := strings.TrimSpace(c.Params("generation")) executionID := strings.TrimSpace(c.Query("dataframe_execution_id")) diff --git a/internal/api/bulk/load/handler.go b/internal/api/bulk/load/handler.go index 9fe6bc96..e6f9dee5 100644 --- a/internal/api/bulk/load/handler.go +++ b/internal/api/bulk/load/handler.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/calypr/loom/internal/authscope" "github.com/calypr/loom/internal/dataset" - "github.com/gofiber/fiber/v3" ) type Handler struct { @@ -30,11 +29,3 @@ func NewHandler(cfg Config) (*Handler, error) { } return &Handler{service: cfg.Service, authz: cfg.Authorizer, snapshots: cfg.Snapshots, releases: cfg.Releases}, nil } - -func (h *Handler) RegisterRoutes(router fiber.Router) { - h.RegisterResourceRoute(router) - router.Post("/api/v1/datasets/:project/generations/:generation", h.createGeneration) - router.Post("/api/v1/datasets/:project/generations/:generation/activate", h.activateGeneration) - router.Put("/api/v1/raw", h.loadRaw) - h.RegisterSnapshotRoutes(router) -} diff --git a/internal/api/bulk/load/raw_load.go b/internal/api/bulk/load/raw_load.go index ba9a5437..340dc07a 100644 --- a/internal/api/bulk/load/raw_load.go +++ b/internal/api/bulk/load/raw_load.go @@ -13,7 +13,7 @@ import ( const defaultRawProject = "default" -func (s *Handler) loadRaw(c fiber.Ctx) error { +func (s *Handler) HandleLoadRaw(c fiber.Ctx) error { contentType, _, err := mime.ParseMediaType(c.Get(fiber.HeaderContentType)) if err != nil || (contentType != "application/x-ndjson" && contentType != "application/ndjson") { return fiber.NewError(fiber.StatusUnsupportedMediaType) diff --git a/internal/api/bulk/load/resource_route.go b/internal/api/bulk/load/resource_route.go index 08c1b967..8fdd7ab5 100644 --- a/internal/api/bulk/load/resource_route.go +++ b/internal/api/bulk/load/resource_route.go @@ -12,13 +12,8 @@ import ( "github.com/gofiber/fiber/v3" ) -// RegisterResourceRoute exposes the primary project/resourceType upload path. -// Generation and raw routes remain opt-in and are not registered here. -func (h *Handler) RegisterResourceRoute(router fiber.Router) { - router.Put("/api/v1/projects/:project/resources/:resourceType", h.resource) -} - -func (h *Handler) resource(c fiber.Ctx) error { +// HandleResource implements the project resource upload transport operation. +func (h *Handler) HandleResource(c fiber.Ctx) error { if !c.IsMultipart() { return fiber.NewError(fiber.StatusUnsupportedMediaType) } diff --git a/internal/api/bulk/load/resource_route_test.go b/internal/api/bulk/load/resource_route_test.go index 7ae27ece..792c0451 100644 --- a/internal/api/bulk/load/resource_route_test.go +++ b/internal/api/bulk/load/resource_route_test.go @@ -46,7 +46,7 @@ func TestResourceRouteUsesPathIdentityAndMultipartFile(t *testing.T) { if err != nil { t.Fatal(err) } - handler.RegisterResourceRoute(server.App()) + server.App().Put("/api/v1/projects/:project/resources/:resourceType", handler.HandleResource) req := resourceMultipartRequest(t, map[string]string{"auth_resource_path": "/programs/p1/projects/p1"}, "file", "Patient.ndjson", []byte("{\"resourceType\":\"Patient\",\"id\":\"1\"}\n")) req.Method = http.MethodPut diff --git a/internal/api/bulk/load/snapshot_route.go b/internal/api/bulk/load/snapshot_route.go index 3df0efb6..fef38007 100644 --- a/internal/api/bulk/load/snapshot_route.go +++ b/internal/api/bulk/load/snapshot_route.go @@ -12,32 +12,13 @@ import ( "github.com/gofiber/fiber/v3" ) -func (h *Handler) RegisterSnapshotRoutes(router fiber.Router) { - if h.snapshots != nil { - router.Post("/api/v1/projects/:project/generations/:generation", h.createSnapshot) - router.Get("/api/v1/projects/:project/generations/:generation", h.snapshotStatus) - router.Delete("/api/v1/projects/:project/generations/:generation", h.abortSnapshot) - router.Put("/api/v1/projects/:project/generations/:generation/resources/:resourceType", h.uploadSnapshotResource) - router.Post("/api/v1/projects/:project/generations/:generation/finalize", h.finalizeSnapshot) - } - if h.releases != nil { - router.Post("/api/v1/projects/:project/releases", h.createRelease) - router.Get("/api/v1/projects/:project/releases/active", h.activeRelease) - router.Get("/api/v1/projects/:project/releases/:release", h.releaseStatus) - router.Post("/api/v1/projects/:project/releases/:release/activate", h.activateExistingRelease) - // Deprecated compatibility endpoint. New clients create a durable release - // and activate that exact release ID in two separate operations. - router.Post("/api/v1/projects/:project/releases/activate", h.activateRelease) - } -} - type createSnapshotRequest struct { GitCommit string `json:"gitCommit"` ExpectedResourceTypes []string `json:"expectedResourceTypes"` AuthResourcePath string `json:"authResourcePath,omitempty"` } -func (h *Handler) createSnapshot(c fiber.Ctx) error { +func (h *Handler) HandleCreateSnapshot(c fiber.Ctx) error { project, generation := strings.TrimSpace(c.Params("project")), strings.TrimSpace(c.Params("generation")) var request createSnapshotRequest if err := json.Unmarshal(c.Body(), &request); err != nil { @@ -59,7 +40,7 @@ func (h *Handler) createSnapshot(c fiber.Ctx) error { return c.Status(http.StatusOK).JSON(result) } -func (h *Handler) snapshotStatus(c fiber.Ctx) error { +func (h *Handler) HandleSnapshotStatus(c fiber.Ctx) error { project := strings.TrimSpace(c.Params("project")) result, err := h.snapshots.Status(c.Context(), project, strings.TrimSpace(c.Params("generation"))) if err != nil { @@ -71,7 +52,7 @@ func (h *Handler) snapshotStatus(c fiber.Ctx) error { return c.Status(http.StatusOK).JSON(result) } -func (h *Handler) uploadSnapshotResource(c fiber.Ctx) error { +func (h *Handler) HandleUploadSnapshotResource(c fiber.Ctx) error { project := strings.TrimSpace(c.Params("project")) generation := strings.TrimSpace(c.Params("generation")) status, err := h.snapshots.Status(c.Context(), project, generation) @@ -88,7 +69,7 @@ func (h *Handler) uploadSnapshotResource(c fiber.Ctx) error { return c.Status(http.StatusOK).JSON(result) } -func (h *Handler) finalizeSnapshot(c fiber.Ctx) error { +func (h *Handler) HandleFinalizeSnapshot(c fiber.Ctx) error { project := strings.TrimSpace(c.Params("project")) generationID := strings.TrimSpace(c.Params("generation")) status, err := h.snapshots.Status(c.Context(), project, generationID) @@ -110,7 +91,7 @@ func (h *Handler) finalizeSnapshot(c fiber.Ctx) error { return c.Status(http.StatusOK).JSON(fiber.Map{"generation": generation, "load": load}) } -func (h *Handler) abortSnapshot(c fiber.Ctx) error { +func (h *Handler) HandleAbortSnapshot(c fiber.Ctx) error { project := strings.TrimSpace(c.Params("project")) generationID := strings.TrimSpace(c.Params("generation")) status, err := h.snapshots.Status(c.Context(), project, generationID) @@ -127,7 +108,7 @@ func (h *Handler) abortSnapshot(c fiber.Ctx) error { return c.Status(http.StatusOK).JSON(result) } -func (h *Handler) activateRelease(c fiber.Ctx) error { +func (h *Handler) HandleActivateReleaseCompatibility(c fiber.Ctx) error { project := strings.TrimSpace(c.Params("project")) var request dataset.ActivationRequest if err := json.Unmarshal(c.Body(), &request); err != nil { @@ -144,7 +125,7 @@ func (h *Handler) activateRelease(c fiber.Ctx) error { return c.Status(http.StatusOK).JSON(result) } -func (h *Handler) createRelease(c fiber.Ctx) error { +func (h *Handler) HandleCreateRelease(c fiber.Ctx) error { project := strings.TrimSpace(c.Params("project")) var request dataset.ActivationRequest if err := json.Unmarshal(c.Body(), &request); err != nil { @@ -161,7 +142,7 @@ func (h *Handler) createRelease(c fiber.Ctx) error { return c.Status(http.StatusOK).JSON(release) } -func (h *Handler) activateExistingRelease(c fiber.Ctx) error { +func (h *Handler) HandleActivateRelease(c fiber.Ctx) error { project := strings.TrimSpace(c.Params("project")) releaseID := strings.TrimSpace(c.Params("release")) release, err := h.releases.Releases.ReadRelease(c.Context(), project, releaseID) @@ -184,7 +165,7 @@ func (h *Handler) activateExistingRelease(c fiber.Ctx) error { return c.Status(http.StatusOK).JSON(active) } -func (h *Handler) activeRelease(c fiber.Ctx) error { +func (h *Handler) HandleActiveRelease(c fiber.Ctx) error { project := strings.TrimSpace(c.Params("project")) active, err := h.releases.Active(c.Context(), project) if err != nil { @@ -196,7 +177,7 @@ func (h *Handler) activeRelease(c fiber.Ctx) error { return c.Status(http.StatusOK).JSON(active) } -func (h *Handler) releaseStatus(c fiber.Ctx) error { +func (h *Handler) HandleReleaseStatus(c fiber.Ctx) error { project := strings.TrimSpace(c.Params("project")) release, err := h.releases.Releases.ReadRelease(c.Context(), project, strings.TrimSpace(c.Params("release"))) if err != nil { diff --git a/internal/api/bulk/load/snapshot_route_test.go b/internal/api/bulk/load/snapshot_route_test.go index 278f347e..ae3ac229 100644 --- a/internal/api/bulk/load/snapshot_route_test.go +++ b/internal/api/bulk/load/snapshot_route_test.go @@ -43,7 +43,7 @@ func TestSnapshotHTTPContractCreateUploadFinalizeStatusAndAbort(t *testing.T) { if err != nil { t.Fatal(err) } - handler.RegisterSnapshotRoutes(server.App()) + registerTestSnapshotRoutes(server.App(), handler) createBody := []byte(`{"gitCommit":"commit-a","expectedResourceTypes":["Patient"]}`) for range 2 { diff --git a/internal/api/bulk/load/test_server_helpers_test.go b/internal/api/bulk/load/test_server_helpers_test.go index d6c8f027..3bedb15b 100644 --- a/internal/api/bulk/load/test_server_helpers_test.go +++ b/internal/api/bulk/load/test_server_helpers_test.go @@ -3,6 +3,7 @@ package load import ( httpapi "github.com/calypr/loom/internal/api/http" "github.com/calypr/loom/internal/authscope" + "github.com/gofiber/fiber/v3" ) type HTTPConfig struct { @@ -20,6 +21,33 @@ func NewHTTPServer(cfg HTTPConfig) (*httpapi.HTTPServer, error) { if err != nil { return nil, err } - h.RegisterRoutes(s.App()) + registerTestRoutes(s.App(), h) return s, nil } + +// registerTestRoutes keeps package-level handler tests focused on transport +// behavior. Production route ownership lives exclusively in generated/loomapi. +func registerTestRoutes(router fiber.Router, h *Handler) { + router.Put("/api/v1/projects/:project/resources/:resourceType", h.HandleResource) + router.Post("/api/v1/datasets/:project/generations/:generation", h.HandleCreateGeneration) + router.Post("/api/v1/datasets/:project/generations/:generation/activate", h.HandleActivateGeneration) + router.Put("/api/v1/raw", h.HandleLoadRaw) + registerTestSnapshotRoutes(router, h) +} + +func registerTestSnapshotRoutes(router fiber.Router, h *Handler) { + if h.snapshots != nil { + router.Post("/api/v1/projects/:project/generations/:generation", h.HandleCreateSnapshot) + router.Get("/api/v1/projects/:project/generations/:generation", h.HandleSnapshotStatus) + router.Put("/api/v1/projects/:project/generations/:generation/resources/:resourceType", h.HandleUploadSnapshotResource) + router.Post("/api/v1/projects/:project/generations/:generation/finalize", h.HandleFinalizeSnapshot) + router.Delete("/api/v1/projects/:project/generations/:generation", h.HandleAbortSnapshot) + } + if h.releases != nil { + router.Post("/api/v1/projects/:project/releases/activate", h.HandleActivateReleaseCompatibility) + router.Post("/api/v1/projects/:project/releases", h.HandleCreateRelease) + router.Post("/api/v1/projects/:project/releases/:release/activate", h.HandleActivateRelease) + router.Get("/api/v1/projects/:project/releases/active", h.HandleActiveRelease) + router.Get("/api/v1/projects/:project/releases/:release", h.HandleReleaseStatus) + } +} diff --git a/internal/api/graphql/graph/handler.go b/internal/api/graphql/graph/handler.go index 62ae4b59..bd112ae3 100644 --- a/internal/api/graphql/graph/handler.go +++ b/internal/api/graphql/graph/handler.go @@ -17,27 +17,12 @@ import ( graphqlerrors "github.com/calypr/loom/internal/api/graphql" "github.com/calypr/loom/internal/api/graphql/graph/resolver" httpapi "github.com/calypr/loom/internal/api/http" - "github.com/gofiber/fiber/v3" fiberadaptor "github.com/gofiber/fiber/v3/middleware/adaptor" "github.com/vektah/gqlparser/v2/gqlerror" ) type RouteConfig struct{ Handler, Playground, Sandbox http.Handler } -func RegisterRoutes(router fiber.Router, cfg RouteConfig) { - if cfg.Playground != nil { - router.Get("/graphql/graph", fiberadaptor.HTTPHandlerWithContext(cfg.Playground)) - } - if cfg.Sandbox != nil { - router.Get("/apollo", fiberadaptor.HTTPHandlerWithContext(cfg.Sandbox)) - } - if cfg.Handler != nil { - h := fiberadaptor.HTTPHandlerWithContext(cfg.Handler) - router.Post("/graphql/graph", h) - router.Post("/graphql/dataframe", h) - } -} - func NewHandler(root *resolver.Resolver, loggers ...*slog.Logger) http.Handler { logger := slog.Default() if len(loggers) > 0 && loggers[0] != nil { diff --git a/internal/api/graphql/graph/http_integration_test.go b/internal/api/graphql/graph/http_integration_test.go index a51120df..e8a2769c 100644 --- a/internal/api/graphql/graph/http_integration_test.go +++ b/internal/api/graphql/graph/http_integration_test.go @@ -16,6 +16,7 @@ import ( "github.com/calypr/loom/internal/catalog" "github.com/calypr/loom/internal/dataframe/runtime" publication "github.com/calypr/loom/internal/dataset" + fiberadaptor "github.com/gofiber/fiber/v3/middleware/adaptor" ) func TestGraphQLSchemaIntrospectionEndpoint(t *testing.T) { @@ -292,7 +293,11 @@ func newGraphServer(root *graphresolver.Resolver, auth authscope.Authenticator) if err != nil { return nil, err } - graph.RegisterRoutes(server.App(), graph.RouteConfig{Handler: graph.NewHandler(root), Playground: graph.NewPlaygroundHandler("/graphql/graph"), Sandbox: graph.NewApolloSandboxHandler("/graphql/graph")}) + handler := fiberadaptor.HTTPHandlerWithContext(graph.NewHandler(root)) + server.App().Post("/graphql/graph", handler) + server.App().Post("/graphql/dataframe", handler) + server.App().Get("/graphql/graph", fiberadaptor.HTTPHandlerWithContext(graph.NewPlaygroundHandler("/graphql/graph"))) + server.App().Get("/apollo", fiberadaptor.HTTPHandlerWithContext(graph.NewApolloSandboxHandler("/graphql/graph"))) return server, nil } diff --git a/internal/api/http/http_test.go b/internal/api/http/http_test.go index fc2e7758..0cc5f622 100644 --- a/internal/api/http/http_test.go +++ b/internal/api/http/http_test.go @@ -16,7 +16,7 @@ import ( ) func TestHealthDoesNotRequireAuthentication(t *testing.T) { - server, err := NewHTTPServer(HTTPConfig{Authenticator: authscope.BasicAuthenticator{Username: "u", Password: "p"}, Authorizer: authscope.AllowAllAuthorizer{}}) + server, err := newTestHTTPServer(HTTPConfig{Authenticator: authscope.BasicAuthenticator{Username: "u", Password: "p"}, Authorizer: authscope.AllowAllAuthorizer{}}) if err != nil { t.Fatal(err) } @@ -31,7 +31,7 @@ func TestHealthDoesNotRequireAuthentication(t *testing.T) { } func TestHealthRoutesDoNotRequireAuthentication(t *testing.T) { - server, err := NewHTTPServer(HTTPConfig{ + server, err := newTestHTTPServer(HTTPConfig{ Authenticator: authscope.BasicAuthenticator{Username: "u", Password: "p"}, Authorizer: authscope.AllowAllAuthorizer{}, }) @@ -52,7 +52,7 @@ func TestHealthRoutesDoNotRequireAuthentication(t *testing.T) { func TestLivenessDoesNotCheckDependencies(t *testing.T) { checks := 0 - server, err := NewHTTPServer(HTTPConfig{ + server, err := newTestHTTPServer(HTTPConfig{ Authorizer: authscope.AllowAllAuthorizer{}, CoreReadyCheck: func(_ context.Context) error { checks++ @@ -95,7 +95,7 @@ func TestReadinessRequiresCoreAndClickHouse(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - server, err := NewHTTPServer(HTTPConfig{ + server, err := newTestHTTPServer(HTTPConfig{ Authorizer: authscope.AllowAllAuthorizer{}, CoreReadyCheck: func(_ context.Context) error { return tt.coreErr @@ -125,7 +125,7 @@ func TestReadinessRequiresCoreAndClickHouse(t *testing.T) { } func TestHealthRetainsDegradedClickHouseCompatibility(t *testing.T) { - server, err := NewHTTPServer(HTTPConfig{ + server, err := newTestHTTPServer(HTTPConfig{ Authorizer: authscope.AllowAllAuthorizer{}, ClickHouseEnabled: true, ClickHouseReadyCheck: func(_ context.Context) error { @@ -155,6 +155,17 @@ func TestNewHTTPServerRequiresAuthorizer(t *testing.T) { } } +func newTestHTTPServer(cfg HTTPConfig) (*HTTPServer, error) { + server, err := NewHTTPServer(cfg) + if err != nil { + return nil, err + } + server.App().Get("/health", server.HandleHealth) + server.App().Get("/livez", server.HandleLiveness) + server.App().Get("/readyz", server.HandleReadiness) + return server, nil +} + func TestLoggingMiddlewareEmitsStructuredResponseDiagnostics(t *testing.T) { var logs bytes.Buffer logger := slog.New(slog.NewTextHandler(&logs, &slog.HandlerOptions{Level: slog.LevelInfo})) diff --git a/internal/api/http/recipe_execution.go b/internal/api/http/recipe_execution.go index 1f0740cc..b4ce8984 100644 --- a/internal/api/http/recipe_execution.go +++ b/internal/api/http/recipe_execution.go @@ -10,49 +10,51 @@ import ( "github.com/gofiber/fiber/v3" ) -// RegisterRecipeExecutionRoute exposes candidate schema metadata without -// exposing physical table names. Authentication is provided by HTTPServer's -// middleware; project/scope authorization is checked against the execution. -func RegisterRecipeExecutionRoute(app *fiber.App, catalog publication.BundleCatalog, scopes *authscope.ScopeResolver) { - if app == nil || catalog == nil { - return +// RecipeExecutionHandler exposes candidate schema metadata without physical +// table names. Generated OpenAPI routing calls Handle directly. +type RecipeExecutionHandler struct { + Catalog publication.BundleCatalog + Scopes *authscope.ScopeResolver +} + +func (h RecipeExecutionHandler) Handle(c fiber.Ctx) error { + if h.Catalog == nil { + return c.Status(http.StatusNotFound).JSON(fiber.Map{"error": "recipe execution not found"}) } - app.Get("/api/v1/dataframe/recipe-executions/:id", func(c fiber.Ctx) error { - id := strings.TrimSpace(c.Params("id")) - execution, err := catalog.GetExecution(c.Context(), id) - if err != nil || execution.ID == "" { - return c.Status(http.StatusNotFound).JSON(fiber.Map{"error": "recipe execution not found"}) - } - if scopes != nil { - principal, _ := authscope.PrincipalFromContext(c.Context()) - if _, scopeErr := scopes.ResolveReadScopeForGeneration(c.Context(), principal, execution.Project, execution.DatasetGeneration, execution.AuthResourcePaths); scopeErr != nil { - status := http.StatusForbidden - if errors.Is(scopeErr, authscope.ErrUnauthenticated) { - status = http.StatusUnauthorized - } - return c.Status(status).JSON(fiber.Map{"error": "recipe execution not found"}) + id := strings.TrimSpace(c.Params("id")) + execution, err := h.Catalog.GetExecution(c.Context(), id) + if err != nil || execution.ID == "" { + return c.Status(http.StatusNotFound).JSON(fiber.Map{"error": "recipe execution not found"}) + } + if h.Scopes != nil { + principal, _ := authscope.PrincipalFromContext(c.Context()) + if _, scopeErr := h.Scopes.ResolveReadScopeForGeneration(c.Context(), principal, execution.Project, execution.DatasetGeneration, execution.AuthResourcePaths); scopeErr != nil { + status := http.StatusForbidden + if errors.Is(scopeErr, authscope.ErrUnauthenticated) { + status = http.StatusUnauthorized } + return c.Status(status).JSON(fiber.Map{"error": "recipe execution not found"}) } - outputs := make([]fiber.Map, 0, len(execution.Outputs)) - for _, output := range execution.Outputs { - columns := make([]fiber.Map, 0, len(output.Columns)) - for _, column := range output.Columns { - logical, nullable, repeated, filterable, sortable, aggregatable := columnCapabilities(column.ClickHouse) - if column.LogicalType != "" { - logical = column.LogicalType - } - if column.Nullable { - nullable = true - } - if column.Repeated { - repeated = true - } - columns = append(columns, fiber.Map{"name": column.Name, "semanticPath": column.SemanticPath, "clickhouseType": column.ClickHouse, "logicalType": logical, "nullable": nullable, "repeated": repeated, "filterable": filterable, "sortable": sortable, "aggregatable": aggregatable}) + } + outputs := make([]fiber.Map, 0, len(execution.Outputs)) + for _, output := range execution.Outputs { + columns := make([]fiber.Map, 0, len(output.Columns)) + for _, column := range output.Columns { + logical, nullable, repeated, filterable, sortable, aggregatable := columnCapabilities(column.ClickHouse) + if column.LogicalType != "" { + logical = column.LogicalType + } + if column.Nullable { + nullable = true } - outputs = append(outputs, fiber.Map{"name": output.Name, "state": recipeExecutionHTTPState(output.State), "rowCount": output.RowCount, "columns": columns}) + if column.Repeated { + repeated = true + } + columns = append(columns, fiber.Map{"name": column.Name, "semanticPath": column.SemanticPath, "clickhouseType": column.ClickHouse, "logicalType": logical, "nullable": nullable, "repeated": repeated, "filterable": filterable, "sortable": sortable, "aggregatable": aggregatable}) } - return c.JSON(fiber.Map{"id": execution.ID, "projectId": execution.Project, "datasetGeneration": execution.DatasetGeneration, "recipeDigest": execution.RecipeDigest, "schemaDigest": execution.SchemaDigest, "resolvedSchemaDigest": execution.SchemaDigest, "state": recipeExecutionHTTPState(execution.State), "outputs": outputs}) - }) + outputs = append(outputs, fiber.Map{"name": output.Name, "state": recipeExecutionHTTPState(output.State), "rowCount": output.RowCount, "columns": columns}) + } + return c.JSON(fiber.Map{"id": execution.ID, "projectId": execution.Project, "datasetGeneration": execution.DatasetGeneration, "recipeDigest": execution.RecipeDigest, "schemaDigest": execution.SchemaDigest, "resolvedSchemaDigest": execution.SchemaDigest, "state": recipeExecutionHTTPState(execution.State), "outputs": outputs}) } // recipeExecutionHTTPState preserves the READY spelling used by the legacy diff --git a/internal/api/http/routes.go b/internal/api/http/routes.go index c47e4f9c..0b3bba88 100644 --- a/internal/api/http/routes.go +++ b/internal/api/http/routes.go @@ -9,16 +9,9 @@ import ( func (s *HTTPServer) register() { s.app.Use(s.requestIDMiddleware, s.recoveryMiddleware, s.loggingMiddleware, s.authenticationMiddleware) - s.registerHealthRoutes() } -func (s *HTTPServer) registerHealthRoutes() { - s.app.Get("/health", s.health) - s.app.Get("/livez", s.liveness) - s.app.Get("/readyz", s.readiness) -} - -func (s *HTTPServer) health(c fiber.Ctx) error { +func (s *HTTPServer) HandleHealth(c fiber.Ctx) error { s.healthMu.Lock() defer s.healthMu.Unlock() if time.Since(s.lastHealth) < 30*time.Second { @@ -31,11 +24,11 @@ func (s *HTTPServer) health(c fiber.Ctx) error { return s.writeHealth(c, result) } -func (s *HTTPServer) liveness(c fiber.Ctx) error { +func (s *HTTPServer) HandleLiveness(c fiber.Ctx) error { return c.Status(fiber.StatusOK).JSON(fiber.Map{"status": "live"}) } -func (s *HTTPServer) readiness(c fiber.Ctx) error { +func (s *HTTPServer) HandleReadiness(c fiber.Ctx) error { ctx, cancel := context.WithTimeout(c.Context(), 2*time.Second) defer cancel() result := s.checkDependencies(ctx) diff --git a/internal/server/explorer_authoring_v2_routes.go b/internal/server/explorer_authoring_v2_routes.go index e1b252ab..f74a354d 100644 --- a/internal/server/explorer_authoring_v2_routes.go +++ b/internal/server/explorer_authoring_v2_routes.go @@ -9,7 +9,7 @@ import ( "strings" "time" - explorerv2api "github.com/calypr/loom/generated/explorerv2" + explorerv2api "github.com/calypr/loom/generated/loomapi" graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" "github.com/calypr/loom/internal/authscope" "github.com/calypr/loom/internal/dataframe/recipe" @@ -22,13 +22,28 @@ import ( "github.com/gofiber/fiber/v3" ) -// RegisterExplorerAuthoringV2Routes is the hard-cut traversal Builder -// contract. Retired authoring formats are not registered as an HTTP surface. -func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, explorers *explorer.Service, capabilities ExplorerV2LifecycleConfig) { - if app == nil || authorizer == nil || authorizeRead == nil || explorers == nil { - return +type explorerAuthoringHandlers struct { + getCapability fiber.Handler + searchSuggestions fiber.Handler + getCandidateSuggestions fiber.Handler + getBuilder fiber.Handler + saveDraft fiber.Handler + exportWorkspace fiber.Handler + applyCommands fiber.Handler + compileBuilder fiber.Handler + compile fiber.Handler + reconcile fiber.Handler + preview fiber.Handler + publish fiber.Handler +} + +// newExplorerAuthoringHandlers is the hard-cut traversal Builder contract. +// Generated OpenAPI code owns all method/path registration. +func newExplorerAuthoringHandlers(authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, explorers *explorer.Service, capabilities ExplorerV2LifecycleConfig) *explorerAuthoringHandlers { + handlers := &explorerAuthoringHandlers{} + if authorizer == nil || authorizeRead == nil || explorers == nil { + return handlers } - prefix := "/api/v1/projects/:project/explorers/:explorerId/authoring/v2" readCapability := func(c fiber.Ctx) (capability.Snapshot, authoringv2.CatalogSnapshot, error) { if capabilities.Capability == nil { @@ -45,7 +60,7 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth return snapshot, authoringV2Catalog(snapshot, id), nil } - app.Get(prefix+"/capability", func(c fiber.Ctx) error { + handlers.getCapability = func(c fiber.Ctx) error { if err := authoringRead(c, authorizeRead); err != nil { return err } @@ -56,9 +71,9 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth PreviewLimits: []int{10, 25, 50, 100}, Features: explorerv2api.AuthoringFeatures{EmissionFilters: true, EmissionCharts: true}, }) - }) + } - app.Post(prefix+"/suggestions", func(c fiber.Ctx) error { + handlers.searchSuggestions = func(c fiber.Ctx) error { if err := authoringRead(c, authorizeRead); err != nil { return err } @@ -88,13 +103,13 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth } } return c.JSON(fiber.Map{"apiVersion": authoringv2.APIVersion, "kind": "ExplorerBuilderCandidateSuggestions", "snapshotToken": request.SnapshotToken, "nodeId": request.NodeId, "candidates": candidates, "diagnostics": []any{}}) - }) + } // Suggested values stay out of the main capability document. They are // bounded during capability construction and fetched only when a user opens // a field control, while retaining the exact snapshot-token semantics used // by compilation. - app.Get(prefix+"/capabilities/:snapshotToken/candidates/:candidateId/suggestions", func(c fiber.Ctx) error { + handlers.getCandidateSuggestions = func(c fiber.Ctx) error { if err := authoringRead(c, authorizeRead); err != nil { return err } @@ -123,9 +138,9 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth }) } return authoringHTTPError(c, &explorer.AuthoringError{Status: http.StatusNotFound, Diagnostic: explorer.AuthoringDiagnostic{Severity: "ERROR", Stage: "capability", Code: "CANDIDATE_NOT_FOUND", Message: "candidate is not present in the capability snapshot"}}) - }) + } - app.Get(prefix+"/builder", func(c fiber.Ctx) error { + handlers.getBuilder = func(c fiber.Ctx) error { if err := authoringRead(c, authorizeRead); err != nil { return err } @@ -168,9 +183,9 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth return authoringHTTPError(c, explorerUnavailable("capability", "CAPABILITY_UNAVAILABLE", err.Error())) } return c.JSON(state) - }) + } - app.Put(prefix+"/draft", func(c fiber.Ctx) error { + handlers.saveDraft = func(c fiber.Ctx) error { if err := authoringWrite(c, authorizer); err != nil { return err } @@ -206,9 +221,9 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth return authoringHTTPError(c, err) } return c.JSON(fiber.Map{"workspace": json.RawMessage(stored.DraftConfig), "draftVersion": stored.DraftVersion, "draftDigest": stored.DraftDigest}) - }) + } - app.Get(prefix+"/export", func(c fiber.Ctx) error { + handlers.exportWorkspace = func(c fiber.Ctx) error { if err := authoringRead(c, authorizeRead); err != nil { return err } @@ -236,9 +251,9 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth c.Set(fiber.HeaderContentType, fiber.MIMEApplicationJSON) c.Set(fiber.HeaderContentDisposition, `attachment; filename="`+id+`.explorer-workspace.json"`) return c.Send(canonical) - }) + } - app.Post(prefix+"/commands", func(c fiber.Ctx) error { + handlers.applyCommands = func(c fiber.Ctx) error { if err := authoringWrite(c, authorizer); err != nil { return err } @@ -268,7 +283,7 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth default: return c.JSON(response) } - }) + } compileWorkspace := func(c fiber.Ctx, workspace authoringv2.Workspace, snapshotToken string) error { if (capabilities.CapabilityToken == nil && capabilities.AuthorizedCapabilityCompile == nil) || capabilities.CompileReceipt == nil { @@ -315,9 +330,9 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth } return compileWorkspace(c, request.Workspace, request.SnapshotToken) } - app.Post(prefix+"/builder", compileHandler) - app.Post(prefix+"/compile", compileHandler) - app.Post(prefix+"/reconcile", func(c fiber.Ctx) error { + handlers.compileBuilder = compileHandler + handlers.compile = compileHandler + handlers.reconcile = func(c fiber.Ctx) error { if err := authoringWrite(c, authorizer); err != nil { return err } @@ -344,9 +359,9 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth return authoringHTTPError(c, explorerConflict("reconcile", "AUTHORING_STATE_MISSING", "the saved Explorer draft cannot be reconciled", nil)) } return compileWorkspace(c, workspace, request.SnapshotToken) - }) + } - app.Post(prefix+"/preview", func(c fiber.Ctx) error { + handlers.preview = func(c fiber.Ctx) error { started := time.Now() previewCtx, cancel := context.WithTimeout(c.Context(), explorerPreviewTimeout) defer cancel() @@ -452,9 +467,9 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth outcome = "success" c.Set(fiber.HeaderContentType, fiber.MIMEApplicationJSON) return c.Send(encoded) - }) + } - app.Post(prefix+"/publish", func(c fiber.Ctx) error { + handlers.publish = func(c fiber.Ctx) error { if err := authoringWrite(c, authorizer); err != nil { return err } @@ -542,7 +557,8 @@ func RegisterExplorerAuthoringV2Routes(app *fiber.App, authorizer authscope.Auth Outputs: outputs, Diagnostics: []explorerv2api.Diagnostic{}, }) - }) + } + return handlers } func validateV2ReceiptRoute(c fiber.Ctx, receipt *explorer.CompilationReceipt, capabilities ExplorerV2LifecycleConfig) error { diff --git a/internal/server/explorer_builder_lifecycle.go b/internal/server/explorer_builder_lifecycle.go index b7327d9c..dd083b9d 100644 --- a/internal/server/explorer_builder_lifecycle.go +++ b/internal/server/explorer_builder_lifecycle.go @@ -10,13 +10,20 @@ import ( "github.com/gofiber/fiber/v3" ) -// RegisterExplorerLifecycleRoutes exposes only collection summaries, creation, -// and the active runtime projection. All browser editing uses authoring/v2. -func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, explorers *explorer.Service, capabilities ExplorerV2LifecycleConfig) { - if app == nil || authorizer == nil || authorizeRead == nil || explorers == nil { - return +type explorerLifecycleHandlers struct { + list fiber.Handler + get fiber.Handler + create fiber.Handler +} + +// newExplorerLifecycleHandlers exposes only collection summaries, creation, +// and the active runtime projection. Generated OpenAPI routing owns paths. +func newExplorerLifecycleHandlers(authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, explorers *explorer.Service, capabilities ExplorerV2LifecycleConfig) *explorerLifecycleHandlers { + handlers := &explorerLifecycleHandlers{} + if authorizer == nil || authorizeRead == nil || explorers == nil { + return handlers } - app.Get("/api/v1/projects/:project/explorers", func(c fiber.Ctx) error { + handlers.list = func(c fiber.Ctx) error { project := explorerProjectParam(c) if err := authorizeRead(c.Context(), principalFromFiber(c), project); err != nil { return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") @@ -30,9 +37,9 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author summaries = append(summaries, explorer.ExplorerSummaryV1{Project: project, ExplorerID: value.ExplorerID, Title: value.Title, Management: value.ManagementMode, ActiveRevisionID: value.ActiveRevisionID, UpdatedAt: value.UpdatedAt}) } return c.JSON(summaries) - }) + } - app.Get("/api/v1/projects/:project/explorers/:explorerId", func(c fiber.Ctx) error { + handlers.get = func(c fiber.Ctx) error { project, id := explorerProjectParam(c), strings.TrimSpace(c.Params("explorerId")) if err := authorizeRead(c.Context(), principalFromFiber(c), project); err != nil { return explorerV2Error(c, http.StatusForbidden, "FORBIDDEN", "forbidden") @@ -45,9 +52,9 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author return explorerV2Error(c, 500, "EXPLORER_READ_FAILED", err.Error()) } return c.JSON(state) - }) + } - app.Post("/api/v1/projects/:project/explorers", func(c fiber.Ctx) error { + handlers.create = func(c fiber.Ctx) error { project := explorerProjectParam(c) if err := authorizeExplorerWrite(c, authorizer, project); err != nil { return err @@ -76,5 +83,6 @@ func RegisterExplorerLifecycleRoutes(app *fiber.App, authorizer authscope.Author return explorerV2Error(c, 422, "INVALID_EXPLORER", err.Error()) } return c.Status(http.StatusCreated).JSON(explorer.ExplorerSummaryV1{Project: project, ExplorerID: value.ExplorerID, Title: value.Title, Management: value.ManagementMode, UpdatedAt: value.UpdatedAt}) - }) + } + return handlers } diff --git a/internal/server/explorer_config_route.go b/internal/server/explorer_config_route.go index 7379b560..421f410a 100644 --- a/internal/server/explorer_config_route.go +++ b/internal/server/explorer_config_route.go @@ -17,16 +17,23 @@ import ( "github.com/gofiber/fiber/v3" ) -// RegisterExplorerConfigV2Route is the sole repository Explorer deployment -// surface. The body is the portable V2 authoring workspace. Repository and -// browser publication deliberately share the same compiler receipt pipeline. type explorerConfigReadAuthorizer func(context.Context, *authscope.Principal, string) error -func RegisterExplorerConfigV2Route(app *fiber.App, authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, explorers *explorer.Service, materialize graphresolver.ExplorerBundleMaterializer, lifecycle ...ExplorerV2LifecycleConfig) { - if app == nil || authorizer == nil || authorizeRead == nil || explorers == nil { - return +type explorerHTTPHandlers struct { + publishRepositoryConfig fiber.Handler + getRepositoryConfig fiber.Handler + lifecycle *explorerLifecycleHandlers + authoring *explorerAuthoringHandlers +} + +// newExplorerHTTPHandlers builds the live Explorer transport implementations; +// generated OpenAPI code owns all method/path registration. +func newExplorerHTTPHandlers(authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, explorers *explorer.Service, materialize graphresolver.ExplorerBundleMaterializer, lifecycle ...ExplorerV2LifecycleConfig) *explorerHTTPHandlers { + handlers := &explorerHTTPHandlers{} + if authorizer == nil || authorizeRead == nil || explorers == nil { + return handlers } - app.Post("/api/v1/projects/:project/generations/:generation/explorer-config", func(c fiber.Ctx) error { + handlers.publishRepositoryConfig = func(c fiber.Ctx) error { project, generation := explorerProjectParam(c), strings.TrimSpace(c.Params("generation")) if project == "" || generation == "" { return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "project and generation are required"}) @@ -123,8 +130,8 @@ func RegisterExplorerConfigV2Route(app *fiber.App, authorizer authscope.Authoriz return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": fmt.Sprintf("persist ExplorerConfigV2: %v", err)}) } return c.Status(http.StatusOK).JSON(fiber.Map{"project": project, "generation": generation, "explorerId": "default", "receiptId": receipt.ID, "revisionId": revision.ID, "executionId": execution.ID, "recipe": receipt.Bundle.Name, "translationVersion": receipt.Bundle.TranslationVersion, "activated": true}) - }) - app.Get("/api/v1/projects/:project/explorer-config", func(c fiber.Ctx) error { + } + handlers.getRepositoryConfig = func(c fiber.Ctx) error { project := explorerProjectParam(c) principal, _ := c.Locals("principal").(*authscope.Principal) if err := authorizeRead(c.Context(), principal, project); err != nil { @@ -138,12 +145,13 @@ func RegisterExplorerConfigV2Route(app *fiber.App, authorizer authscope.Authoriz return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(value) - }) + } if len(lifecycle) == 0 { lifecycle = []ExplorerV2LifecycleConfig{{Materialize: materialize}} } - RegisterExplorerLifecycleRoutes(app, authorizer, authorizeRead, explorers, lifecycle[0]) - RegisterExplorerAuthoringV2Routes(app, authorizer, authorizeRead, explorers, lifecycle[0]) + handlers.lifecycle = newExplorerLifecycleHandlers(authorizer, authorizeRead, explorers, lifecycle[0]) + handlers.authoring = newExplorerAuthoringHandlers(authorizer, authorizeRead, explorers, lifecycle[0]) + return handlers } func explorerMaterializations(bundle recipe.Bundle, execution graphresolver.RecipeExecution) []explorer.Materialization { diff --git a/internal/server/explorer_config_route_test.go b/internal/server/explorer_config_route_test.go index d70ee535..09f4790f 100644 --- a/internal/server/explorer_config_route_test.go +++ b/internal/server/explorer_config_route_test.go @@ -52,7 +52,7 @@ func TestRepositoryDeploymentPersistsExecutableDataframeSelectors(t *testing.T) }, ActivateRelease: activateRelease, } - RegisterExplorerConfigV2Route(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, materialize, config) + registerTestExplorerRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, materialize, config) request := requestJSONWithHeaders(t, app, http.MethodPost, "/api/v1/projects/project-a/generations/generation-a/explorer-config", string(baselineExplorerWorkspaceV2()), map[string]string{"X-Loom-Source-Commit": "commit-a"}) if request.StatusCode != http.StatusOK { diff --git a/internal/server/explorer_lifecycle_helpers.go b/internal/server/explorer_lifecycle_helpers.go index 85e0382c..a52bf47b 100644 --- a/internal/server/explorer_lifecycle_helpers.go +++ b/internal/server/explorer_lifecycle_helpers.go @@ -5,7 +5,6 @@ import ( "encoding/hex" "encoding/json" "fmt" - "net/url" "strings" graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" @@ -36,15 +35,6 @@ func verifyQueryableOutputs(bundle recipe.Bundle, execution graphresolver.Recipe return nil } -func mustBundleDigest(bundle recipe.Bundle) string { - digest, _ := bundle.Digest() - return digest -} - -func explorerURL(project, id string) string { - return "/api/v1/projects/" + url.PathEscape(project) + "/explorers/" + url.PathEscape(id) -} - func resolvedOutputFingerprints(resolved engine.Resolved) map[string]string { result := make(map[string]string, len(resolved.Compiled.Outputs)) for _, output := range resolved.Compiled.Outputs { diff --git a/internal/server/explorer_preview_response.go b/internal/server/explorer_preview_response.go index f690c6c1..3a0b3eb2 100644 --- a/internal/server/explorer_preview_response.go +++ b/internal/server/explorer_preview_response.go @@ -9,7 +9,7 @@ import ( "net/http" "time" - explorerv2api "github.com/calypr/loom/generated/explorerv2" + explorerv2api "github.com/calypr/loom/generated/loomapi" dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" "github.com/calypr/loom/internal/explorer" "github.com/gofiber/fiber/v3" diff --git a/internal/server/explorer_receipt_contract_test.go b/internal/server/explorer_receipt_contract_test.go index 397fea88..33c9ef5f 100644 --- a/internal/server/explorer_receipt_contract_test.go +++ b/internal/server/explorer_receipt_contract_test.go @@ -165,7 +165,7 @@ func TestNativeV2RouteUsesAuthorizedPersistedReceipt(t *testing.T) { }, } app := fiber.New() - RegisterExplorerAuthoringV2Routes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, config) + registerTestExplorerAuthoringRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, config) body := `{"workspace":` + string(baselineExplorerWorkspaceV2()) + `,"snapshotToken":"` + snapshot.Token + `"}` compiled := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/compile", body) if compiled.StatusCode != http.StatusOK { @@ -243,7 +243,7 @@ func TestBuilderCommandsCreateBackendOwnedDraftAndReconcileIt(t *testing.T) { }, } app := fiber.New() - RegisterExplorerAuthoringV2Routes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, config) + registerTestExplorerAuthoringRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, config) commandBody := `{"commandId":"browser-command-1","snapshotToken":"` + snapshot.Token + `","expectedDraftVersion":0,"commands":[{"type":"CREATE_TABLE","title":"Patients","rootNodeId":"n_patient"}]}` created := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers/custom/authoring/v2/commands", commandBody) @@ -292,7 +292,7 @@ func TestCreateExplorerFromCurrentClonesWorkspaceOnServer(t *testing.T) { t.Fatal(err) } app := fiber.New() - RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{}) + registerTestExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{}) created := requestJSON(t, app, http.MethodPost, "/api/v1/projects/project-a/explorers", `{"name":"Cloned Explorer","title":"Cloned Explorer","sourceExplorerId":"source"}`) if created.StatusCode != http.StatusCreated { t.Fatalf("clone status=%d body=%s", created.StatusCode, created.Body) diff --git a/internal/server/explorer_route_test_helpers_test.go b/internal/server/explorer_route_test_helpers_test.go new file mode 100644 index 00000000..9430eca9 --- /dev/null +++ b/internal/server/explorer_route_test_helpers_test.go @@ -0,0 +1,40 @@ +package server + +import ( + graphresolver "github.com/calypr/loom/internal/api/graphql/graph/resolver" + "github.com/calypr/loom/internal/authscope" + "github.com/calypr/loom/internal/explorer" + "github.com/gofiber/fiber/v3" +) + +func registerTestExplorerLifecycleRoutes(router fiber.Router, authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, service *explorer.Service, config ExplorerV2LifecycleConfig) { + handlers := newExplorerLifecycleHandlers(authorizer, authorizeRead, service, config) + router.Get("/api/v1/projects/:project/explorers", handlers.list) + router.Post("/api/v1/projects/:project/explorers", handlers.create) + router.Get("/api/v1/projects/:project/explorers/:explorerId", handlers.get) +} + +func registerTestExplorerAuthoringRoutes(router fiber.Router, authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, service *explorer.Service, config ExplorerV2LifecycleConfig) { + h := newExplorerAuthoringHandlers(authorizer, authorizeRead, service, config) + base := "/api/v1/projects/:project/explorers/:explorerId/authoring/v2" + router.Get(base+"/capability", h.getCapability) + router.Get(base+"/capabilities/:snapshotToken/candidates/:candidateId/suggestions", h.getCandidateSuggestions) + router.Post(base+"/suggestions", h.searchSuggestions) + router.Get(base+"/builder", h.getBuilder) + router.Post(base+"/builder", h.compileBuilder) + router.Post(base+"/compile", h.compile) + router.Post(base+"/commands", h.applyCommands) + router.Post(base+"/reconcile", h.reconcile) + router.Put(base+"/draft", h.saveDraft) + router.Get(base+"/export", h.exportWorkspace) + router.Post(base+"/preview", h.preview) + router.Post(base+"/publish", h.publish) +} + +func registerTestExplorerRoutes(router fiber.Router, authorizer authscope.Authorizer, authorizeRead explorerConfigReadAuthorizer, service *explorer.Service, materialize graphresolver.ExplorerBundleMaterializer, config ExplorerV2LifecycleConfig) { + h := newExplorerHTTPHandlers(authorizer, authorizeRead, service, materialize, config) + router.Post("/api/v1/projects/:project/generations/:generation/explorer-config", h.publishRepositoryConfig) + router.Get("/api/v1/projects/:project/explorer-config", h.getRepositoryConfig) + registerTestExplorerLifecycleRoutes(router, authorizer, authorizeRead, service, config) + registerTestExplorerAuthoringRoutes(router, authorizer, authorizeRead, service, config) +} diff --git a/internal/server/explorer_state_route_test.go b/internal/server/explorer_state_route_test.go index a0ebbe05..d3018def 100644 --- a/internal/server/explorer_state_route_test.go +++ b/internal/server/explorer_state_route_test.go @@ -47,7 +47,7 @@ func TestExplorerStateRouteBuildsDefaultProjectionFromRecipe(t *testing.T) { store.mu.Unlock() app := fiber.New() - RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{}) + registerTestExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{}) response := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/patients", "") if response.StatusCode != http.StatusOK { t.Fatalf("status=%d body=%s", response.StatusCode, response.Body) @@ -147,7 +147,7 @@ func TestExplorerStateRouteReturnsExplicitUnpublishedProjection(t *testing.T) { } app := fiber.New() - RegisterExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{}) + registerTestExplorerLifecycleRoutes(app, authscope.AllowAllAuthorizer{}, func(context.Context, *authscope.Principal, string) error { return nil }, service, ExplorerV2LifecycleConfig{}) response := requestJSON(t, app, http.MethodGet, "/api/v1/projects/project-a/explorers/empty", "") if response.StatusCode != http.StatusOK { t.Fatalf("status=%d body=%s", response.StatusCode, response.Body) diff --git a/internal/server/openapi_route_inventory_test.go b/internal/server/openapi_route_inventory_test.go new file mode 100644 index 00000000..a1a71c48 --- /dev/null +++ b/internal/server/openapi_route_inventory_test.go @@ -0,0 +1,124 @@ +package server + +import ( + "context" + "fmt" + "strings" + "testing" + + loomapi "github.com/calypr/loom/generated/loomapi" + "github.com/gofiber/fiber/v3" +) + +func TestGeneratedRoutesExactlyMatchOpenAPISpec(t *testing.T) { + app := fiber.New() + handler := loomapi.NewStrictHandler(&HTTPRoutes{}, []loomapi.StrictMiddlewareFunc{strictFiberContextMiddleware}) + loomapi.RegisterHandlersWithOptions(app, handler, loomapi.FiberServerOptions{}) + + want := map[string]bool{} + spec, err := loomapi.GetSwagger() + if err != nil { + t.Fatal(err) + } + if err := spec.Validate(context.Background()); err != nil { + t.Fatalf("embedded OpenAPI document is invalid: %v", err) + } + for path, item := range spec.Paths.Map() { + for method := range item.Operations() { + want[strings.ToUpper(method)+" "+path] = true + } + } + + got := map[string]bool{} + for _, route := range app.GetRoutes(true) { + path := route.Path + for _, parameter := range route.Params { + path = strings.ReplaceAll(path, ":"+parameter, "{"+parameter+"}") + } + got[route.Method+" "+path] = true + } + for route := range want { + if !got[route] { + t.Errorf("OpenAPI operation is not registered: %s", route) + } + } + for route := range got { + if !want[route] { + t.Errorf("registered route is absent from OpenAPI: %s", route) + } + } + if len(got) != 39 || len(want) != 39 { + t.Errorf("route count got=%d spec=%d, want 39", len(got), len(want)) + } +} + +func TestOpenAPIOperationsDeclareExplicitResponses(t *testing.T) { + spec, err := loomapi.GetSwagger() + if err != nil { + t.Fatal(err) + } + for path, item := range spec.Paths.Map() { + for method, operation := range item.Operations() { + name := fmt.Sprintf("%s %s", strings.ToUpper(method), path) + responses := operation.Responses.Map() + if _, ok := responses["default"]; ok { + t.Errorf("%s uses a default response instead of an explicit status", name) + } + hasSuccess := false + for status, responseRef := range responses { + if strings.HasPrefix(status, "2") { + hasSuccess = true + } + if responseRef == nil || responseRef.Value == nil { + t.Errorf("%s response %s is unresolved", name, status) + continue + } + if responseRef.Value.Description == nil || strings.TrimSpace(*responseRef.Value.Description) == "" { + t.Errorf("%s response %s has no human-readable description", name, status) + } + if len(responseRef.Value.Content) == 0 { + t.Errorf("%s response %s does not declare a response media type and schema", name, status) + } + } + if !hasSuccess { + t.Errorf("%s has no explicit successful response", name) + } + if path != "/health" && path != "/livez" && path != "/readyz" { + if _, ok := responses["401"]; !ok { + t.Errorf("%s omits the authentication failure produced by shared middleware", name) + } + } + } + } +} + +func TestOpenAPIDocumentsOperationSpecificFailureStatuses(t *testing.T) { + spec, err := loomapi.GetSwagger() + if err != nil { + t.Fatal(err) + } + assertStatuses := func(method, path string, statuses ...string) { + t.Helper() + item := spec.Paths.Value(path) + if item == nil { + t.Errorf("path %s not found", path) + return + } + operation := item.GetOperation(method) + if operation == nil { + t.Errorf("%s %s not found", method, path) + return + } + responses := operation.Responses.Map() + for _, status := range statuses { + if _, ok := responses[status]; !ok { + t.Errorf("%s does not document response %s", operation.OperationID, status) + } + } + } + + assertStatuses("PUT", "/api/v1/projects/{project}/resources/{resourceType}", "400", "401", "403", "415", "422", "500", "503") + assertStatuses("POST", "/api/v1/datasets/{project}/generations/{generation}", "400", "401", "403", "409", "415", "422", "500", "503") + assertStatuses("POST", "/api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/preview", "400", "401", "403", "404", "409", "413", "422", "429", "499", "500", "503", "504") + assertStatuses("POST", "/api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/publish", "400", "401", "403", "404", "409", "422", "500", "503") +} diff --git a/internal/server/openapi_routes.go b/internal/server/openapi_routes.go new file mode 100644 index 00000000..2e33d908 --- /dev/null +++ b/internal/server/openapi_routes.go @@ -0,0 +1,1196 @@ +package server + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/http" + + loomapi "github.com/calypr/loom/generated/loomapi" + loadapi "github.com/calypr/loom/internal/api/bulk/load" + graphapi "github.com/calypr/loom/internal/api/graphql/graph" + httpapi "github.com/calypr/loom/internal/api/http" + "github.com/gofiber/fiber/v3" + fiberadaptor "github.com/gofiber/fiber/v3/middleware/adaptor" +) + +type strictFiberContextKey struct{} + +type HTTPRoutes struct { + server *httpapi.HTTPServer + load *loadapi.Handler + recipe httpapi.RecipeExecutionHandler + graphql graphapi.RouteConfig + explorer *explorerHTTPHandlers +} + +var _ loomapi.StrictServerInterface = (*HTTPRoutes)(nil) + +func strictFiberContextMiddleware(next loomapi.StrictHandlerFunc, _ string) loomapi.StrictHandlerFunc { + return func(c fiber.Ctx, args any) (any, error) { + c.SetContext(context.WithValue(c.Context(), strictFiberContextKey{}, c)) + return next(c, args) + } +} + +func fiberContext(ctx context.Context) (fiber.Ctx, error) { + c, ok := ctx.Value(strictFiberContextKey{}).(fiber.Ctx) + if !ok || c == nil { + return nil, fmt.Errorf("generated route is missing Fiber request context") + } + return c, nil +} + +func runFiberHandler(ctx context.Context, handler fiber.Handler) (int, []byte, error) { + c, err := fiberContext(ctx) + if err != nil { + return 0, nil, err + } + if handler == nil { + return http.StatusNotFound, []byte(`{"error":"not found"}`), nil + } + if err := handler(c); err != nil { + return 0, nil, err + } + status := c.Response().StatusCode() + body := append([]byte(nil), c.Response().Body()...) + c.Response().ResetBody() + return status, body, nil +} + +func decodeResponse[T any](body []byte) (T, error) { + var value T + if err := json.Unmarshal(body, &value); err != nil { + return value, fmt.Errorf("decode generated response: %w", err) + } + return value, nil +} + +func authoringError(body []byte, status int) (loomapi.ErrorResponse, int, error) { + value, err := decodeResponse[loomapi.ErrorResponse](body) + return value, status, err +} + +func serviceError(body []byte) (loomapi.ServiceErrorResponse, error) { + return decodeResponse[loomapi.ServiceErrorResponse](body) +} + +func legacyError(body []byte) (loomapi.LegacyErrorResponse, error) { + return decodeResponse[loomapi.LegacyErrorResponse](body) +} + +func unexpectedResponseStatus(operation string, status int) error { + return fmt.Errorf("%s returned undocumented HTTP status %d", operation, status) +} + +func (r *HTTPRoutes) GetHealth(ctx context.Context, _ loomapi.GetHealthRequestObject) (loomapi.GetHealthResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.server.HandleHealth) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.GetHealth200JSONResponse](body) + return response, decodeErr + } + if status == http.StatusServiceUnavailable { + response, decodeErr := decodeResponse[loomapi.GetHealth503JSONResponse](body) + return response, decodeErr + } + return nil, unexpectedResponseStatus("getHealth", status) +} + +func (r *HTTPRoutes) GetLiveness(ctx context.Context, _ loomapi.GetLivenessRequestObject) (loomapi.GetLivenessResponseObject, error) { + _, body, err := runFiberHandler(ctx, r.server.HandleLiveness) + if err != nil { + return nil, err + } + response, decodeErr := decodeResponse[loomapi.GetLiveness200JSONResponse](body) + return response, decodeErr +} + +func (r *HTTPRoutes) GetReadiness(ctx context.Context, _ loomapi.GetReadinessRequestObject) (loomapi.GetReadinessResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.server.HandleReadiness) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.GetReadiness200JSONResponse](body) + return response, decodeErr + } + response, decodeErr := decodeResponse[loomapi.GetReadiness503JSONResponse](body) + return response, decodeErr +} + +func (r *HTTPRoutes) UploadProjectResource(ctx context.Context, _ loomapi.UploadProjectResourceRequestObject) (loomapi.UploadProjectResourceResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleResource) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.UploadProjectResource200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case http.StatusBadRequest: + return loomapi.UploadProjectResource400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case http.StatusUnauthorized: + return loomapi.UploadProjectResource401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case http.StatusForbidden: + return loomapi.UploadProjectResource403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case http.StatusUnsupportedMediaType: + return loomapi.UploadProjectResource415JSONResponse{ServiceUnsupportedMediaTypeJSONResponse: loomapi.ServiceUnsupportedMediaTypeJSONResponse(value)}, nil + case http.StatusUnprocessableEntity: + return loomapi.UploadProjectResource422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil + case http.StatusInternalServerError: + return loomapi.UploadProjectResource500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case http.StatusServiceUnavailable: + return loomapi.UploadProjectResource503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("uploadProjectResource", status) + } +} + +func (r *HTTPRoutes) CreateDatasetGeneration(ctx context.Context, _ loomapi.CreateDatasetGenerationRequestObject) (loomapi.CreateDatasetGenerationResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleCreateGeneration) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.CreateDatasetGeneration200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case http.StatusBadRequest: + return loomapi.CreateDatasetGeneration400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case http.StatusUnauthorized: + return loomapi.CreateDatasetGeneration401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case http.StatusForbidden: + return loomapi.CreateDatasetGeneration403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case http.StatusConflict: + return loomapi.CreateDatasetGeneration409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil + case http.StatusUnsupportedMediaType: + return loomapi.CreateDatasetGeneration415JSONResponse{ServiceUnsupportedMediaTypeJSONResponse: loomapi.ServiceUnsupportedMediaTypeJSONResponse(value)}, nil + case http.StatusUnprocessableEntity: + return loomapi.CreateDatasetGeneration422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil + case http.StatusInternalServerError: + return loomapi.CreateDatasetGeneration500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case http.StatusServiceUnavailable: + return loomapi.CreateDatasetGeneration503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("createDatasetGeneration", status) + } +} + +func (r *HTTPRoutes) ActivateDatasetGeneration(ctx context.Context, _ loomapi.ActivateDatasetGenerationRequestObject) (loomapi.ActivateDatasetGenerationResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleActivateGeneration) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.ActivateDatasetGeneration200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case http.StatusBadRequest: + return loomapi.ActivateDatasetGeneration400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case http.StatusUnauthorized: + return loomapi.ActivateDatasetGeneration401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case http.StatusForbidden: + return loomapi.ActivateDatasetGeneration403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case http.StatusConflict: + return loomapi.ActivateDatasetGeneration409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil + case http.StatusInternalServerError: + return loomapi.ActivateDatasetGeneration500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case http.StatusServiceUnavailable: + return loomapi.ActivateDatasetGeneration503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("activateDatasetGeneration", status) + } +} + +func (r *HTTPRoutes) UploadRawNDJSON(ctx context.Context, _ loomapi.UploadRawNDJSONRequestObject) (loomapi.UploadRawNDJSONResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleLoadRaw) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.UploadRawNDJSON200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case http.StatusBadRequest: + return loomapi.UploadRawNDJSON400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case http.StatusUnauthorized: + return loomapi.UploadRawNDJSON401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case http.StatusForbidden: + return loomapi.UploadRawNDJSON403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case http.StatusUnsupportedMediaType: + return loomapi.UploadRawNDJSON415JSONResponse{ServiceUnsupportedMediaTypeJSONResponse: loomapi.ServiceUnsupportedMediaTypeJSONResponse(value)}, nil + case http.StatusUnprocessableEntity: + return loomapi.UploadRawNDJSON422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil + case http.StatusInternalServerError: + return loomapi.UploadRawNDJSON500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case http.StatusServiceUnavailable: + return loomapi.UploadRawNDJSON503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("uploadRawNDJSON", status) + } +} + +func (r *HTTPRoutes) CreateSnapshot(ctx context.Context, _ loomapi.CreateSnapshotRequestObject) (loomapi.CreateSnapshotResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleCreateSnapshot) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.CreateSnapshot200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.CreateSnapshot400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case 401: + return loomapi.CreateSnapshot401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.CreateSnapshot403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 409: + return loomapi.CreateSnapshot409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil + case 500: + return loomapi.CreateSnapshot500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.CreateSnapshot503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("createSnapshot", status) + } +} + +func (r *HTTPRoutes) GetSnapshot(ctx context.Context, _ loomapi.GetSnapshotRequestObject) (loomapi.GetSnapshotResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleSnapshotStatus) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.GetSnapshot200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 401: + return loomapi.GetSnapshot401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.GetSnapshot403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.GetSnapshot404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil + case 500: + return loomapi.GetSnapshot500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.GetSnapshot503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("getSnapshot", status) + } +} + +func (r *HTTPRoutes) AbortSnapshot(ctx context.Context, _ loomapi.AbortSnapshotRequestObject) (loomapi.AbortSnapshotResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleAbortSnapshot) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.AbortSnapshot200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 401: + return loomapi.AbortSnapshot401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.AbortSnapshot403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.AbortSnapshot404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.AbortSnapshot409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil + case 500: + return loomapi.AbortSnapshot500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.AbortSnapshot503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("abortSnapshot", status) + } +} + +func (r *HTTPRoutes) UploadSnapshotResource(ctx context.Context, _ loomapi.UploadSnapshotResourceRequestObject) (loomapi.UploadSnapshotResourceResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleUploadSnapshotResource) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.UploadSnapshotResource200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.UploadSnapshotResource400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case 401: + return loomapi.UploadSnapshotResource401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.UploadSnapshotResource403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.UploadSnapshotResource404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.UploadSnapshotResource409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil + case 422: + return loomapi.UploadSnapshotResource422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.UploadSnapshotResource500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.UploadSnapshotResource503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("uploadSnapshotResource", status) + } +} + +func (r *HTTPRoutes) FinalizeSnapshot(ctx context.Context, _ loomapi.FinalizeSnapshotRequestObject) (loomapi.FinalizeSnapshotResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleFinalizeSnapshot) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.FinalizeSnapshot200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.FinalizeSnapshot400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case 401: + return loomapi.FinalizeSnapshot401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.FinalizeSnapshot403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.FinalizeSnapshot404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.FinalizeSnapshot409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil + case 422: + return loomapi.FinalizeSnapshot422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.FinalizeSnapshot500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.FinalizeSnapshot503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("finalizeSnapshot", status) + } +} + +func (r *HTTPRoutes) CreateRelease(ctx context.Context, _ loomapi.CreateReleaseRequestObject) (loomapi.CreateReleaseResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleCreateRelease) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.CreateRelease200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.CreateRelease400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case 401: + return loomapi.CreateRelease401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.CreateRelease403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.CreateRelease404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.CreateRelease409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil + case 422: + return loomapi.CreateRelease422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.CreateRelease500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.CreateRelease503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("createRelease", status) + } +} + +func (r *HTTPRoutes) GetActiveRelease(ctx context.Context, _ loomapi.GetActiveReleaseRequestObject) (loomapi.GetActiveReleaseResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleActiveRelease) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.GetActiveRelease200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 401: + return loomapi.GetActiveRelease401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.GetActiveRelease403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.GetActiveRelease404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil + case 500: + return loomapi.GetActiveRelease500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.GetActiveRelease503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("getActiveRelease", status) + } +} + +func (r *HTTPRoutes) GetRelease(ctx context.Context, _ loomapi.GetReleaseRequestObject) (loomapi.GetReleaseResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleReleaseStatus) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.GetRelease200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 401: + return loomapi.GetRelease401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.GetRelease403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.GetRelease404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil + case 500: + return loomapi.GetRelease500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.GetRelease503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("getRelease", status) + } +} + +func (r *HTTPRoutes) ActivateRelease(ctx context.Context, _ loomapi.ActivateReleaseRequestObject) (loomapi.ActivateReleaseResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleActivateRelease) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.ActivateRelease200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.ActivateRelease400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case 401: + return loomapi.ActivateRelease401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.ActivateRelease403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.ActivateRelease404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.ActivateRelease409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil + case 422: + return loomapi.ActivateRelease422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.ActivateRelease500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.ActivateRelease503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("activateRelease", status) + } +} + +func (r *HTTPRoutes) ActivateReleaseCompatibility(ctx context.Context, _ loomapi.ActivateReleaseCompatibilityRequestObject) (loomapi.ActivateReleaseCompatibilityResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleActivateReleaseCompatibility) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.ActivateReleaseCompatibility200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.ActivateReleaseCompatibility400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case 401: + return loomapi.ActivateReleaseCompatibility401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.ActivateReleaseCompatibility403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.ActivateReleaseCompatibility404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.ActivateReleaseCompatibility409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil + case 422: + return loomapi.ActivateReleaseCompatibility422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.ActivateReleaseCompatibility500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.ActivateReleaseCompatibility503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("activateReleaseCompatibility", status) + } +} + +func (r *HTTPRoutes) GetRecipeExecution(ctx context.Context, _ loomapi.GetRecipeExecutionRequestObject) (loomapi.GetRecipeExecutionResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.recipe.Handle) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.GetRecipeExecution200JSONResponse](body) + return response, decodeErr + } + if status == http.StatusUnauthorized { + response, decodeErr := decodeResponse[loomapi.GetRecipeExecution401JSONResponse](body) + return response, decodeErr + } + value, decodeErr := legacyError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 403: + return loomapi.GetRecipeExecution403JSONResponse{LegacyForbiddenJSONResponse: loomapi.LegacyForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.GetRecipeExecution404JSONResponse{LegacyNotFoundJSONResponse: loomapi.LegacyNotFoundJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("getRecipeExecution", status) + } +} + +func (r *HTTPRoutes) runGraphQL(ctx context.Context, handler http.Handler) (int, []byte, error) { + if handler == nil { + return http.StatusNotFound, []byte(`{"error":"not found"}`), nil + } + return runFiberHandler(ctx, fiberadaptor.HTTPHandlerWithContext(handler)) +} + +func (r *HTTPRoutes) ExecuteGraphQL(ctx context.Context, _ loomapi.ExecuteGraphQLRequestObject) (loomapi.ExecuteGraphQLResponseObject, error) { + status, body, err := r.runGraphQL(ctx, r.graphql.Handler) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.ExecuteGraphQL200JSONResponse](body) + return response, decodeErr + } + if status == http.StatusUnauthorized { + value, decodeErr := serviceError(body) + return loomapi.ExecuteGraphQL401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, decodeErr + } + value, decodeErr := decodeResponse[loomapi.RawJSON](body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.ExecuteGraphQL400JSONResponse{GraphQLBadRequestJSONResponse: loomapi.GraphQLBadRequestJSONResponse(value)}, nil + case 422: + return loomapi.ExecuteGraphQL422JSONResponse{GraphQLUnprocessableJSONResponse: loomapi.GraphQLUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.ExecuteGraphQL500JSONResponse{GraphQLInternalErrorJSONResponse: loomapi.GraphQLInternalErrorJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("executeGraphQL", status) + } +} + +func (r *HTTPRoutes) ExecuteDataframeGraphQL(ctx context.Context, _ loomapi.ExecuteDataframeGraphQLRequestObject) (loomapi.ExecuteDataframeGraphQLResponseObject, error) { + status, body, err := r.runGraphQL(ctx, r.graphql.Handler) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.ExecuteDataframeGraphQL200JSONResponse](body) + return response, decodeErr + } + if status == http.StatusUnauthorized { + value, decodeErr := serviceError(body) + return loomapi.ExecuteDataframeGraphQL401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, decodeErr + } + value, decodeErr := decodeResponse[loomapi.RawJSON](body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.ExecuteDataframeGraphQL400JSONResponse{GraphQLBadRequestJSONResponse: loomapi.GraphQLBadRequestJSONResponse(value)}, nil + case 422: + return loomapi.ExecuteDataframeGraphQL422JSONResponse{GraphQLUnprocessableJSONResponse: loomapi.GraphQLUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.ExecuteDataframeGraphQL500JSONResponse{GraphQLInternalErrorJSONResponse: loomapi.GraphQLInternalErrorJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("executeDataframeGraphQL", status) + } +} + +func (r *HTTPRoutes) GetGraphQLPlayground(ctx context.Context, _ loomapi.GetGraphQLPlaygroundRequestObject) (loomapi.GetGraphQLPlaygroundResponseObject, error) { + status, body, err := r.runGraphQL(ctx, r.graphql.Playground) + if err != nil { + return nil, err + } + if status != http.StatusOK { + return nil, fiber.ErrNotFound + } + return loomapi.GetGraphQLPlayground200TexthtmlResponse{HTMLTexthtmlResponse: loomapi.HTMLTexthtmlResponse{Body: bytes.NewReader(body), ContentLength: int64(len(body))}}, nil +} + +func (r *HTTPRoutes) GetApolloSandbox(ctx context.Context, _ loomapi.GetApolloSandboxRequestObject) (loomapi.GetApolloSandboxResponseObject, error) { + status, body, err := r.runGraphQL(ctx, r.graphql.Sandbox) + if err != nil { + return nil, err + } + if status != http.StatusOK { + return nil, fiber.ErrNotFound + } + return loomapi.GetApolloSandbox200TexthtmlResponse{HTMLTexthtmlResponse: loomapi.HTMLTexthtmlResponse{Body: bytes.NewReader(body), ContentLength: int64(len(body))}}, nil +} + +func (r *HTTPRoutes) ListExplorers(ctx context.Context, _ loomapi.ListExplorersRequestObject) (loomapi.ListExplorersResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.lifecycle.list) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.ListExplorers200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := legacyError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 403: + return loomapi.ListExplorers403JSONResponse{LegacyForbiddenJSONResponse: loomapi.LegacyForbiddenJSONResponse(value)}, nil + case 500: + return loomapi.ListExplorers500JSONResponse{LegacyInternalErrorJSONResponse: loomapi.LegacyInternalErrorJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("listExplorers", status) + } +} + +func (r *HTTPRoutes) CreateExplorer(ctx context.Context, _ loomapi.CreateExplorerRequestObject) (loomapi.CreateExplorerResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.lifecycle.create) + if err != nil { + return nil, err + } + if status == http.StatusCreated { + response, decodeErr := decodeResponse[loomapi.CreateExplorer201JSONResponse](body) + return response, decodeErr + } + value, decodeErr := legacyError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.CreateExplorer400JSONResponse{LegacyBadRequestJSONResponse: loomapi.LegacyBadRequestJSONResponse(value)}, nil + case 403: + return loomapi.CreateExplorer403JSONResponse{LegacyForbiddenJSONResponse: loomapi.LegacyForbiddenJSONResponse(value)}, nil + case 409: + return loomapi.CreateExplorer409JSONResponse{LegacyConflictJSONResponse: loomapi.LegacyConflictJSONResponse(value)}, nil + case 422: + return loomapi.CreateExplorer422JSONResponse{LegacyUnprocessableJSONResponse: loomapi.LegacyUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.CreateExplorer500JSONResponse{LegacyInternalErrorJSONResponse: loomapi.LegacyInternalErrorJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("createExplorer", status) + } +} + +func (r *HTTPRoutes) GetExplorer(ctx context.Context, _ loomapi.GetExplorerRequestObject) (loomapi.GetExplorerResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.lifecycle.get) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.GetExplorer200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := legacyError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 403: + return loomapi.GetExplorer403JSONResponse{LegacyForbiddenJSONResponse: loomapi.LegacyForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.GetExplorer404JSONResponse{LegacyNotFoundJSONResponse: loomapi.LegacyNotFoundJSONResponse(value)}, nil + case 500: + return loomapi.GetExplorer500JSONResponse{LegacyInternalErrorJSONResponse: loomapi.LegacyInternalErrorJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("getExplorer", status) + } +} + +func (r *HTTPRoutes) PublishRepositoryExplorerConfig(ctx context.Context, _ loomapi.PublishRepositoryExplorerConfigRequestObject) (loomapi.PublishRepositoryExplorerConfigResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.publishRepositoryConfig) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.PublishRepositoryExplorerConfig200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := legacyError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.PublishRepositoryExplorerConfig400JSONResponse{LegacyBadRequestJSONResponse: loomapi.LegacyBadRequestJSONResponse(value)}, nil + case 403: + return loomapi.PublishRepositoryExplorerConfig403JSONResponse{LegacyForbiddenJSONResponse: loomapi.LegacyForbiddenJSONResponse(value)}, nil + case 409: + return loomapi.PublishRepositoryExplorerConfig409JSONResponse{LegacyConflictJSONResponse: loomapi.LegacyConflictJSONResponse(value)}, nil + case 422: + return loomapi.PublishRepositoryExplorerConfig422JSONResponse{LegacyUnprocessableJSONResponse: loomapi.LegacyUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.PublishRepositoryExplorerConfig500JSONResponse{LegacyInternalErrorJSONResponse: loomapi.LegacyInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.PublishRepositoryExplorerConfig503JSONResponse{LegacyUnavailableJSONResponse: loomapi.LegacyUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("publishRepositoryExplorerConfig", status) + } +} + +func (r *HTTPRoutes) GetRepositoryExplorerConfig(ctx context.Context, _ loomapi.GetRepositoryExplorerConfigRequestObject) (loomapi.GetRepositoryExplorerConfigResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.getRepositoryConfig) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.GetRepositoryExplorerConfig200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := legacyError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 403: + return loomapi.GetRepositoryExplorerConfig403JSONResponse{LegacyForbiddenJSONResponse: loomapi.LegacyForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.GetRepositoryExplorerConfig404JSONResponse{LegacyNotFoundJSONResponse: loomapi.LegacyNotFoundJSONResponse(value)}, nil + case 500: + return loomapi.GetRepositoryExplorerConfig500JSONResponse{LegacyInternalErrorJSONResponse: loomapi.LegacyInternalErrorJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("getRepositoryExplorerConfig", status) + } +} + +func (r *HTTPRoutes) GetExplorerAuthoringCapability(ctx context.Context, _ loomapi.GetExplorerAuthoringCapabilityRequestObject) (loomapi.GetExplorerAuthoringCapabilityResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.authoring.getCapability) + if err != nil { + return nil, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.AuthoringCapability](body) + return loomapi.GetExplorerAuthoringCapability200JSONResponse(value), e + } + value, _, e := authoringError(body, status) + if e != nil { + return nil, e + } + switch status { + case 403: + return loomapi.GetExplorerAuthoringCapability403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil + case 500: + return loomapi.GetExplorerAuthoringCapability500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("getExplorerAuthoringCapability", status) + } +} + +func (r *HTTPRoutes) SearchExplorerCandidates(ctx context.Context, _ loomapi.SearchExplorerCandidatesRequestObject) (loomapi.SearchExplorerCandidatesResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.authoring.searchSuggestions) + if err != nil { + return nil, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.CandidateSearchResponse](body) + return loomapi.SearchExplorerCandidates200JSONResponse(value), e + } + value, _, e := authoringError(body, status) + if e != nil { + return nil, e + } + switch status { + case 400: + return loomapi.SearchExplorerCandidates400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(value)}, nil + case 403: + return loomapi.SearchExplorerCandidates403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil + case 409: + return loomapi.SearchExplorerCandidates409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil + case 500: + return loomapi.SearchExplorerCandidates500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.SearchExplorerCandidates503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("searchExplorerCandidates", status) + } +} + +func (r *HTTPRoutes) GetExplorerCandidateSuggestions(ctx context.Context, _ loomapi.GetExplorerCandidateSuggestionsRequestObject) (loomapi.GetExplorerCandidateSuggestionsResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.authoring.getCandidateSuggestions) + if err != nil { + return nil, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.CandidateSuggestions](body) + return loomapi.GetExplorerCandidateSuggestions200JSONResponse(value), e + } + value, _, e := authoringError(body, status) + if e != nil { + return nil, e + } + switch status { + case 400: + return loomapi.GetExplorerCandidateSuggestions400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(value)}, nil + case 403: + return loomapi.GetExplorerCandidateSuggestions403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.GetExplorerCandidateSuggestions404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.GetExplorerCandidateSuggestions409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil + case 500: + return loomapi.GetExplorerCandidateSuggestions500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.GetExplorerCandidateSuggestions503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("getExplorerCandidateSuggestions", status) + } +} + +func (r *HTTPRoutes) GetExplorerBuilder(ctx context.Context, _ loomapi.GetExplorerBuilderRequestObject) (loomapi.GetExplorerBuilderResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.authoring.getBuilder) + if err != nil { + return nil, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.BuilderState](body) + return loomapi.GetExplorerBuilder200JSONResponse(value), e + } + value, _, e := authoringError(body, status) + if e != nil { + return nil, e + } + switch status { + case 403: + return loomapi.GetExplorerBuilder403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.GetExplorerBuilder404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.GetExplorerBuilder409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil + case 500: + return loomapi.GetExplorerBuilder500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.GetExplorerBuilder503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("getExplorerBuilder", status) + } +} + +func (r *HTTPRoutes) SaveExplorerDraft(ctx context.Context, _ loomapi.SaveExplorerDraftRequestObject) (loomapi.SaveExplorerDraftResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.authoring.saveDraft) + if err != nil { + return nil, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.SaveDraftResponse](body) + return loomapi.SaveExplorerDraft200JSONResponse(value), e + } + value, _, e := authoringError(body, status) + if e != nil { + return nil, e + } + switch status { + case 400: + return loomapi.SaveExplorerDraft400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(value)}, nil + case 403: + return loomapi.SaveExplorerDraft403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.SaveExplorerDraft404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.SaveExplorerDraft409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil + case 422: + return loomapi.SaveExplorerDraft422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.SaveExplorerDraft500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.SaveExplorerDraft503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("saveExplorerDraft", status) + } +} + +func (r *HTTPRoutes) ExportExplorerWorkspace(ctx context.Context, _ loomapi.ExportExplorerWorkspaceRequestObject) (loomapi.ExportExplorerWorkspaceResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.authoring.exportWorkspace) + if err != nil { + return nil, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.Workspace](body) + return loomapi.ExportExplorerWorkspace200JSONResponse(value), e + } + value, _, e := authoringError(body, status) + if e != nil { + return nil, e + } + switch status { + case 403: + return loomapi.ExportExplorerWorkspace403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.ExportExplorerWorkspace404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.ExportExplorerWorkspace409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil + case 500: + return loomapi.ExportExplorerWorkspace500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("exportExplorerWorkspace", status) + } +} + +func (r *HTTPRoutes) ApplyExplorerBuilderCommands(ctx context.Context, _ loomapi.ApplyExplorerBuilderCommandsRequestObject) (loomapi.ApplyExplorerBuilderCommandsResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.authoring.applyCommands) + if err != nil { + return nil, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.ApplyCommandsResponse](body) + return loomapi.ApplyExplorerBuilderCommands200JSONResponse(value), e + } + value, _, e := authoringError(body, status) + if e != nil { + return nil, e + } + switch status { + case 400: + return loomapi.ApplyExplorerBuilderCommands400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(value)}, nil + case 403: + return loomapi.ApplyExplorerBuilderCommands403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil + case 409: + return loomapi.ApplyExplorerBuilderCommands409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil + case 422: + return loomapi.ApplyExplorerBuilderCommands422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.ApplyExplorerBuilderCommands500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.ApplyExplorerBuilderCommands503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("applyExplorerBuilderCommands", status) + } +} + +func (r *HTTPRoutes) compileExplorer(ctx context.Context, handler fiber.Handler) (loomapi.CompileResponse, loomapi.ErrorResponse, int, error) { + status, body, err := runFiberHandler(ctx, handler) + if err != nil { + return loomapi.CompileResponse{}, loomapi.ErrorResponse{}, 0, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.CompileResponse](body) + return value, loomapi.ErrorResponse{}, status, e + } + value, _, e := authoringError(body, status) + return loomapi.CompileResponse{}, value, status, e +} + +func (r *HTTPRoutes) CompileExplorerBuilder(ctx context.Context, _ loomapi.CompileExplorerBuilderRequestObject) (loomapi.CompileExplorerBuilderResponseObject, error) { + value, failure, status, err := r.compileExplorer(ctx, r.explorer.authoring.compileBuilder) + if err != nil { + return nil, err + } + if status == http.StatusOK { + return loomapi.CompileExplorerBuilder200JSONResponse(value), nil + } + switch status { + case 400: + return loomapi.CompileExplorerBuilder400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(failure)}, nil + case 403: + return loomapi.CompileExplorerBuilder403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(failure)}, nil + case 409: + return loomapi.CompileExplorerBuilder409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(failure)}, nil + case 422: + return loomapi.CompileExplorerBuilder422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(failure)}, nil + case 500: + return loomapi.CompileExplorerBuilder500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(failure)}, nil + case 503: + return loomapi.CompileExplorerBuilder503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(failure)}, nil + default: + return nil, unexpectedResponseStatus("compileExplorerBuilder", status) + } +} + +func (r *HTTPRoutes) CompileExplorer(ctx context.Context, _ loomapi.CompileExplorerRequestObject) (loomapi.CompileExplorerResponseObject, error) { + value, failure, status, err := r.compileExplorer(ctx, r.explorer.authoring.compile) + if err != nil { + return nil, err + } + if status == http.StatusOK { + return loomapi.CompileExplorer200JSONResponse(value), nil + } + switch status { + case 400: + return loomapi.CompileExplorer400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(failure)}, nil + case 403: + return loomapi.CompileExplorer403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(failure)}, nil + case 409: + return loomapi.CompileExplorer409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(failure)}, nil + case 422: + return loomapi.CompileExplorer422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(failure)}, nil + case 500: + return loomapi.CompileExplorer500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(failure)}, nil + case 503: + return loomapi.CompileExplorer503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(failure)}, nil + default: + return nil, unexpectedResponseStatus("compileExplorer", status) + } +} + +func (r *HTTPRoutes) ReconcileExplorerBuilder(ctx context.Context, _ loomapi.ReconcileExplorerBuilderRequestObject) (loomapi.ReconcileExplorerBuilderResponseObject, error) { + value, failure, status, err := r.compileExplorer(ctx, r.explorer.authoring.reconcile) + if err != nil { + return nil, err + } + if status == http.StatusOK { + return loomapi.ReconcileExplorerBuilder200JSONResponse(value), nil + } + switch status { + case 400: + return loomapi.ReconcileExplorerBuilder400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(failure)}, nil + case 403: + return loomapi.ReconcileExplorerBuilder403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(failure)}, nil + case 404: + return loomapi.ReconcileExplorerBuilder404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(failure)}, nil + case 409: + return loomapi.ReconcileExplorerBuilder409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(failure)}, nil + case 422: + return loomapi.ReconcileExplorerBuilder422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(failure)}, nil + case 500: + return loomapi.ReconcileExplorerBuilder500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(failure)}, nil + case 503: + return loomapi.ReconcileExplorerBuilder503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(failure)}, nil + default: + return nil, unexpectedResponseStatus("reconcileExplorerBuilder", status) + } +} + +func (r *HTTPRoutes) PreviewExplorer(ctx context.Context, _ loomapi.PreviewExplorerRequestObject) (loomapi.PreviewExplorerResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.authoring.preview) + if err != nil { + return nil, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.PreviewResponse](body) + return loomapi.PreviewExplorer200JSONResponse(value), e + } + value, _, e := authoringError(body, status) + if e != nil { + return nil, e + } + switch status { + case 400: + return loomapi.PreviewExplorer400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(value)}, nil + case 403: + return loomapi.PreviewExplorer403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.PreviewExplorer404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.PreviewExplorer409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil + case 413: + return loomapi.PreviewExplorer413JSONResponse{AuthoringPayloadTooLargeJSONResponse: loomapi.AuthoringPayloadTooLargeJSONResponse(value)}, nil + case 422: + return loomapi.PreviewExplorer422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(value)}, nil + case 429: + return loomapi.PreviewExplorer429JSONResponse{AuthoringTooManyRequestsJSONResponse: loomapi.AuthoringTooManyRequestsJSONResponse(value)}, nil + case 499: + return loomapi.PreviewExplorer499JSONResponse{AuthoringClientClosedRequestJSONResponse: loomapi.AuthoringClientClosedRequestJSONResponse(value)}, nil + case 500: + return loomapi.PreviewExplorer500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.PreviewExplorer503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil + case 504: + return loomapi.PreviewExplorer504JSONResponse{AuthoringGatewayTimeoutJSONResponse: loomapi.AuthoringGatewayTimeoutJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("previewExplorer", status) + } +} + +func (r *HTTPRoutes) PublishExplorer(ctx context.Context, _ loomapi.PublishExplorerRequestObject) (loomapi.PublishExplorerResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.authoring.publish) + if err != nil { + return nil, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.PublishResponse](body) + return loomapi.PublishExplorer200JSONResponse(value), e + } + value, _, e := authoringError(body, status) + if e != nil { + return nil, e + } + switch status { + case 400: + return loomapi.PublishExplorer400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(value)}, nil + case 403: + return loomapi.PublishExplorer403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.PublishExplorer404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.PublishExplorer409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil + case 422: + return loomapi.PublishExplorer422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.PublishExplorer500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.PublishExplorer503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("publishExplorer", status) + } +} diff --git a/internal/server/routes.go b/internal/server/routes.go index c38b8b3c..492d31a1 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -3,6 +3,7 @@ package server import ( "fmt" + loomapi "github.com/calypr/loom/generated/loomapi" loadapi "github.com/calypr/loom/internal/api/bulk/load" graphapi "github.com/calypr/loom/internal/api/graphql/graph" "github.com/calypr/loom/internal/api/graphql/graph/resolver" @@ -12,12 +13,11 @@ import ( "github.com/calypr/loom/internal/dataset" ) -func registerRoutes(server *api.HTTPServer, resourceService *loadapi.Service, snapshotService *loadapi.SnapshotService, releaseService *dataset.ReleaseService, authorizer authscope.Authorizer, graphResolver *resolver.Resolver, optional ...any) error { +func registerRoutes(server *api.HTTPServer, resourceService *loadapi.Service, snapshotService *loadapi.SnapshotService, releaseService *dataset.ReleaseService, authorizer authscope.Authorizer, graphResolver *resolver.Resolver, explorerHandlers *explorerHTTPHandlers, optional ...any) error { resourceHandler, err := loadapi.NewHandler(loadapi.Config{Service: resourceService, Authorizer: authorizer, Snapshots: snapshotService, Releases: releaseService}) if err != nil { return fmt.Errorf("create resource load handler: %w", err) } - resourceHandler.RegisterRoutes(server.App()) var releases publication.BundleCatalog var scopes *authscope.ScopeResolver for _, value := range optional { @@ -28,7 +28,14 @@ func registerRoutes(server *api.HTTPServer, resourceService *loadapi.Service, sn scopes = typed } } - api.RegisterRecipeExecutionRoute(server.App(), releases, scopes) - graphapi.RegisterRoutes(server.App(), graphapi.RouteConfig{Handler: graphapi.NewHandler(graphResolver, server.Logger()), Playground: graphapi.NewPlaygroundHandler("/graphql/graph"), Sandbox: graphapi.NewApolloSandboxHandler("/graphql/graph")}) + routes := &HTTPRoutes{ + server: server, + load: resourceHandler, + recipe: api.RecipeExecutionHandler{Catalog: releases, Scopes: scopes}, + graphql: graphapi.RouteConfig{Handler: graphapi.NewHandler(graphResolver, server.Logger()), Playground: graphapi.NewPlaygroundHandler("/graphql/graph"), Sandbox: graphapi.NewApolloSandboxHandler("/graphql/graph")}, + explorer: explorerHandlers, + } + handler := loomapi.NewStrictHandler(routes, []loomapi.StrictMiddlewareFunc{strictFiberContextMiddleware}) + loomapi.RegisterHandlersWithOptions(server.App(), handler, loomapi.FiberServerOptions{}) return nil } diff --git a/internal/server/routes_test.go b/internal/server/routes_test.go index 4c2fb6f7..667b654d 100644 --- a/internal/server/routes_test.go +++ b/internal/server/routes_test.go @@ -2,6 +2,7 @@ package server import ( "context" + "io" "net/http" "net/http/httptest" "testing" @@ -31,10 +32,23 @@ func TestRegisterRoutesExposesGenerationReleaseWorkflow(t *testing.T) { if err != nil { t.Fatal(err) } - if err := registerRoutes(server, resourceService, nil, nil, authscope.AllowAllAuthorizer{}, &resolver.Resolver{}); err != nil { + if err := registerRoutes(server, resourceService, nil, nil, authscope.AllowAllAuthorizer{}, &resolver.Resolver{}, &explorerHTTPHandlers{lifecycle: &explorerLifecycleHandlers{}, authoring: &explorerAuthoringHandlers{}}); err != nil { t.Fatal(err) } + health, err := server.App().Test(httptest.NewRequest(http.MethodGet, "/livez", nil)) + if err != nil { + t.Fatal(err) + } + healthBody, err := io.ReadAll(health.Body) + _ = health.Body.Close() + if err != nil { + t.Fatal(err) + } + if health.StatusCode != http.StatusOK || string(healthBody) != `{"status":"live"}` { + t.Fatalf("generated liveness response status=%d body=%s", health.StatusCode, healthBody) + } + for _, request := range []struct { method string path string diff --git a/internal/server/server.go b/internal/server/server.go index 3263f4d9..6b8c1da5 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -502,15 +502,15 @@ func run(ctx context.Context, serverConfig Config) error { if err != nil { return fmt.Errorf("create HTTP server: %w", err) } - if err := registerRoutes(server, resourceService, snapshotService, releaseService, authorizer, resolver, publishedRegistry, scopeResolver); err != nil { - return fmt.Errorf("register HTTP routes: %w", err) - } - RegisterExplorerConfigV2Route(server.App(), authorizer, func(ctx context.Context, principal *authscope.Principal, project string) error { + explorerHandlers := newExplorerHTTPHandlers(authorizer, func(ctx context.Context, principal *authscope.Principal, project string) error { if scopeResolver == nil { return nil } return scopeResolver.AuthorizeReadProject(ctx, principal, project) }, explorerService, explorerMaterializer, lifecycleConfig) + if err := registerRoutes(server, resourceService, snapshotService, releaseService, authorizer, resolver, explorerHandlers, publishedRegistry, scopeResolver); err != nil { + return fmt.Errorf("register HTTP routes: %w", err) + } if publicationWorker != nil { go func() { err := publicationWorker.Run(ctx, time.Second, func(workerErr error) { diff --git a/openapi/README.md b/openapi/README.md new file mode 100644 index 00000000..db1598d2 --- /dev/null +++ b/openapi/README.md @@ -0,0 +1,40 @@ +# Loom OpenAPI contract + +[`openapi.yaml`](openapi.yaml) is the canonical contract for every Loom HTTP +route. It currently defines all 39 REST, health, GraphQL transport, and browser +UI operations registered by the server. + +The files in this directory are source files: + +- `openapi.yaml` — methods, paths, parameters, request bodies, responses, and + wire models; +- `oapi-codegen.yaml` — generation settings for models, the Fiber v3 server, + the strict server interface, and the embedded specification. + +Regenerate the checked-in Go package after either file changes: + +```bash +make generate-openapi +``` + +Generated output belongs in `generated/loomapi/`. Handwritten operation +implementations belong in `internal/server/openapi_routes.go`; production route +registration belongs only in the generated registrar invoked by +`internal/server/routes.go`. + +Every operation declares its expected HTTP statuses explicitly. Error +responses include a human-readable explanation, media type, and schema; the +strict implementation returns the corresponding generated response union +member. Do not replace these with `default` responses: an undocumented status +is a contract bug and should fail loudly until the route and specification are +reconciled. + +Validation and ownership checks: + +```bash +make openapi-check +go test ./internal/server -run TestGeneratedRoutesExactlyMatchOpenAPISpec +``` + +Do not hand-edit `generated/loomapi/api.gen.go` or register a production Fiber +route directly. diff --git a/openapi/oapi-codegen.yaml b/openapi/oapi-codegen.yaml new file mode 100644 index 00000000..7cc590d4 --- /dev/null +++ b/openapi/oapi-codegen.yaml @@ -0,0 +1,10 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/v2.8.0/configuration-schema.json +package: loomapi +generate: + models: true + fiber-v3-server: true + strict-server: true + embedded-spec: true +output: generated/loomapi/api.gen.go +output-options: + skip-prune: false diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml new file mode 100644 index 00000000..567c8e69 --- /dev/null +++ b/openapi/openapi.yaml @@ -0,0 +1,1645 @@ +openapi: 3.0.3 +info: + title: Loom HTTP API + version: 1.0.0 +servers: + - url: / +paths: + /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/capability: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/ExplorerId' + get: + operationId: getExplorerAuthoringCapability + responses: + '200': + description: Supported authoring operations and UI features. + content: + application/json: + schema: + $ref: '#/components/schemas/AuthoringCapability' + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/AuthoringForbidden'} + '500': {$ref: '#/components/responses/AuthoringInternalError'} + /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/capabilities/{snapshotToken}/candidates/{candidateId}/suggestions: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/ExplorerId' + - name: snapshotToken + in: path + required: true + schema: {type: string, minLength: 1} + - name: candidateId + in: path + required: true + schema: {type: string, minLength: 1} + get: + operationId: getExplorerCandidateSuggestions + responses: + '200': + description: Bounded values for one candidate in an immutable snapshot. + content: + application/json: + schema: + $ref: '#/components/schemas/CandidateSuggestions' + '400': {$ref: '#/components/responses/AuthoringBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/AuthoringForbidden'} + '404': {$ref: '#/components/responses/AuthoringNotFound'} + '409': {$ref: '#/components/responses/AuthoringConflict'} + '500': {$ref: '#/components/responses/AuthoringInternalError'} + '503': {$ref: '#/components/responses/AuthoringUnavailable'} + /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/suggestions: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/ExplorerId' + post: + operationId: searchExplorerCandidates + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CandidateSearchRequest' + responses: + '200': + description: Candidate definitions matching a node and query. + content: + application/json: + schema: + $ref: '#/components/schemas/CandidateSearchResponse' + '400': {$ref: '#/components/responses/AuthoringBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/AuthoringForbidden'} + '409': {$ref: '#/components/responses/AuthoringConflict'} + '500': {$ref: '#/components/responses/AuthoringInternalError'} + '503': {$ref: '#/components/responses/AuthoringUnavailable'} + /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/builder: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/ExplorerId' + get: + operationId: getExplorerBuilder + responses: + '200': + description: Current workspace and its immutable catalog snapshot. + content: + application/json: + schema: + $ref: '#/components/schemas/BuilderState' + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/AuthoringForbidden'} + '404': {$ref: '#/components/responses/AuthoringNotFound'} + '409': {$ref: '#/components/responses/AuthoringConflict'} + '500': {$ref: '#/components/responses/AuthoringInternalError'} + '503': {$ref: '#/components/responses/AuthoringUnavailable'} + post: + operationId: compileExplorerBuilder + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CompileRequest' + responses: + '200': + description: Immutable compilation receipt. + content: + application/json: + schema: + $ref: '#/components/schemas/CompileResponse' + '400': {$ref: '#/components/responses/AuthoringBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/AuthoringForbidden'} + '409': {$ref: '#/components/responses/AuthoringConflict'} + '422': {$ref: '#/components/responses/AuthoringUnprocessable'} + '500': {$ref: '#/components/responses/AuthoringInternalError'} + '503': {$ref: '#/components/responses/AuthoringUnavailable'} + /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/compile: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/ExplorerId' + post: + operationId: compileExplorer + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CompileRequest' + responses: + '200': + description: Immutable compilation receipt. + content: + application/json: + schema: + $ref: '#/components/schemas/CompileResponse' + '400': {$ref: '#/components/responses/AuthoringBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/AuthoringForbidden'} + '409': {$ref: '#/components/responses/AuthoringConflict'} + '422': {$ref: '#/components/responses/AuthoringUnprocessable'} + '500': {$ref: '#/components/responses/AuthoringInternalError'} + '503': {$ref: '#/components/responses/AuthoringUnavailable'} + /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/commands: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/ExplorerId' + post: + operationId: applyExplorerBuilderCommands + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ApplyCommandsRequest' + responses: + '200': + description: Canonical backend-authored workspace after an atomic command batch. + content: + application/json: + schema: + $ref: '#/components/schemas/ApplyCommandsResponse' + '400': {$ref: '#/components/responses/AuthoringBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/AuthoringForbidden'} + '409': {$ref: '#/components/responses/AuthoringConflict'} + '422': {$ref: '#/components/responses/AuthoringUnprocessable'} + '500': {$ref: '#/components/responses/AuthoringInternalError'} + '503': {$ref: '#/components/responses/AuthoringUnavailable'} + /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/reconcile: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/ExplorerId' + post: + operationId: reconcileExplorerBuilder + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ReconcileRequest' + responses: + '200': + description: Immutable receipt compiled from the exact persisted draft. + content: + application/json: + schema: + $ref: '#/components/schemas/CompileResponse' + '400': {$ref: '#/components/responses/AuthoringBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/AuthoringForbidden'} + '404': {$ref: '#/components/responses/AuthoringNotFound'} + '409': {$ref: '#/components/responses/AuthoringConflict'} + '422': {$ref: '#/components/responses/AuthoringUnprocessable'} + '500': {$ref: '#/components/responses/AuthoringInternalError'} + '503': {$ref: '#/components/responses/AuthoringUnavailable'} + /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/draft: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/ExplorerId' + put: + operationId: saveExplorerDraft + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SaveDraftRequest' + responses: + '200': + description: Canonical server-owned V2 workspace draft. + content: + application/json: + schema: + $ref: '#/components/schemas/SaveDraftResponse' + '400': {$ref: '#/components/responses/AuthoringBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/AuthoringForbidden'} + '404': {$ref: '#/components/responses/AuthoringNotFound'} + '409': {$ref: '#/components/responses/AuthoringConflict'} + '422': {$ref: '#/components/responses/AuthoringUnprocessable'} + '500': {$ref: '#/components/responses/AuthoringInternalError'} + '503': {$ref: '#/components/responses/AuthoringUnavailable'} + /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/export: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/ExplorerId' + get: + operationId: exportExplorerWorkspace + responses: + '200': + description: Canonical portable V2 workspace. + content: + application/json: + schema: + $ref: '#/components/schemas/Workspace' + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/AuthoringForbidden'} + '404': {$ref: '#/components/responses/AuthoringNotFound'} + '409': {$ref: '#/components/responses/AuthoringConflict'} + '500': {$ref: '#/components/responses/AuthoringInternalError'} + /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/preview: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/ExplorerId' + post: + operationId: previewExplorer + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PreviewRequest' + responses: + '200': + description: Bounded preview of one receipt output. + content: + application/json: + schema: + $ref: '#/components/schemas/PreviewResponse' + '400': {$ref: '#/components/responses/AuthoringBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/AuthoringForbidden'} + '404': {$ref: '#/components/responses/AuthoringNotFound'} + '409': {$ref: '#/components/responses/AuthoringConflict'} + '413': {$ref: '#/components/responses/AuthoringPayloadTooLarge'} + '422': {$ref: '#/components/responses/AuthoringUnprocessable'} + '429': {$ref: '#/components/responses/AuthoringTooManyRequests'} + '499': {$ref: '#/components/responses/AuthoringClientClosedRequest'} + '500': {$ref: '#/components/responses/AuthoringInternalError'} + '503': {$ref: '#/components/responses/AuthoringUnavailable'} + '504': {$ref: '#/components/responses/AuthoringGatewayTimeout'} + /api/v1/projects/{project}/explorers/{explorerId}/authoring/v2/publish: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/ExplorerId' + post: + operationId: publishExplorer + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PublishRequest' + responses: + '200': + description: Activated Explorer revision. + content: + application/json: + schema: + $ref: '#/components/schemas/PublishResponse' + '400': {$ref: '#/components/responses/AuthoringBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/AuthoringForbidden'} + '404': {$ref: '#/components/responses/AuthoringNotFound'} + '409': {$ref: '#/components/responses/AuthoringConflict'} + '422': {$ref: '#/components/responses/AuthoringUnprocessable'} + '500': {$ref: '#/components/responses/AuthoringInternalError'} + '503': {$ref: '#/components/responses/AuthoringUnavailable'} + /health: + get: + operationId: getHealth + summary: Report cached core and dataframe health. + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '503': + description: A required health dependency is not ready. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + /livez: + get: + operationId: getLiveness + summary: Report process liveness without checking dependencies. + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + /readyz: + get: + operationId: getReadiness + summary: Report whether required dependencies are ready. + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '503': + description: Dependencies are not ready. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + /api/v1/projects/{project}/resources/{resourceType}: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/ResourceType' + put: + operationId: uploadProjectResource + summary: Upload one multipart NDJSON resource file. + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + required: [file] + properties: + file: {type: string, format: binary} + auth_resource_path: {type: string} + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '400': {$ref: '#/components/responses/ServiceBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/ServiceForbidden'} + '415': {$ref: '#/components/responses/ServiceUnsupportedMediaType'} + '422': {$ref: '#/components/responses/ServiceUnprocessable'} + '500': {$ref: '#/components/responses/ServiceInternalError'} + '503': {$ref: '#/components/responses/ServiceUnavailable'} + /api/v1/datasets/{project}/generations/{generation}: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/Generation' + post: + operationId: createDatasetGeneration + summary: Upload a multipart dataset generation. + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + required: [file, project, generation] + properties: + file: + type: array + items: {type: string, format: binary} + project: {type: string} + generation: {type: string} + auth_resource_path: {type: string} + defer_activation: {type: boolean} + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '400': {$ref: '#/components/responses/ServiceBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/ServiceForbidden'} + '409': {$ref: '#/components/responses/ServiceConflict'} + '415': {$ref: '#/components/responses/ServiceUnsupportedMediaType'} + '422': {$ref: '#/components/responses/ServiceUnprocessable'} + '500': {$ref: '#/components/responses/ServiceInternalError'} + '503': {$ref: '#/components/responses/ServiceUnavailable'} + /api/v1/datasets/{project}/generations/{generation}/activate: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/Generation' + - name: dataframe_execution_id + in: query + required: true + schema: {type: string} + - name: auth_resource_path + in: query + schema: {type: string} + post: + operationId: activateDatasetGeneration + summary: Activate a generation after dataframe publication. + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '400': {$ref: '#/components/responses/ServiceBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/ServiceForbidden'} + '409': {$ref: '#/components/responses/ServiceConflict'} + '500': {$ref: '#/components/responses/ServiceInternalError'} + '503': {$ref: '#/components/responses/ServiceUnavailable'} + /api/v1/raw: + put: + operationId: uploadRawNDJSON + summary: Stream raw NDJSON into a generation. + parameters: + - name: project + in: query + schema: {type: string} + - name: generation + in: query + schema: {type: string} + - name: auth_resource_path + in: query + schema: {type: string} + requestBody: + required: true + content: + application/x-ndjson: + schema: {type: string, format: binary} + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '400': {$ref: '#/components/responses/ServiceBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/ServiceForbidden'} + '415': {$ref: '#/components/responses/ServiceUnsupportedMediaType'} + '422': {$ref: '#/components/responses/ServiceUnprocessable'} + '500': {$ref: '#/components/responses/ServiceInternalError'} + '503': {$ref: '#/components/responses/ServiceUnavailable'} + /api/v1/projects/{project}/generations/{generation}: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/Generation' + post: + operationId: createSnapshot + summary: Create or resume an immutable generation snapshot. + requestBody: + required: true + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '400': {$ref: '#/components/responses/ServiceBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/ServiceForbidden'} + '409': {$ref: '#/components/responses/ServiceConflict'} + '500': {$ref: '#/components/responses/ServiceInternalError'} + '503': {$ref: '#/components/responses/ServiceUnavailable'} + get: + operationId: getSnapshot + summary: Read generation snapshot status. + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/ServiceForbidden'} + '404': {$ref: '#/components/responses/ServiceNotFound'} + '500': {$ref: '#/components/responses/ServiceInternalError'} + '503': {$ref: '#/components/responses/ServiceUnavailable'} + delete: + operationId: abortSnapshot + summary: Abort a generation snapshot. + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/ServiceForbidden'} + '404': {$ref: '#/components/responses/ServiceNotFound'} + '409': {$ref: '#/components/responses/ServiceConflict'} + '500': {$ref: '#/components/responses/ServiceInternalError'} + '503': {$ref: '#/components/responses/ServiceUnavailable'} + /api/v1/projects/{project}/generations/{generation}/resources/{resourceType}: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/Generation' + - $ref: '#/components/parameters/ResourceType' + put: + operationId: uploadSnapshotResource + summary: Stream one resource type into an immutable snapshot. + parameters: + - name: X-Content-SHA256 + in: header + schema: {type: string} + requestBody: + required: true + content: + application/octet-stream: + schema: {type: string, format: binary} + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '400': {$ref: '#/components/responses/ServiceBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/ServiceForbidden'} + '404': {$ref: '#/components/responses/ServiceNotFound'} + '409': {$ref: '#/components/responses/ServiceConflict'} + '422': {$ref: '#/components/responses/ServiceUnprocessable'} + '500': {$ref: '#/components/responses/ServiceInternalError'} + '503': {$ref: '#/components/responses/ServiceUnavailable'} + /api/v1/projects/{project}/generations/{generation}/finalize: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/Generation' + post: + operationId: finalizeSnapshot + summary: Validate and finalize an immutable generation snapshot. + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '400': {$ref: '#/components/responses/ServiceBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/ServiceForbidden'} + '404': {$ref: '#/components/responses/ServiceNotFound'} + '409': {$ref: '#/components/responses/ServiceConflict'} + '422': {$ref: '#/components/responses/ServiceUnprocessable'} + '500': {$ref: '#/components/responses/ServiceInternalError'} + '503': {$ref: '#/components/responses/ServiceUnavailable'} + /api/v1/projects/{project}/releases: + parameters: + - $ref: '#/components/parameters/Project' + post: + operationId: createRelease + summary: Create a durable project release candidate. + requestBody: + required: true + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '400': {$ref: '#/components/responses/ServiceBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/ServiceForbidden'} + '404': {$ref: '#/components/responses/ServiceNotFound'} + '409': {$ref: '#/components/responses/ServiceConflict'} + '422': {$ref: '#/components/responses/ServiceUnprocessable'} + '500': {$ref: '#/components/responses/ServiceInternalError'} + '503': {$ref: '#/components/responses/ServiceUnavailable'} + /api/v1/projects/{project}/releases/active: + parameters: + - $ref: '#/components/parameters/Project' + get: + operationId: getActiveRelease + summary: Read the active project release. + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/ServiceForbidden'} + '404': {$ref: '#/components/responses/ServiceNotFound'} + '500': {$ref: '#/components/responses/ServiceInternalError'} + '503': {$ref: '#/components/responses/ServiceUnavailable'} + /api/v1/projects/{project}/releases/{release}: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/Release' + get: + operationId: getRelease + summary: Read a project release by ID. + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/ServiceForbidden'} + '404': {$ref: '#/components/responses/ServiceNotFound'} + '500': {$ref: '#/components/responses/ServiceInternalError'} + '503': {$ref: '#/components/responses/ServiceUnavailable'} + /api/v1/projects/{project}/releases/{release}/activate: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/Release' + post: + operationId: activateRelease + summary: Activate an existing durable release. + requestBody: + required: true + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '400': {$ref: '#/components/responses/ServiceBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/ServiceForbidden'} + '404': {$ref: '#/components/responses/ServiceNotFound'} + '409': {$ref: '#/components/responses/ServiceConflict'} + '422': {$ref: '#/components/responses/ServiceUnprocessable'} + '500': {$ref: '#/components/responses/ServiceInternalError'} + '503': {$ref: '#/components/responses/ServiceUnavailable'} + /api/v1/projects/{project}/releases/activate: + parameters: + - $ref: '#/components/parameters/Project' + post: + operationId: activateReleaseCompatibility + summary: Create and activate a release in one legacy operation. + deprecated: true + requestBody: + required: true + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '400': {$ref: '#/components/responses/ServiceBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/ServiceForbidden'} + '404': {$ref: '#/components/responses/ServiceNotFound'} + '409': {$ref: '#/components/responses/ServiceConflict'} + '422': {$ref: '#/components/responses/ServiceUnprocessable'} + '500': {$ref: '#/components/responses/ServiceInternalError'} + '503': {$ref: '#/components/responses/ServiceUnavailable'} + /api/v1/dataframe/recipe-executions/{id}: + parameters: + - name: id + in: path + required: true + schema: {type: string} + get: + operationId: getRecipeExecution + summary: Read public metadata for a dataframe recipe execution. + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '401': + description: Authentication is missing, invalid, or cannot be resolved for the execution's dataset scope. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '403': {$ref: '#/components/responses/LegacyForbidden'} + '404': {$ref: '#/components/responses/LegacyNotFound'} + /graphql/graph: + get: + operationId: getGraphQLPlayground + summary: Render the GraphQL playground. + responses: + '200': {$ref: '#/components/responses/HTML'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '404': {$ref: '#/components/responses/ServiceNotFound'} + post: + operationId: executeGraphQL + summary: Execute a graph or FHIR GraphQL operation. + requestBody: + required: true + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '400': {$ref: '#/components/responses/GraphQLBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '422': {$ref: '#/components/responses/GraphQLUnprocessable'} + '500': {$ref: '#/components/responses/GraphQLInternalError'} + /graphql/dataframe: + post: + operationId: executeDataframeGraphQL + summary: Execute a dataframe GraphQL operation. + requestBody: + required: true + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '400': {$ref: '#/components/responses/GraphQLBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '422': {$ref: '#/components/responses/GraphQLUnprocessable'} + '500': {$ref: '#/components/responses/GraphQLInternalError'} + /apollo: + get: + operationId: getApolloSandbox + summary: Render the Apollo GraphQL sandbox. + responses: + '200': {$ref: '#/components/responses/HTML'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '404': {$ref: '#/components/responses/ServiceNotFound'} + /api/v1/projects/{project}/explorers: + parameters: + - $ref: '#/components/parameters/Project' + get: + operationId: listExplorers + summary: List Explorer summaries for a project. + responses: + '200': + description: Successful response. + content: + application/json: + schema: + type: array + items: + type: object + additionalProperties: true + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/LegacyForbidden'} + '500': {$ref: '#/components/responses/LegacyInternalError'} + post: + operationId: createExplorer + summary: Create an interactive Explorer. + requestBody: + required: true + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + responses: + '201': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '400': {$ref: '#/components/responses/LegacyBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/LegacyForbidden'} + '409': {$ref: '#/components/responses/LegacyConflict'} + '422': {$ref: '#/components/responses/LegacyUnprocessable'} + '500': {$ref: '#/components/responses/LegacyInternalError'} + /api/v1/projects/{project}/explorers/{explorerId}: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/ExplorerId' + get: + operationId: getExplorer + summary: Read an Explorer's active runtime projection. + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/LegacyForbidden'} + '404': {$ref: '#/components/responses/LegacyNotFound'} + '500': {$ref: '#/components/responses/LegacyInternalError'} + /api/v1/projects/{project}/generations/{generation}/explorer-config: + parameters: + - $ref: '#/components/parameters/Project' + - $ref: '#/components/parameters/Generation' + post: + operationId: publishRepositoryExplorerConfig + summary: Compile and publish a repository-owned Explorer workspace. + parameters: + - name: auth_resource_path + in: query + schema: {type: string} + - name: X-Loom-Source-Commit + in: header + required: true + schema: {type: string} + requestBody: + required: true + content: + application/json: + schema: {$ref: '#/components/schemas/Workspace'} + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '400': {$ref: '#/components/responses/LegacyBadRequest'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/LegacyForbidden'} + '409': {$ref: '#/components/responses/LegacyConflict'} + '422': {$ref: '#/components/responses/LegacyUnprocessable'} + '500': {$ref: '#/components/responses/LegacyInternalError'} + '503': {$ref: '#/components/responses/LegacyUnavailable'} + /api/v1/projects/{project}/explorer-config: + parameters: + - $ref: '#/components/parameters/Project' + get: + operationId: getRepositoryExplorerConfig + summary: Read the active repository-owned Explorer config. + responses: + '200': + description: Successful response. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + '401': {$ref: '#/components/responses/ServiceUnauthorized'} + '403': {$ref: '#/components/responses/LegacyForbidden'} + '404': {$ref: '#/components/responses/LegacyNotFound'} + '500': {$ref: '#/components/responses/LegacyInternalError'} +components: + parameters: + Project: + name: project + in: path + required: true + schema: {type: string, minLength: 1} + ExplorerId: + name: explorerId + in: path + required: true + schema: {type: string, minLength: 1} + Generation: + name: generation + in: path + required: true + schema: {type: string, minLength: 1} + ResourceType: + name: resourceType + in: path + required: true + schema: {type: string, minLength: 1} + Release: + name: release + in: path + required: true + schema: {type: string, minLength: 1} + responses: + AuthoringBadRequest: + description: The JSON document is malformed, contains unknown fields, or omits required authoring input. + content: + application/json: + schema: {$ref: '#/components/schemas/ErrorResponse'} + AuthoringForbidden: + description: The authenticated principal cannot read or modify this Explorer project. + content: + application/json: + schema: {$ref: '#/components/schemas/ErrorResponse'} + AuthoringNotFound: + description: The Explorer, candidate, compilation receipt, or other operation-specific authoring resource does not exist. + content: + application/json: + schema: {$ref: '#/components/schemas/ErrorResponse'} + AuthoringConflict: + description: Immutable capability or receipt state is stale, or optimistic draft/publication state changed. + content: + application/json: + schema: {$ref: '#/components/schemas/ErrorResponse'} + AuthoringPayloadTooLarge: + description: The bounded preview result exceeds the maximum response size. + content: + application/json: + schema: {$ref: '#/components/schemas/ErrorResponse'} + AuthoringUnprocessable: + description: The request is valid JSON but its workspace, command, output, or compilation intent is semantically invalid. + content: + application/json: + schema: {$ref: '#/components/schemas/ErrorResponse'} + AuthoringTooManyRequests: + description: The requested preview plan exceeds the server's execution-cost policy. + content: + application/json: + schema: {$ref: '#/components/schemas/ErrorResponse'} + AuthoringClientClosedRequest: + description: The client canceled preview execution before completion. + content: + application/json: + schema: {$ref: '#/components/schemas/ErrorResponse'} + AuthoringInternalError: + description: An unexpected authoring, persistence, or preview failure occurred. + content: + application/json: + schema: {$ref: '#/components/schemas/ErrorResponse'} + AuthoringUnavailable: + description: A required capability, receipt store, materializer, activation service, or backend is unavailable. + content: + application/json: + schema: {$ref: '#/components/schemas/ErrorResponse'} + AuthoringGatewayTimeout: + description: Preview execution exceeded its server-side deadline. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + ServiceBadRequest: + description: A required path, query, multipart, JSON, or NDJSON value is missing or invalid. + content: + application/json: + schema: {$ref: '#/components/schemas/ServiceErrorResponse'} + ServiceUnauthorized: + description: Authentication credentials are absent or invalid. + content: + application/json: + schema: {$ref: '#/components/schemas/ServiceErrorResponse'} + ServiceForbidden: + description: The authenticated principal lacks access to the requested project or resource scope. + content: + application/json: + schema: {$ref: '#/components/schemas/ServiceErrorResponse'} + ServiceNotFound: + description: The requested dataset, generation, release, recipe execution, or route resource was not found. + content: + application/json: + schema: {$ref: '#/components/schemas/ServiceErrorResponse'} + ServiceConflict: + description: Immutable content, activation state, cursor state, or publication state conflicts with the request. + content: + application/json: + schema: {$ref: '#/components/schemas/ServiceErrorResponse'} + ServicePayloadTooLarge: + description: The request or generated response exceeds the configured size limit. + content: + application/json: + schema: {$ref: '#/components/schemas/ServiceErrorResponse'} + ServiceUnprocessable: + description: The request is syntactically valid but its data, generation, or release requirements cannot be processed. + content: + application/json: + schema: {$ref: '#/components/schemas/ServiceErrorResponse'} + ServiceUnsupportedMediaType: + description: Content-Type is not supported by this upload operation. + content: + application/json: + schema: {$ref: '#/components/schemas/ServiceErrorResponse'} + ServiceInternalError: + description: An unexpected server error occurred; details are redacted and correlated by requestId. + content: + application/json: + schema: {$ref: '#/components/schemas/ServiceErrorResponse'} + ServiceUnavailable: + description: A required authorization, storage, ingestion, publication, or query backend is unavailable. + content: + application/json: + schema: {$ref: '#/components/schemas/ServiceErrorResponse'} + GraphQLBadRequest: + description: The GraphQL HTTP request envelope or transport parameters are malformed. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + GraphQLUnprocessable: + description: The GraphQL document could not be parsed or validated for execution. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + GraphQLInternalError: + description: GraphQL execution failed before a normal GraphQL response could be produced. + content: + application/json: + schema: {$ref: '#/components/schemas/RawJSON'} + LegacyBadRequest: + description: The legacy Explorer request is malformed or missing required input. + content: + application/json: + schema: {$ref: '#/components/schemas/LegacyErrorResponse'} + LegacyUnauthorized: + description: Authentication credentials are absent or invalid. + content: + application/json: + schema: {$ref: '#/components/schemas/ServiceErrorResponse'} + LegacyForbidden: + description: The authenticated principal cannot access this Explorer project. + content: + application/json: + schema: {$ref: '#/components/schemas/LegacyErrorResponse'} + LegacyNotFound: + description: The Explorer or repository-owned Explorer configuration was not found. + content: + application/json: + schema: {$ref: '#/components/schemas/LegacyErrorResponse'} + LegacyConflict: + description: The Explorer already exists or repository deployment state changed or is inconsistent. + content: + application/json: + schema: {$ref: '#/components/schemas/LegacyErrorResponse'} + LegacyUnprocessable: + description: The Explorer workspace or deployment is syntactically valid but cannot be compiled, materialized, or published. + content: + application/json: + schema: {$ref: '#/components/schemas/LegacyErrorResponse'} + LegacyInternalError: + description: Reading or persisting the Explorer failed unexpectedly. + content: + application/json: + schema: {$ref: '#/components/schemas/LegacyErrorResponse'} + LegacyUnavailable: + description: Repository compilation, materialization, or release activation is not configured or unavailable. + content: + application/json: + schema: {$ref: '#/components/schemas/LegacyErrorResponse'} + HTML: + description: Existing browser UI document. + content: + text/html: + schema: {type: string} + schemas: + RawJSON: + description: JSON whose existing shape is preserved losslessly during route cutover. + type: object + additionalProperties: true + ServiceErrorResponse: + description: Stable error envelope emitted by Loom's shared HTTP error mapper and snapshot routes. + type: object + additionalProperties: false + required: [error] + properties: + error: + $ref: '#/components/schemas/ServiceErrorBody' + ServiceErrorBody: + type: object + additionalProperties: false + required: [code, message] + properties: + code: {type: string} + message: {type: string} + details: + type: object + nullable: true + additionalProperties: true + retryable: {type: boolean} + requestId: {type: string} + LegacyErrorResponse: + description: Error envelope retained by legacy Explorer and recipe-execution routes. + type: object + additionalProperties: true + required: [error] + properties: + error: + description: Either a legacy message string or a structured code/message object, depending on the route. + oneOf: + - {type: string} + - $ref: '#/components/schemas/LegacyErrorBody' + LegacyErrorBody: + type: object + additionalProperties: true + required: [code, message] + properties: + code: {type: string} + message: {type: string} + AuthoringCapability: + type: object + additionalProperties: false + required: [apiVersion, kind, operations, previewLimits, features] + properties: + apiVersion: {$ref: '#/components/schemas/APIVersion'} + kind: {type: string, enum: [ExplorerAuthoringCapabilities]} + operations: + type: array + items: {type: string, enum: [builder, compile, suggestions, preview, publish, draft, export, commands, reconcile]} + previewLimits: + type: array + items: {type: integer, minimum: 1, maximum: 1000} + features: + $ref: '#/components/schemas/AuthoringFeatures' + AuthoringFeatures: + type: object + additionalProperties: false + required: [emissionFilters, emissionCharts, sharedFilters, fixedFilters, fileActions, deleteExplorer] + properties: + emissionFilters: {type: boolean} + emissionCharts: {type: boolean} + sharedFilters: {type: boolean} + fixedFilters: {type: boolean} + fileActions: {type: boolean} + deleteExplorer: {type: boolean} + APIVersion: + type: string + enum: [loom.calypr.org/explorer-authoring/v2] + ProjectionMode: + type: string + enum: [SCALAR, FIRST, ARRAY, DISTINCT_ARRAY, VALUE, ALL, DISTINCT] + Workspace: + type: object + x-go-type: authoringv2.Workspace + x-go-type-import: + path: github.com/calypr/loom/internal/explorer/authoringv2 + name: authoringv2 + additionalProperties: false + required: [apiVersion, kind, explorer, documents, tabs] + properties: + apiVersion: {$ref: '#/components/schemas/APIVersion'} + kind: {type: string, enum: [ExplorerBuilderWorkspace]} + explorer: {$ref: '#/components/schemas/ExplorerMetadata'} + documents: + type: array + items: {$ref: '#/components/schemas/Document'} + tabs: + type: array + items: {$ref: '#/components/schemas/Tab'} + sharedFilters: + type: object + additionalProperties: + type: array + items: {$ref: '#/components/schemas/SharedFilterBinding'} + fileActions: {$ref: '#/components/schemas/FileActions'} + ExplorerMetadata: + type: object + additionalProperties: false + required: [title] + properties: + title: {type: string, minLength: 1} + description: {type: string} + Tab: + type: object + additionalProperties: false + required: [id, title, outputId, order, visible] + properties: + id: {type: string, pattern: '^[A-Za-z_][A-Za-z0-9_]*$'} + title: {type: string, minLength: 1} + outputId: {type: string, minLength: 1} + order: {type: integer, minimum: 0} + visible: {type: boolean} + Document: + type: object + additionalProperties: false + required: [kind, output, rootResourceType, route, columns] + properties: + kind: {type: string, enum: [ExplorerBuilderDocument]} + output: {$ref: '#/components/schemas/Output'} + rootResourceType: {type: string, minLength: 1} + route: {$ref: '#/components/schemas/RouteNode'} + columns: + type: array + items: {$ref: '#/components/schemas/Column'} + fixedFilters: + type: array + items: {$ref: '#/components/schemas/FixedFilter'} + actions: + type: array + items: {$ref: '#/components/schemas/Action'} + Output: + type: object + additionalProperties: false + required: [id, title] + properties: + id: {type: string, minLength: 1} + title: {type: string, minLength: 1} + rowLabel: {type: string} + RouteNode: + type: object + additionalProperties: false + required: [occurrenceId, resourceType] + properties: + occurrenceId: {type: string, minLength: 1} + resourceType: {type: string, minLength: 1} + relationship: {type: string} + children: + type: array + items: {$ref: '#/components/schemas/RouteNode'} + ColumnSource: + type: object + additionalProperties: false + required: [kind] + properties: + kind: + type: string + enum: [field, identifierBySystem, extensionByUrl, codingBySystem, observationComponentByCode, projectId] + fieldPath: {type: string} + match: {type: string} + projectionMode: {type: string, enum: [VALUE, FIRST, ALL, DISTINCT]} + Column: + type: object + additionalProperties: false + required: [column, label, occurrenceId, source] + properties: + column: {type: string, pattern: '^[A-Za-z_][A-Za-z0-9_]*$'} + label: {type: string, minLength: 1} + logicalType: {type: string} + occurrenceId: {type: string, minLength: 1} + source: {$ref: '#/components/schemas/ColumnSource'} + table: {$ref: '#/components/schemas/TablePresentation'} + filter: {$ref: '#/components/schemas/FilterPresentation'} + chart: {$ref: '#/components/schemas/ChartPresentation'} + FixedFilter: + type: object + additionalProperties: false + required: [column, values] + properties: + column: {type: string, minLength: 1} + values: + type: array + minItems: 1 + items: {type: string} + ActionColumn: + type: object + additionalProperties: false + required: [column] + properties: + column: {type: string, minLength: 1} + exportHeader: {type: string} + Action: + type: object + additionalProperties: false + required: [type, title] + properties: + type: {type: string, minLength: 1} + title: {type: string, minLength: 1} + fileName: {type: string} + columns: + type: array + items: {$ref: '#/components/schemas/ActionColumn'} + SharedFilterBinding: + type: object + additionalProperties: false + required: [outputId, column] + properties: + outputId: {type: string, minLength: 1} + column: {type: string, minLength: 1} + FileActions: + type: object + additionalProperties: false + required: [extensions, actions] + properties: + extensions: + type: object + additionalProperties: + type: array + items: {type: string} + actions: + type: object + additionalProperties: {type: string} + TablePresentation: + type: object + additionalProperties: false + properties: + visible: {type: boolean} + order: {type: integer, minimum: 0} + pinned: {type: boolean} + cellRenderer: {type: string, enum: [fileActions]} + FilterPresentation: + type: object + additionalProperties: false + properties: + label: {type: string} + order: {type: integer, minimum: 0} + ChartPresentation: + type: object + additionalProperties: false + required: [type] + properties: + type: {type: string, minLength: 1} + title: {type: string} + order: {type: integer, minimum: 0} + CompileRequest: + type: object + additionalProperties: false + required: [workspace, snapshotToken] + properties: + workspace: {$ref: '#/components/schemas/Workspace'} + snapshotToken: {type: string, minLength: 1} + ApplyCommandsRequest: + type: object + additionalProperties: false + required: [commandId, snapshotToken, expectedDraftVersion, commands] + properties: + commandId: {type: string, minLength: 1} + snapshotToken: {type: string, minLength: 1} + expectedDraftVersion: {type: integer, format: int64, minimum: 0} + expectedDraftDigest: {type: string} + commands: + type: array + minItems: 1 + items: {$ref: '#/components/schemas/AuthoringCommand'} + AuthoringCommand: + type: object + additionalProperties: false + required: [type] + properties: + type: + type: string + enum: [CREATE_TABLE, DUPLICATE_TABLE, DELETE_TABLE, RENAME_TABLE, REORDER_TABLES, SET_TABLE_ROOT, ADD_ROUTE, REMOVE_ROUTE, ADD_COLUMN, UPDATE_COLUMN, REMOVE_COLUMN] + outputId: {type: string, minLength: 1} + sourceOutputId: {type: string, minLength: 1} + title: {type: string, minLength: 1} + rootNodeId: {type: string, minLength: 1} + parentOccurrenceId: {type: string, minLength: 1} + occurrenceId: {type: string, minLength: 1} + edgeId: {type: string, minLength: 1} + candidateId: {type: string, minLength: 1} + projectionMode: {$ref: '#/components/schemas/ProjectionMode'} + initialPresentation: {type: string, enum: [TABLE, FILTER, CHART]} + column: {type: string, minLength: 1} + columnValue: {$ref: '#/components/schemas/Column'} + outputIds: + type: array + items: {type: string, minLength: 1} + CommandResult: + type: object + additionalProperties: false + required: [type] + properties: + type: {type: string, enum: [TABLE_CREATED, TABLE_CHANGED, ROUTE_ADDED, COLUMN_ADDED]} + outputId: {type: string} + tabId: {type: string} + occurrenceId: {type: string} + column: {type: string} + ApplyCommandsResponse: + type: object + additionalProperties: false + required: [commandId, workspace, draftVersion, draftDigest, results, diagnostics] + properties: + commandId: {type: string, minLength: 1} + workspace: {$ref: '#/components/schemas/Workspace'} + draftVersion: {type: integer, format: int64, minimum: 1} + draftDigest: {type: string, minLength: 1} + results: + type: array + items: {$ref: '#/components/schemas/CommandResult'} + diagnostics: + type: array + items: {$ref: '#/components/schemas/Diagnostic'} + ReconcileRequest: + type: object + additionalProperties: false + required: [snapshotToken, draftVersion, draftDigest] + properties: + snapshotToken: {type: string, minLength: 1} + draftVersion: {type: integer, format: int64, minimum: 1} + draftDigest: {type: string, minLength: 1} + SaveDraftRequest: + type: object + additionalProperties: false + required: [workspace, snapshotToken, expectedDraftVersion] + properties: + workspace: {$ref: '#/components/schemas/Workspace'} + snapshotToken: {type: string, minLength: 1} + expectedDraftVersion: {type: integer, format: int64, minimum: 0} + expectedDraftDigest: {type: string} + SaveDraftResponse: + type: object + additionalProperties: false + required: [workspace, draftVersion, draftDigest] + properties: + workspace: {$ref: '#/components/schemas/Workspace'} + draftVersion: {type: integer, format: int64, minimum: 1} + draftDigest: {type: string, minLength: 1} + BuilderState: + type: object + additionalProperties: false + required: [apiVersion, kind, lifecycleState, draftVersion, draftDigest, workspace, catalog] + properties: + apiVersion: {$ref: '#/components/schemas/APIVersion'} + kind: {type: string, enum: [ExplorerBuilderState]} + lifecycleState: {type: string, enum: [NEW, READY]} + draftVersion: {type: integer, format: int64, minimum: 0} + draftDigest: {type: string} + workspace: + allOf: + - $ref: '#/components/schemas/Workspace' + nullable: true + catalog: {$ref: '#/components/schemas/Catalog'} + Catalog: + type: object + additionalProperties: false + required: [generation, authorizationScopeDigest, snapshotToken, complete, nodes, edges, candidates, routePolicy] + properties: + generation: {type: string, minLength: 1} + authorizationScopeDigest: {type: string, minLength: 1} + resolvedSchemaDigest: {type: string} + snapshotToken: {type: string, minLength: 1} + complete: {type: boolean} + nodes: + type: array + items: {$ref: '#/components/schemas/CatalogNode'} + edges: + type: array + items: {$ref: '#/components/schemas/CatalogEdge'} + candidates: + type: array + items: {$ref: '#/components/schemas/CatalogCandidate'} + routePolicy: {$ref: '#/components/schemas/RoutePolicy'} + CatalogNode: + type: object + additionalProperties: false + required: [nodeId, resourceType, rowRootEligible, populated] + properties: + nodeId: {type: string, minLength: 1} + resourceType: {type: string, minLength: 1} + rowRootEligible: {type: boolean} + rowGrain: {type: string} + populated: {type: boolean} + documentCount: {type: integer, format: int64, minimum: 0} + CatalogEdge: + type: object + additionalProperties: false + required: [edgeId, fromNodeId, toNodeId, label, populated] + properties: + edgeId: {type: string, minLength: 1} + fromNodeId: {type: string, minLength: 1} + toNodeId: {type: string, minLength: 1} + label: {type: string, minLength: 1} + populated: {type: boolean} + CatalogCandidate: + type: object + additionalProperties: false + required: [candidateId, nodeId, fieldPath, label, logicalType, repeated, filterable, chartable, projectionModes, defaultProjectionMode] + properties: + candidateId: {type: string, minLength: 1} + nodeId: {type: string, minLength: 1} + fieldPath: {type: string, minLength: 1} + label: {type: string, minLength: 1} + logicalType: {type: string, minLength: 1} + repeated: {type: boolean} + filterable: {type: boolean} + chartable: {type: boolean} + projectionModes: + type: array + items: {$ref: '#/components/schemas/ProjectionMode'} + defaultProjectionMode: {$ref: '#/components/schemas/ProjectionMode'} + RoutePolicy: + type: object + additionalProperties: false + required: [allowRepeatedEdges, allowSelfLoops] + properties: + maxSteps: {type: integer, minimum: 0} + allowRepeatedEdges: {type: boolean} + allowSelfLoops: {type: boolean} + CandidateSuggestions: + type: object + additionalProperties: false + required: [apiVersion, kind, snapshotToken, candidateId, values, complete, truncated] + properties: + apiVersion: {$ref: '#/components/schemas/APIVersion'} + kind: {type: string, enum: [ExplorerCandidateSuggestions]} + snapshotToken: {type: string, minLength: 1} + candidateId: {type: string, minLength: 1} + values: + type: array + items: {type: string} + complete: {type: boolean} + truncated: {type: boolean} + CandidateSearchRequest: + type: object + additionalProperties: false + required: [snapshotToken, nodeId] + properties: + snapshotToken: {type: string, minLength: 1} + nodeId: {type: string, minLength: 1} + query: {type: string} + CandidateSearchResponse: + type: object + additionalProperties: false + required: [apiVersion, kind, snapshotToken, nodeId, candidates, diagnostics] + properties: + apiVersion: {$ref: '#/components/schemas/APIVersion'} + kind: {type: string, enum: [ExplorerBuilderCandidateSuggestions]} + snapshotToken: {type: string, minLength: 1} + nodeId: {type: string, minLength: 1} + candidates: + type: array + items: {$ref: '#/components/schemas/CatalogCandidate'} + diagnostics: + type: array + items: {$ref: '#/components/schemas/Diagnostic'} + ContractColumn: + type: object + additionalProperties: false + required: [column, label, logicalType, filterable, chartable] + properties: + column: {type: string, minLength: 1} + label: {type: string} + logicalType: {type: string, minLength: 1} + filterable: {type: boolean} + chartable: {type: boolean} + ReceiptOutput: + type: object + additionalProperties: false + required: [outputId, title, rowGrain, columns] + properties: + outputId: {type: string, minLength: 1} + title: {type: string, minLength: 1} + rowGrain: {type: string} + columns: + type: array + items: {$ref: '#/components/schemas/ContractColumn'} + CompileResponse: + type: object + additionalProperties: false + required: [apiVersion, kind, receiptId, snapshotToken, generation, intentDigest, compilerVersion, builder, outputs, diagnostics] + properties: + apiVersion: {$ref: '#/components/schemas/APIVersion'} + kind: {type: string, enum: [ExplorerBuilderReceipt]} + receiptId: {type: string, minLength: 1} + snapshotToken: {type: string, minLength: 1} + generation: {type: string, minLength: 1} + intentDigest: {type: string, minLength: 1} + compilerVersion: {type: string, minLength: 1} + builder: {$ref: '#/components/schemas/Workspace'} + outputs: + type: array + items: {$ref: '#/components/schemas/ReceiptOutput'} + diagnostics: + type: array + items: {$ref: '#/components/schemas/Diagnostic'} + PreviewRequest: + type: object + additionalProperties: false + required: [receiptId, outputId] + properties: + receiptId: {type: string, minLength: 1} + outputId: {type: string, minLength: 1} + limit: {type: integer, minimum: 1, maximum: 1000} + PreviewResponse: + type: object + additionalProperties: false + required: [apiVersion, kind, receiptId, outputId, columns, rows, rowCount, diagnostics] + properties: + apiVersion: {$ref: '#/components/schemas/APIVersion'} + kind: {type: string, enum: [ExplorerBuilderPreview]} + receiptId: {type: string, minLength: 1} + outputId: {type: string, minLength: 1} + columns: + type: array + items: {$ref: '#/components/schemas/ContractColumn'} + rows: + type: array + items: + type: object + additionalProperties: true + rowCount: {type: integer, minimum: 0} + diagnostics: + type: array + items: {$ref: '#/components/schemas/Diagnostic'} + PublishRequest: + type: object + additionalProperties: false + required: [receiptId] + properties: + receiptId: {type: string, minLength: 1} + PublicationOutput: + type: object + additionalProperties: false + required: [outputId, state, materializationId] + properties: + outputId: {type: string, minLength: 1} + state: {type: string, minLength: 1} + materializationId: {type: string, minLength: 1} + PublishResponse: + type: object + additionalProperties: false + required: [apiVersion, kind, receiptId, revisionId, state, outputs, diagnostics] + properties: + apiVersion: {$ref: '#/components/schemas/APIVersion'} + kind: {type: string, enum: [ExplorerBuilderPublication]} + receiptId: {type: string, minLength: 1} + revisionId: {type: string, minLength: 1} + state: {type: string, minLength: 1} + outputs: + type: array + items: {$ref: '#/components/schemas/PublicationOutput'} + diagnostics: + type: array + items: {$ref: '#/components/schemas/Diagnostic'} + Diagnostic: + type: object + additionalProperties: false + required: [severity, stage, code, message] + properties: + severity: {type: string, minLength: 1} + stage: {type: string, minLength: 1} + code: {type: string, pattern: '^[A-Z][A-Z0-9_]*$'} + jsonPath: {type: string} + message: {type: string, minLength: 1} + details: + type: object + additionalProperties: true + requestId: {type: string} + ErrorResponse: + type: object + additionalProperties: false + required: [error] + properties: + error: + $ref: '#/components/schemas/ErrorBody' + diagnostics: + type: array + items: {$ref: '#/components/schemas/Diagnostic'} + ErrorBody: + type: object + additionalProperties: true + required: [code, message] + properties: + code: {type: string, minLength: 1} + message: {type: string, minLength: 1} + requestId: {type: string} + diagnostic: {$ref: '#/components/schemas/Diagnostic'} From 9e5fabdcf54f2fffbf1ef485022f45fd99f62966 Mon Sep 17 00:00:00 2001 From: matthewpeterkort Date: Fri, 28 Aug 2026 16:59:10 -0700 Subject: [PATCH 13/15] cleanup --- internal/catalog/types.go | 2 - internal/dataframe/published/federation.go | 340 ----- .../dataframe/published/federation_query.go | 351 ++++++ .../explorer/arango/receipt_store_test.go | 6 - internal/explorer/arango/store.go | 7 - internal/explorer/authoringv2/canonical.go | 364 ++++++ .../explorer/authoringv2/semantic_types.go | 7 - internal/explorer/authoringv2/types.go | 894 +------------ internal/explorer/authoringv2/types_test.go | 15 - internal/explorer/authoringv2/validation.go | 487 ++++++++ .../explorer/authoringv2/workspace_test.go | 11 + internal/explorer/compilation.go | 8 - internal/explorer/config_v2.go | 101 -- internal/explorer/config_v2_test.go | 48 - internal/explorer/service.go | 4 - internal/explorer/store.go | 1 - internal/explorer/viewer_projection.go | 98 -- internal/fhir/schema/generated_metadata.go | 1 - internal/server/http_test_helpers_test.go | 12 - internal/server/openapi_data_routes.go | 529 ++++++++ internal/server/openapi_explorer_routes.go | 512 ++++++++ internal/server/openapi_graphql_routes.go | 98 ++ internal/server/openapi_routes.go | 1113 ----------------- 23 files changed, 2358 insertions(+), 2651 deletions(-) create mode 100644 internal/dataframe/published/federation_query.go create mode 100644 internal/explorer/authoringv2/canonical.go create mode 100644 internal/explorer/authoringv2/validation.go delete mode 100644 internal/explorer/config_v2_test.go create mode 100644 internal/server/openapi_data_routes.go create mode 100644 internal/server/openapi_explorer_routes.go create mode 100644 internal/server/openapi_graphql_routes.go diff --git a/internal/catalog/types.go b/internal/catalog/types.go index 12c526ed..6052eba3 100644 --- a/internal/catalog/types.go +++ b/internal/catalog/types.go @@ -77,8 +77,6 @@ type ResourceInventoryObservation struct { DocumentCount int64 `json:"document_count"` } -type ResourceInventoryRecord = ResourceInventoryObservation - type ResourceInventoryResult struct { Values []ResourceInventoryObservation `json:"values"` Available bool `json:"available"` diff --git a/internal/dataframe/published/federation.go b/internal/dataframe/published/federation.go index 3252b61b..63231bfe 100644 --- a/internal/dataframe/published/federation.go +++ b/internal/dataframe/published/federation.go @@ -731,343 +731,3 @@ func (r *Reader) PublishedProjects(ctx context.Context) ([]string, error) { sort.Strings(result) return result, nil } - -func (r *Reader) PageFederatedDataset(ctx context.Context, dataset FederatedDataset, req FederatedPageRequest) (FederatedPage, error) { - if r == nil || r.ClickHouse == nil { - return FederatedPage{}, dataframeerrors.NewError(dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) - } - columns, allowed, err := federatedColumns(dataset, req.Columns, req.Sort) - if err != nil { - return FederatedPage{}, err - } - first := req.First - if first <= 0 { - first = 100 - } - if r.MaxPage > 0 && first > r.MaxPage { - first = r.MaxPage - } - cursor, err := decodeCursor(req.After) - if err != nil { - return FederatedPage{}, dataframeerrors.Wrap(err, dataframeerrors.CodeInvalidCursor, "") - } - unionColumns := append([]string(nil), columns...) - if req.Sort != nil && !contains(unionColumns, req.Sort.Column) { - unionColumns = append(unionColumns, req.Sort.Column) - } - for _, filter := range req.Filters { - if !contains(unionColumns, filter.Column) { - unionColumns = append(unionColumns, filter.Column) - } - } - union, unionArgs, err := federatedNormalizedUnion(dataset, unionColumns, req.AccessByProject) - if err != nil { - return FederatedPage{}, err - } - where, whereArgs, err := buildWhere(req.Filters, allowed) - if err != nil { - return FederatedPage{}, err - } - queryColumns := append([]string(nil), unionColumns...) - queryColumns = append(queryColumns, "__loom_row_id", "__loom_global_row_id") - selectColumns := quotedColumns(queryColumns) + ", count() OVER() AS `__loom_total`" - readColumns := append(append([]string(nil), queryColumns...), "__loom_total") - counted := fmt.Sprintf("SELECT %s FROM (%s) AS __loom_federated", selectColumns, union) - queryArgs := append([]any(nil), unionArgs...) - queryArgs = append(queryArgs, whereArgs...) - if len(where) > 0 { - counted += " WHERE " + strings.Join(where, " AND ") - } - query := fmt.Sprintf("SELECT %s FROM (%s) AS __loom_counted", quotedColumns(readColumns), counted) - if cursor != nil { - cursorWhere, cursorArgs, err := federatedCursorPredicate(cursor, req.Sort) - if err != nil { - return FederatedPage{}, err - } - query += " WHERE " + cursorWhere - queryArgs = append(queryArgs, cursorArgs...) - } - if req.Sort != nil { - direction := "ASC" - if req.Sort.Desc { - direction = "DESC" - } - query += fmt.Sprintf(" ORDER BY `%s` %s, `__loom_global_row_id` ASC", req.Sort.Column, direction) - } else { - query += " ORDER BY `__loom_global_row_id` ASC" - } - query += fmt.Sprintf(" LIMIT %d", first+1) - rows, err := r.ClickHouse.QueryRowsArgs(ctx, query, readColumns, queryArgs...) - if err != nil { - return FederatedPage{}, backendCallError(err) - } - var count int64 - if len(rows) > 0 { - count, err = numericCount(rows[0]["__loom_total"]) - if err != nil { - return FederatedPage{}, err - } - } else { - // A window has no carrier row for an empty page (including an after - // cursor beyond the end), so only that case needs the count fallback. - count, err = r.federatedCountDataset(ctx, dataset, allowed, req) - if err != nil { - return FederatedPage{}, err - } - } - hasNext := len(rows) > first - if hasNext { - rows = rows[:first] - } - next := "" - if hasNext && len(rows) > 0 { - last := rows[len(rows)-1] - rowID := fmt.Sprint(last["__loom_global_row_id"]) - var sortValue any - if req.Sort != nil { - sortValue = last[req.Sort.Column] - if sortValue == nil { - return FederatedPage{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidCursor, "") - } - } - next = encodeCursor(rowID, sortValue) - } - for _, row := range rows { - delete(row, "__loom_total") - delete(row, "__loom_row_id") - delete(row, "__loom_global_row_id") - for _, column := range unionColumns { - if !contains(columns, column) { - delete(row, column) - } - } - } - return FederatedPage{Dataset: dataset, Columns: columns, Rows: rows, TotalCount: count, HasNext: hasNext, NextCursor: next}, nil -} - -func (r *Reader) StreamFederatedDataset(ctx context.Context, dataset FederatedDataset, req FederatedStreamRequest, visit func(map[string]any) error) (FederatedDataset, error) { - if r == nil || r.ClickHouse == nil { - return FederatedDataset{}, dataframeerrors.NewError(dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) - } - if visit == nil { - return FederatedDataset{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") - } - columns, allowed, err := federatedColumns(dataset, req.Columns, req.Sort) - if err != nil { - return FederatedDataset{}, err - } - unionColumns := append([]string(nil), columns...) - if req.Sort != nil && !contains(unionColumns, req.Sort.Column) { - unionColumns = append(unionColumns, req.Sort.Column) - } - for _, filter := range req.Filters { - if !contains(unionColumns, filter.Column) { - unionColumns = append(unionColumns, filter.Column) - } - } - union, args, err := federatedNormalizedUnion(dataset, unionColumns, req.AccessByProject) - if err != nil { - return FederatedDataset{}, err - } - where, whereArgs, err := buildWhere(req.Filters, allowed) - if err != nil { - return FederatedDataset{}, err - } - args = append(args, whereArgs...) - queryColumns := append([]string(nil), unionColumns...) - queryColumns = append(queryColumns, "__loom_row_id", "__loom_global_row_id") - query := fmt.Sprintf("SELECT %s FROM (%s) AS __loom_federated", quotedColumns(queryColumns), union) - if len(where) > 0 { - query += " WHERE " + strings.Join(where, " AND ") - } - if req.Sort != nil { - direction := "ASC" - if req.Sort.Desc { - direction = "DESC" - } - query += fmt.Sprintf(" ORDER BY `%s` %s, `__loom_global_row_id` ASC", req.Sort.Column, direction) - } else { - query += " ORDER BY `__loom_global_row_id` ASC" - } - err = r.ClickHouse.QueryRowsArgsVisit(ctx, query, queryColumns, func(row map[string]any) error { - delete(row, "__loom_row_id") - delete(row, "__loom_global_row_id") - for _, column := range unionColumns { - if !contains(columns, column) { - delete(row, column) - } - } - return visit(row) - }, args...) - if err != nil { - return FederatedDataset{}, backendCallError(err) - } - return dataset, nil -} - -func (r *Reader) federatedCountDataset(ctx context.Context, dataset FederatedDataset, allowed map[string]struct{}, req FederatedPageRequest) (int64, error) { - union, args, err := federatedNormalizedUnion(dataset, datasetVisibleColumns(dataset), req.AccessByProject) - if err != nil { - return 0, err - } - where, whereArgs, err := buildWhere(req.Filters, allowed) - if err != nil { - return 0, err - } - args = append(args, whereArgs...) - query := fmt.Sprintf("SELECT count() AS `__loom_total` FROM (%s) AS __loom_federated", union) - if len(where) > 0 { - query += " WHERE " + strings.Join(where, " AND ") - } - rows, err := r.ClickHouse.QueryRowsArgs(ctx, query, []string{"__loom_total"}, args...) - if err != nil { - return 0, backendCallError(err) - } - var total int64 - for _, row := range rows { - value, err := numericCount(row["__loom_total"]) - if err != nil { - return 0, err - } - total += value - } - return total, nil -} - -func datasetVisibleColumns(dataset FederatedDataset) []string { - result := make([]string, 0, len(dataset.Columns)) - for _, column := range dataset.Columns { - if column.Name != authResourcePathColumn && column.Name != "__loom_row_id" { - result = append(result, column.Name) - } - } - return result -} - -func federatedColumns(dataset FederatedDataset, requested []string, sort *Sort) ([]string, map[string]struct{}, error) { - for _, column := range requested { - if column == authResourcePathColumn { - return nil, nil, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") - } - } - allowed := make(map[string]struct{}, len(dataset.Columns)) - columns := append([]string(nil), requested...) - for _, column := range dataset.Columns { - if column.Name == "__loom_row_id" { - continue - } - allowed[column.Name] = struct{}{} - if len(requested) == 0 { - if column.Name != authResourcePathColumn { - columns = append(columns, column.Name) - } - } - } - if err := validateReaderColumns(columns, allowed); err != nil { - return nil, nil, err - } - if sort != nil { - if sort.Column == authResourcePathColumn { - return nil, nil, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") - } - if err := validateReaderColumns([]string{sort.Column}, allowed); err != nil { - return nil, nil, dataframeerrors.Wrap(err, dataframeerrors.CodeInvalidRequest, "") - } - } - return columns, allowed, nil -} - -// federatedNormalizedUnion creates the single typed source union used by rows, -// counts and aggregates. User predicates are deliberately applied by callers -// around this union; only per-source authorization remains inside branches. -func federatedNormalizedUnion(dataset FederatedDataset, columns []string, accessByProject map[string]SourceAccess) (string, []any, error) { - branches := make([]string, 0, len(dataset.Sources)) - args := make([]any, 0) - for _, source := range dataset.Sources { - present := make(map[string]Column, len(source.Columns)) - for _, column := range source.Columns { - present[column.Name] = column - } - selects := make([]string, 0, len(columns)+2) - for _, column := range columns { - target, ok := findColumn(dataset.Columns, column) - if !ok { - return "", nil, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") - } - if column == projectIDColumn { - // The catalog project is authoritative, including for legacy tables - // without a physical project_id column. - selects = append(selects, fmt.Sprintf("CAST(? AS %s) AS `project_id`", target.ClickHouse)) - args = append(args, source.Project) - } else if sourceColumn, exists := present[column]; exists { - selects = append(selects, fmt.Sprintf("CAST(`%s` AS %s) AS `%s`", sourceColumn.Name, target.ClickHouse, column)) - } else if strings.HasPrefix(target.ClickHouse, "Array(") { - selects = append(selects, fmt.Sprintf("CAST([] AS %s) AS `%s`", target.ClickHouse, column)) - } else { - typ := target.ClickHouse - if !strings.HasPrefix(typ, "Nullable(") { - typ = "Nullable(" + typ + ")" - } - selects = append(selects, fmt.Sprintf("CAST(NULL AS %s) AS `%s`", typ, column)) - } - } - selects = append(selects, "toString(`__loom_row_id`) AS `__loom_row_id`", "concat(?, ':', toString(`__loom_row_id`)) AS `__loom_global_row_id`") - branch := "SELECT " + strings.Join(selects, ", ") + " FROM `" + source.PhysicalTable + "`" - access := accessByProject[source.Project] - if !access.Unrestricted { - if _, ok := present[authResourcePathColumn]; ok { - branch += " WHERE `auth_resource_path` IN ?" - args = append(args, source.ID, access.ResourcePaths) - } else { - branch += " WHERE 0" - args = append(args, source.ID) - } - } else { - args = append(args, source.ID) - } - branches = append(branches, branch) - } - return strings.Join(branches, " UNION ALL "), args, nil -} - -func validateReaderColumns(columns []string, allowed map[string]struct{}) error { - for _, column := range columns { - if column == "__loom_row_id" || column == "__loom_global_row_id" { - return dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, fmt.Sprintf("column %q is internal to dataframe pagination", column)) - } - if _, ok := allowed[column]; !ok { - return dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, fmt.Sprintf("column %q is not in federated dataset schema", column)) - } - } - return nil -} - -func quotedColumns(columns []string) string { - quoted := make([]string, len(columns)) - for index, column := range columns { - quoted[index] = fmt.Sprintf("`%s`", column) - } - return strings.Join(quoted, ", ") -} - -func shortQueryID(query string) string { - digest := sha256.Sum256([]byte(query)) - return hex.EncodeToString(digest[:8]) -} - -func federatedCursorPredicate(cursor *pageCursor, sort *Sort) (string, []any, error) { - if cursor == nil || cursor.RowID == "" { - return "", nil, fmt.Errorf("invalid federated cursor") - } - if sort == nil { - return "`__loom_global_row_id` > ?", []any{cursor.RowID}, nil - } - if cursor.SortValue == nil { - return "", nil, fmt.Errorf("federated keyset cursor is missing sort value") - } - op := ">" - if sort.Desc { - op = "<" - } - return fmt.Sprintf("(`%s` %s ? OR (`%s` = ? AND `__loom_global_row_id` > ?))", sort.Column, op, sort.Column), []any{cursor.SortValue, cursor.SortValue, cursor.RowID}, nil -} diff --git a/internal/dataframe/published/federation_query.go b/internal/dataframe/published/federation_query.go new file mode 100644 index 00000000..dcdccd28 --- /dev/null +++ b/internal/dataframe/published/federation_query.go @@ -0,0 +1,351 @@ +package published + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "fmt" + "strings" + + dataframeerrors "github.com/calypr/loom/internal/dataframe/errors" +) + +func (r *Reader) PageFederatedDataset(ctx context.Context, dataset FederatedDataset, req FederatedPageRequest) (FederatedPage, error) { + if r == nil || r.ClickHouse == nil { + return FederatedPage{}, dataframeerrors.NewError(dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) + } + columns, allowed, err := federatedColumns(dataset, req.Columns, req.Sort) + if err != nil { + return FederatedPage{}, err + } + first := req.First + if first <= 0 { + first = 100 + } + if r.MaxPage > 0 && first > r.MaxPage { + first = r.MaxPage + } + cursor, err := decodeCursor(req.After) + if err != nil { + return FederatedPage{}, dataframeerrors.Wrap(err, dataframeerrors.CodeInvalidCursor, "") + } + unionColumns := append([]string(nil), columns...) + if req.Sort != nil && !contains(unionColumns, req.Sort.Column) { + unionColumns = append(unionColumns, req.Sort.Column) + } + for _, filter := range req.Filters { + if !contains(unionColumns, filter.Column) { + unionColumns = append(unionColumns, filter.Column) + } + } + union, unionArgs, err := federatedNormalizedUnion(dataset, unionColumns, req.AccessByProject) + if err != nil { + return FederatedPage{}, err + } + where, whereArgs, err := buildWhere(req.Filters, allowed) + if err != nil { + return FederatedPage{}, err + } + queryColumns := append([]string(nil), unionColumns...) + queryColumns = append(queryColumns, "__loom_row_id", "__loom_global_row_id") + selectColumns := quotedColumns(queryColumns) + ", count() OVER() AS `__loom_total`" + readColumns := append(append([]string(nil), queryColumns...), "__loom_total") + counted := fmt.Sprintf("SELECT %s FROM (%s) AS __loom_federated", selectColumns, union) + queryArgs := append([]any(nil), unionArgs...) + queryArgs = append(queryArgs, whereArgs...) + if len(where) > 0 { + counted += " WHERE " + strings.Join(where, " AND ") + } + query := fmt.Sprintf("SELECT %s FROM (%s) AS __loom_counted", quotedColumns(readColumns), counted) + if cursor != nil { + cursorWhere, cursorArgs, err := federatedCursorPredicate(cursor, req.Sort) + if err != nil { + return FederatedPage{}, err + } + query += " WHERE " + cursorWhere + queryArgs = append(queryArgs, cursorArgs...) + } + if req.Sort != nil { + direction := "ASC" + if req.Sort.Desc { + direction = "DESC" + } + query += fmt.Sprintf(" ORDER BY `%s` %s, `__loom_global_row_id` ASC", req.Sort.Column, direction) + } else { + query += " ORDER BY `__loom_global_row_id` ASC" + } + query += fmt.Sprintf(" LIMIT %d", first+1) + rows, err := r.ClickHouse.QueryRowsArgs(ctx, query, readColumns, queryArgs...) + if err != nil { + return FederatedPage{}, backendCallError(err) + } + var count int64 + if len(rows) > 0 { + count, err = numericCount(rows[0]["__loom_total"]) + if err != nil { + return FederatedPage{}, err + } + } else { + // A window has no carrier row for an empty page (including an after + // cursor beyond the end), so only that case needs the count fallback. + count, err = r.federatedCountDataset(ctx, dataset, allowed, req) + if err != nil { + return FederatedPage{}, err + } + } + hasNext := len(rows) > first + if hasNext { + rows = rows[:first] + } + next := "" + if hasNext && len(rows) > 0 { + last := rows[len(rows)-1] + rowID := fmt.Sprint(last["__loom_global_row_id"]) + var sortValue any + if req.Sort != nil { + sortValue = last[req.Sort.Column] + if sortValue == nil { + return FederatedPage{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidCursor, "") + } + } + next = encodeCursor(rowID, sortValue) + } + for _, row := range rows { + delete(row, "__loom_total") + delete(row, "__loom_row_id") + delete(row, "__loom_global_row_id") + for _, column := range unionColumns { + if !contains(columns, column) { + delete(row, column) + } + } + } + return FederatedPage{Dataset: dataset, Columns: columns, Rows: rows, TotalCount: count, HasNext: hasNext, NextCursor: next}, nil +} + +func (r *Reader) StreamFederatedDataset(ctx context.Context, dataset FederatedDataset, req FederatedStreamRequest, visit func(map[string]any) error) (FederatedDataset, error) { + if r == nil || r.ClickHouse == nil { + return FederatedDataset{}, dataframeerrors.NewError(dataframeerrors.CodeBackendUnavailable, "", dataframeerrors.WithRetryable(true)) + } + if visit == nil { + return FederatedDataset{}, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") + } + columns, allowed, err := federatedColumns(dataset, req.Columns, req.Sort) + if err != nil { + return FederatedDataset{}, err + } + unionColumns := append([]string(nil), columns...) + if req.Sort != nil && !contains(unionColumns, req.Sort.Column) { + unionColumns = append(unionColumns, req.Sort.Column) + } + for _, filter := range req.Filters { + if !contains(unionColumns, filter.Column) { + unionColumns = append(unionColumns, filter.Column) + } + } + union, args, err := federatedNormalizedUnion(dataset, unionColumns, req.AccessByProject) + if err != nil { + return FederatedDataset{}, err + } + where, whereArgs, err := buildWhere(req.Filters, allowed) + if err != nil { + return FederatedDataset{}, err + } + args = append(args, whereArgs...) + queryColumns := append([]string(nil), unionColumns...) + queryColumns = append(queryColumns, "__loom_row_id", "__loom_global_row_id") + query := fmt.Sprintf("SELECT %s FROM (%s) AS __loom_federated", quotedColumns(queryColumns), union) + if len(where) > 0 { + query += " WHERE " + strings.Join(where, " AND ") + } + if req.Sort != nil { + direction := "ASC" + if req.Sort.Desc { + direction = "DESC" + } + query += fmt.Sprintf(" ORDER BY `%s` %s, `__loom_global_row_id` ASC", req.Sort.Column, direction) + } else { + query += " ORDER BY `__loom_global_row_id` ASC" + } + err = r.ClickHouse.QueryRowsArgsVisit(ctx, query, queryColumns, func(row map[string]any) error { + delete(row, "__loom_row_id") + delete(row, "__loom_global_row_id") + for _, column := range unionColumns { + if !contains(columns, column) { + delete(row, column) + } + } + return visit(row) + }, args...) + if err != nil { + return FederatedDataset{}, backendCallError(err) + } + return dataset, nil +} + +func (r *Reader) federatedCountDataset(ctx context.Context, dataset FederatedDataset, allowed map[string]struct{}, req FederatedPageRequest) (int64, error) { + union, args, err := federatedNormalizedUnion(dataset, datasetVisibleColumns(dataset), req.AccessByProject) + if err != nil { + return 0, err + } + where, whereArgs, err := buildWhere(req.Filters, allowed) + if err != nil { + return 0, err + } + args = append(args, whereArgs...) + query := fmt.Sprintf("SELECT count() AS `__loom_total` FROM (%s) AS __loom_federated", union) + if len(where) > 0 { + query += " WHERE " + strings.Join(where, " AND ") + } + rows, err := r.ClickHouse.QueryRowsArgs(ctx, query, []string{"__loom_total"}, args...) + if err != nil { + return 0, backendCallError(err) + } + var total int64 + for _, row := range rows { + value, err := numericCount(row["__loom_total"]) + if err != nil { + return 0, err + } + total += value + } + return total, nil +} + +func datasetVisibleColumns(dataset FederatedDataset) []string { + result := make([]string, 0, len(dataset.Columns)) + for _, column := range dataset.Columns { + if column.Name != authResourcePathColumn && column.Name != "__loom_row_id" { + result = append(result, column.Name) + } + } + return result +} + +func federatedColumns(dataset FederatedDataset, requested []string, sort *Sort) ([]string, map[string]struct{}, error) { + for _, column := range requested { + if column == authResourcePathColumn { + return nil, nil, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") + } + } + allowed := make(map[string]struct{}, len(dataset.Columns)) + columns := append([]string(nil), requested...) + for _, column := range dataset.Columns { + if column.Name == "__loom_row_id" { + continue + } + allowed[column.Name] = struct{}{} + if len(requested) == 0 { + if column.Name != authResourcePathColumn { + columns = append(columns, column.Name) + } + } + } + if err := validateReaderColumns(columns, allowed); err != nil { + return nil, nil, err + } + if sort != nil { + if sort.Column == authResourcePathColumn { + return nil, nil, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") + } + if err := validateReaderColumns([]string{sort.Column}, allowed); err != nil { + return nil, nil, dataframeerrors.Wrap(err, dataframeerrors.CodeInvalidRequest, "") + } + } + return columns, allowed, nil +} + +// federatedNormalizedUnion creates the single typed source union used by rows, +// counts and aggregates. User predicates are deliberately applied by callers +// around this union; only per-source authorization remains inside branches. +func federatedNormalizedUnion(dataset FederatedDataset, columns []string, accessByProject map[string]SourceAccess) (string, []any, error) { + branches := make([]string, 0, len(dataset.Sources)) + args := make([]any, 0) + for _, source := range dataset.Sources { + present := make(map[string]Column, len(source.Columns)) + for _, column := range source.Columns { + present[column.Name] = column + } + selects := make([]string, 0, len(columns)+2) + for _, column := range columns { + target, ok := findColumn(dataset.Columns, column) + if !ok { + return "", nil, dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, "") + } + if column == projectIDColumn { + // The catalog project is authoritative, including for legacy tables + // without a physical project_id column. + selects = append(selects, fmt.Sprintf("CAST(? AS %s) AS `project_id`", target.ClickHouse)) + args = append(args, source.Project) + } else if sourceColumn, exists := present[column]; exists { + selects = append(selects, fmt.Sprintf("CAST(`%s` AS %s) AS `%s`", sourceColumn.Name, target.ClickHouse, column)) + } else if strings.HasPrefix(target.ClickHouse, "Array(") { + selects = append(selects, fmt.Sprintf("CAST([] AS %s) AS `%s`", target.ClickHouse, column)) + } else { + typ := target.ClickHouse + if !strings.HasPrefix(typ, "Nullable(") { + typ = "Nullable(" + typ + ")" + } + selects = append(selects, fmt.Sprintf("CAST(NULL AS %s) AS `%s`", typ, column)) + } + } + selects = append(selects, "toString(`__loom_row_id`) AS `__loom_row_id`", "concat(?, ':', toString(`__loom_row_id`)) AS `__loom_global_row_id`") + branch := "SELECT " + strings.Join(selects, ", ") + " FROM `" + source.PhysicalTable + "`" + access := accessByProject[source.Project] + if !access.Unrestricted { + if _, ok := present[authResourcePathColumn]; ok { + branch += " WHERE `auth_resource_path` IN ?" + args = append(args, source.ID, access.ResourcePaths) + } else { + branch += " WHERE 0" + args = append(args, source.ID) + } + } else { + args = append(args, source.ID) + } + branches = append(branches, branch) + } + return strings.Join(branches, " UNION ALL "), args, nil +} + +func validateReaderColumns(columns []string, allowed map[string]struct{}) error { + for _, column := range columns { + if column == "__loom_row_id" || column == "__loom_global_row_id" { + return dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, fmt.Sprintf("column %q is internal to dataframe pagination", column)) + } + if _, ok := allowed[column]; !ok { + return dataframeerrors.NewError(dataframeerrors.CodeInvalidRequest, fmt.Sprintf("column %q is not in federated dataset schema", column)) + } + } + return nil +} + +func quotedColumns(columns []string) string { + quoted := make([]string, len(columns)) + for index, column := range columns { + quoted[index] = fmt.Sprintf("`%s`", column) + } + return strings.Join(quoted, ", ") +} + +func shortQueryID(query string) string { + digest := sha256.Sum256([]byte(query)) + return hex.EncodeToString(digest[:8]) +} + +func federatedCursorPredicate(cursor *pageCursor, sort *Sort) (string, []any, error) { + if cursor == nil || cursor.RowID == "" { + return "", nil, fmt.Errorf("invalid federated cursor") + } + if sort == nil { + return "`__loom_global_row_id` > ?", []any{cursor.RowID}, nil + } + if cursor.SortValue == nil { + return "", nil, fmt.Errorf("federated keyset cursor is missing sort value") + } + op := ">" + if sort.Desc { + op = "<" + } + return fmt.Sprintf("(`%s` %s ? OR (`%s` = ? AND `__loom_global_row_id` > ?))", sort.Column, op, sort.Column), []any{cursor.SortValue, cursor.SortValue, cursor.RowID}, nil +} diff --git a/internal/explorer/arango/receipt_store_test.go b/internal/explorer/arango/receipt_store_test.go index 5bc00383..e7501e47 100644 --- a/internal/explorer/arango/receipt_store_test.go +++ b/internal/explorer/arango/receipt_store_test.go @@ -69,12 +69,6 @@ func TestReceiptArangoStoreUsesImmutableTenantScopedQueries(t *testing.T) { if !strings.Contains(call.query, "d.project == @project") || !strings.Contains(call.query, "d.explorerId == @explorerId") { t.Fatalf("lookup is not tenant scoped: %s", call.query) } - if _, err := adapter.GetCompilationReceiptByCompilationKey(context.Background(), "project-a", "explorer-a", receipt.CompilationKey); err != nil { - t.Fatal(err) - } - if !strings.Contains(client.calls[len(client.calls)-1].query, "d.compilationKey == @compilationKey") { - t.Fatalf("compilation key query missing: %s", client.calls[len(client.calls)-1].query) - } } func testReceiptBundle() recipe.Bundle { diff --git a/internal/explorer/arango/store.go b/internal/explorer/arango/store.go index f2484866..bb47b4a5 100644 --- a/internal/explorer/arango/store.go +++ b/internal/explorer/arango/store.go @@ -144,9 +144,6 @@ func (s *Store) InsertCompilationReceipt(ctx context.Context, receipt explorer.C if err != nil { return nil, err } - if receipt.Project != "" && receipt.ExplorerID != "" { - return s.GetCompilationReceiptForExplorer(ctx, receipt.Project, receipt.ExplorerID, receipt.ID) - } return s.GetCompilationReceiptForExplorer(ctx, receipt.Project, receipt.ExplorerID, receipt.ID) } @@ -154,10 +151,6 @@ func (s *Store) GetCompilationReceiptForExplorer(ctx context.Context, project, e return s.readCompilationReceipt(ctx, `FOR d IN @@c FILTER d._key == @key AND d.project == @project AND d.explorerId == @explorerId RETURN d`, map[string]any{"@c": CompilationReceiptsCollection, "key": id, "project": project, "explorerId": explorerID}) } -func (s *Store) GetCompilationReceiptByCompilationKey(ctx context.Context, project, explorerID, compilationKey string) (*explorer.CompilationReceipt, error) { - return s.readCompilationReceipt(ctx, `FOR d IN @@c FILTER d.project == @project AND d.explorerId == @explorerId AND d.compilationKey == @compilationKey SORT d._key LIMIT 1 RETURN d`, map[string]any{"@c": CompilationReceiptsCollection, "project": project, "explorerId": explorerID, "compilationKey": compilationKey}) -} - func (s *Store) readCompilationReceipt(ctx context.Context, query string, binds map[string]any) (*explorer.CompilationReceipt, error) { var out *explorer.CompilationReceipt err := s.client.QueryRows(ctx, query, 1, binds, func(row map[string]any) error { diff --git a/internal/explorer/authoringv2/canonical.go b/internal/explorer/authoringv2/canonical.go new file mode 100644 index 00000000..2b833f3f --- /dev/null +++ b/internal/explorer/authoringv2/canonical.go @@ -0,0 +1,364 @@ +package authoringv2 + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "sort" +) + +func (d Document) CanonicalJSON() ([]byte, error) { + if err := d.Validate(); err != nil { + return nil, err + } + n := d + n.RouteSteps = append([]RouteStep(nil), d.RouteSteps...) + n.Selections = append([]Selection(nil), d.Selections...) + sort.SliceStable(n.Selections, func(i, j int) bool { + left := n.Selections[i].CandidateID + "\x00" + n.Selections[i].OccurrenceID + right := n.Selections[j].CandidateID + "\x00" + n.Selections[j].OccurrenceID + return left < right + }) + if n.RouteSteps == nil { + n.RouteSteps = []RouteStep{} + } + if n.Selections == nil { + n.Selections = []Selection{} + } + if n.Presentation == nil { + n.Presentation = map[string]Presentation{} + } + return json.Marshal(n) +} + +func (w Workspace) CanonicalJSON() ([]byte, error) { + if err := w.Validate(); err != nil { + return nil, err + } + n := w.NormalizePresentationOrders() + n.Documents = append([]Document(nil), n.Documents...) + for i := range n.Documents { + n.Documents[i].APIVersion = "" + if n.Documents[i].Columns == nil { + n.Documents[i].Columns = []Column{} + } + n.Documents[i].Selections = append([]Selection(nil), n.Documents[i].Selections...) + sort.SliceStable(n.Documents[i].Selections, func(a, b int) bool { + left := n.Documents[i].Selections[a] + right := n.Documents[i].Selections[b] + return left.CandidateID+"\x00"+left.OccurrenceID+"\x00"+left.ProjectionMode < right.CandidateID+"\x00"+right.OccurrenceID+"\x00"+right.ProjectionMode + }) + if n.Documents[i].RouteSteps == nil { + n.Documents[i].RouteSteps = []RouteStep{} + } + if n.Documents[i].Selections == nil { + n.Documents[i].Selections = []Selection{} + } + if n.Documents[i].Presentation == nil { + n.Documents[i].Presentation = map[string]Presentation{} + } + } + n.Tabs = append([]Tab(nil), w.Tabs...) + if n.Documents == nil { + n.Documents = []Document{} + } + if n.Tabs == nil { + n.Tabs = []Tab{} + } + return json.Marshal(n) +} + +// NormalizePresentationOrders gives every table column one unambiguous, +// contiguous presentation position. Authored order is the primary key and the +// stable public column identity breaks ties. The normalized order also becomes +// the recipe projection order, so presentation and execution cannot disagree. +// +// Duplicate presentation positions are valid mutable Builder input. Freezing +// them here keeps equivalent requests from depending on frontend collection or +// map iteration order and makes the normalized workspace safe to persist and +// return to the Builder. +func (w Workspace) NormalizePresentationOrders() Workspace { + n := w + n.Documents = append([]Document(nil), w.Documents...) + for documentIndex := range n.Documents { + document := &n.Documents[documentIndex] + columns := append([]Column(nil), document.Columns...) + if columns == nil { + columns = []Column{} + } + for columnIndex := range columns { + column := &columns[columnIndex] + if column.Table != nil { + table := *column.Table + column.Table = &table + } + if column.Filter != nil { + filter := *column.Filter + column.Filter = &filter + } + if column.Chart != nil { + chart := *column.Chart + column.Chart = &chart + } + } + sort.SliceStable(columns, func(i, j int) bool { + left, right := columns[i], columns[j] + leftClass, leftOrder := presentationOrder(left) + rightClass, rightOrder := presentationOrder(right) + if leftClass != rightClass { + return leftClass < rightClass + } + if leftOrder != rightOrder { + return leftOrder < rightOrder + } + return left.Column < right.Column + }) + tableOrder := 0 + for columnIndex := range columns { + if columns[columnIndex].Table == nil { + continue + } + value := tableOrder + columns[columnIndex].Table.Order = &value + tableOrder++ + } + normalizeFilterOrders(columns) + normalizeChartOrders(columns) + document.Columns = columns + } + return n +} + +func normalizeFilterOrders(columns []Column) { + indexes := make([]int, 0, len(columns)) + for index := range columns { + if columns[index].Filter != nil { + indexes = append(indexes, index) + } + } + sort.SliceStable(indexes, func(i, j int) bool { + left, right := columns[indexes[i]], columns[indexes[j]] + return auxiliaryPresentationLess(left.Filter.Order, left.Column, right.Filter.Order, right.Column) + }) + for order, index := range indexes { + value := order + columns[index].Filter.Order = &value + } +} + +func normalizeChartOrders(columns []Column) { + indexes := make([]int, 0, len(columns)) + for index := range columns { + if columns[index].Chart != nil { + indexes = append(indexes, index) + } + } + sort.SliceStable(indexes, func(i, j int) bool { + left, right := columns[indexes[i]], columns[indexes[j]] + return auxiliaryPresentationLess(left.Chart.Order, left.Column, right.Chart.Order, right.Column) + }) + for order, index := range indexes { + value := order + columns[index].Chart.Order = &value + } +} + +func auxiliaryPresentationLess(leftOrder *int, leftColumn string, rightOrder *int, rightColumn string) bool { + if (leftOrder == nil) != (rightOrder == nil) { + return leftOrder != nil + } + if leftOrder != nil && *leftOrder != *rightOrder { + return *leftOrder < *rightOrder + } + return leftColumn < rightColumn +} + +func presentationOrder(column Column) (class, order int) { + if column.Table == nil { + return 2, 0 + } + if column.Table.Order == nil { + return 1, 0 + } + return 0, *column.Table.Order +} + +func (w Workspace) Digest() (string, error) { + raw, err := w.CanonicalJSON() + if err != nil { + return "", err + } + sum := sha256.Sum256(raw) + return "sha256:" + hex.EncodeToString(sum[:]), nil +} + +func (d Document) Digest() (string, error) { + raw, err := d.CanonicalJSON() + if err != nil { + return "", err + } + sum := sha256.Sum256(raw) + return "sha256:" + hex.EncodeToString(sum[:]), nil +} + +func (c CatalogSnapshot) CanonicalJSON() ([]byte, error) { + if err := c.Validate(); err != nil { + return nil, err + } + n := c + n.Nodes = append([]CatalogNode(nil), c.Nodes...) + n.Edges = append([]CatalogEdge(nil), c.Edges...) + n.Candidates = append([]CatalogCandidate(nil), c.Candidates...) + n.Diagnostics = append([]CatalogDiagnostic(nil), c.Diagnostics...) + for i := range n.Candidates { + n.Candidates[i].ProjectionModes = append([]string(nil), n.Candidates[i].ProjectionModes...) + n.Candidates[i].FilterOperators = append([]string(nil), n.Candidates[i].FilterOperators...) + n.Candidates[i].ChartOperations = append([]string(nil), n.Candidates[i].ChartOperations...) + sort.Strings(n.Candidates[i].ProjectionModes) + sort.Strings(n.Candidates[i].FilterOperators) + sort.Strings(n.Candidates[i].ChartOperations) + } + sort.Slice(n.Nodes, func(i, j int) bool { return n.Nodes[i].ID < n.Nodes[j].ID }) + sort.Slice(n.Edges, func(i, j int) bool { return n.Edges[i].ID < n.Edges[j].ID }) + sort.Slice(n.Candidates, func(i, j int) bool { return n.Candidates[i].ID < n.Candidates[j].ID }) + sort.Slice(n.Diagnostics, func(i, j int) bool { + if n.Diagnostics[i].Code != n.Diagnostics[j].Code { + return n.Diagnostics[i].Code < n.Diagnostics[j].Code + } + return n.Diagnostics[i].Message < n.Diagnostics[j].Message + }) + return json.Marshal(n) +} + +func (c CatalogSnapshot) Digest() (string, error) { + raw, err := c.CanonicalJSON() + if err != nil { + return "", err + } + sum := sha256.Sum256(raw) + return "sha256:" + hex.EncodeToString(sum[:]), nil +} + +func (s BuilderState) CanonicalJSON() ([]byte, error) { + if err := s.Validate(); err != nil { + return nil, err + } + var workspace []byte + var err error + if s.Workspace == nil { + workspace = []byte("null") + } else { + workspace, err = s.Workspace.CanonicalJSON() + if err != nil { + return nil, err + } + } + catalog, err := s.Catalog.CanonicalJSON() + if err != nil { + return nil, err + } + return json.Marshal(struct { + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Workspace json.RawMessage `json:"workspace"` + Catalog json.RawMessage `json:"catalog"` + }{s.APIVersion, s.Kind, workspace, catalog}) +} + +func (s BuilderState) Digest() (string, error) { + raw, err := s.CanonicalJSON() + if err != nil { + return "", err + } + sum := sha256.Sum256(raw) + return "sha256:" + hex.EncodeToString(sum[:]), nil +} + +func DecodeWorkspace(raw []byte) (Workspace, error) { + var out Workspace + if err := strictDecode(raw, &out); err != nil { + return out, err + } + if err := out.Validate(); err != nil { + return out, err + } + for i := range out.Documents { + if out.Documents[i].Columns == nil { + out.Documents[i].Columns = []Column{} + } + } + return out, nil +} + +func strictDecode(raw []byte, target any) error { + if err := rejectDuplicateKeys(raw); err != nil { + return fmt.Errorf("strict decode: %w", err) + } + dec := json.NewDecoder(bytes.NewReader(raw)) + dec.DisallowUnknownFields() + if err := dec.Decode(target); err != nil { + return fmt.Errorf("strict decode: %w", err) + } + var trailing any + if err := dec.Decode(&trailing); err != io.EOF { + if err == nil { + return fmt.Errorf("strict decode: trailing JSON value") + } + return fmt.Errorf("strict decode: %w", err) + } + return nil +} + +func rejectDuplicateKeys(raw []byte) error { + dec := json.NewDecoder(bytes.NewReader(raw)) + var walk func() error + walk = func() error { + tok, err := dec.Token() + if err != nil { + return err + } + delim, ok := tok.(json.Delim) + if !ok { + return nil + } + switch delim { + case '{': + seen := map[string]bool{} + for dec.More() { + key, err := dec.Token() + if err != nil { + return err + } + name, ok := key.(string) + if !ok { + return fmt.Errorf("object key is not a string") + } + if seen[name] { + return fmt.Errorf("duplicate JSON key %q", name) + } + seen[name] = true + if err := walk(); err != nil { + return err + } + } + _, err = dec.Token() + return err + case '[': + for dec.More() { + if err := walk(); err != nil { + return err + } + } + _, err = dec.Token() + return err + } + return nil + } + if err := walk(); err != nil { + return err + } + return nil +} diff --git a/internal/explorer/authoringv2/semantic_types.go b/internal/explorer/authoringv2/semantic_types.go index dbd3823f..42ea285e 100644 --- a/internal/explorer/authoringv2/semantic_types.go +++ b/internal/explorer/authoringv2/semantic_types.go @@ -3,7 +3,6 @@ package authoringv2 import ( "fmt" "regexp" - "sort" "strings" ) @@ -244,9 +243,3 @@ func (w Workspace) validateSemanticBindings() error { } return nil } - -func sortedRouteChildren(children []RouteNode) []RouteNode { - result := append([]RouteNode(nil), children...) - sort.SliceStable(result, func(i, j int) bool { return result[i].OccurrenceID < result[j].OccurrenceID }) - return result -} diff --git a/internal/explorer/authoringv2/types.go b/internal/explorer/authoringv2/types.go index f7ef4d49..07baa2e3 100644 --- a/internal/explorer/authoringv2/types.go +++ b/internal/explorer/authoringv2/types.go @@ -4,48 +4,19 @@ package authoringv2 import ( - "bytes" - "crypto/sha256" - "encoding/hex" - "encoding/json" - "fmt" - "io" "net/url" - "sort" "strings" ) const ( - APIVersion = "loom.calypr.org/explorer-authoring/v2" - Kind = "ExplorerBuilderDocument" - WorkspaceKind = "ExplorerBuilderWorkspace" - StateKind = "ExplorerBuilderState" - CatalogKind = "ExplorerBuilderCatalog" - AuthoringV2APIVersion = APIVersion - ExplorerBuilderV2Kind = Kind - ExplorerBuilderStateV2Kind = StateKind - ExplorerBuilderCatalogV2Kind = CatalogKind - RootOccurrenceID = "base" + APIVersion = "loom.calypr.org/explorer-authoring/v2" + Kind = "ExplorerBuilderDocument" + WorkspaceKind = "ExplorerBuilderWorkspace" + StateKind = "ExplorerBuilderState" + CatalogKind = "ExplorerBuilderCatalog" + RootOccurrenceID = "base" ) -// Versioned aliases keep call sites explicit while retaining concise domain -// names inside this package. -type AuthoringDocumentV2 = Document -type ExplorerBuilderDocumentV2 = Document -type ExplorerBuilderWorkspaceV2 = Workspace -type BuilderStateV2 = BuilderState -type ExplorerBuilderStateV2 = BuilderState -type CatalogProjectionV2 = CatalogSnapshot -type ExplorerBuilderCatalogV2 = CatalogSnapshot -type RoutePolicyV2 = RoutePolicy -type RouteStepV2 = RouteStep -type SelectionV2 = Selection -type OutputV2 = Output -type PresentationV2 = Presentation -type CatalogNodeV2 = CatalogNode -type CatalogEdgeV2 = CatalogEdge -type CatalogCandidateV2 = CatalogCandidate - // Document is the complete durable Builder intent. A route is a finite edge // path from RootNodeID. Its root occurrence is always "base" and its tail is // computed from the path; neither is a second authored node identity. @@ -231,856 +202,3 @@ type RouteOccurrence struct { NodeID string IncomingEdgeID string } - -func (d Document) Occurrences(c CatalogSnapshot) ([]RouteOccurrence, error) { - if err := d.Validate(); err != nil { - return nil, err - } - edges := c.edgeIndex() - current := d.RootNodeID - occ := []RouteOccurrence{{ID: RootOccurrenceID, NodeID: current}} - for i, step := range d.RouteSteps { - e := edges[step.EdgeID] - if e == nil { - return nil, fmt.Errorf("route step %d references unknown edge %q", i, step.EdgeID) - } - if e.FromNodeID != current { - return nil, fmt.Errorf("route step %d is disconnected: edge starts at %q, expected %q", i, e.FromNodeID, current) - } - id := step.OccurrenceID - if id == "" { - id = DerivedOccurrenceID(i) - } - occ = append(occ, RouteOccurrence{ID: id, NodeID: e.ToNodeID, IncomingEdgeID: e.ID}) - current = e.ToNodeID - } - return occ, nil -} - -func (d Document) TailOccurrence(c CatalogSnapshot) (RouteOccurrence, error) { - occ, err := d.Occurrences(c) - if err != nil { - return RouteOccurrence{}, err - } - return occ[len(occ)-1], nil -} - -func (d Document) TailOccurrenceID(c CatalogSnapshot) (string, error) { - tail, err := d.TailOccurrence(c) - if err != nil { - return "", err - } - return tail.ID, nil -} - -func DerivedOccurrenceID(stepIndex int) string { - return fmt.Sprintf("step-%d", stepIndex+1) -} - -func (d Document) Validate() error { - if d.Kind != Kind { - return fmt.Errorf("unsupported V2 document protocol or kind") - } - if emptyID(d.Output.ID) || strings.TrimSpace(d.Output.Title) == "" { - return fmt.Errorf("output id and title are required") - } - if !physicalColumnPattern.MatchString(d.Output.ID) { - return fmt.Errorf("output id must contain only letters, digits, and underscores and may not start with a digit") - } - if d.semantic() { - return d.validateSemantic() - } - if emptyID(d.RootNodeID) { - return fmt.Errorf("rootNodeId is required") - } - seenOccurrences := map[string]bool{RootOccurrenceID: true} - for i, step := range d.RouteSteps { - if emptyID(step.EdgeID) { - return fmt.Errorf("routeSteps[%d].edgeId is required", i) - } - occurrenceID := step.OccurrenceID - if occurrenceID == "" { - occurrenceID = DerivedOccurrenceID(i) - } - if step.OccurrenceID != "" { - if step.OccurrenceID == RootOccurrenceID { - return fmt.Errorf("routeSteps[%d] cannot author the derived base occurrence", i) - } - if emptyID(step.OccurrenceID) { - return fmt.Errorf("routeSteps[%d].occurrenceId is invalid", i) - } - } - if seenOccurrences[occurrenceID] { - return fmt.Errorf("duplicate route occurrence id %q", occurrenceID) - } - seenOccurrences[occurrenceID] = true - } - seenSelections := map[string]bool{} - for i, selection := range d.Selections { - if emptyID(selection.CandidateID) { - return fmt.Errorf("selections[%d].candidateId is required", i) - } - if strings.TrimSpace(selection.ProjectionMode) == "" { - return fmt.Errorf("selections[%d].projectionMode is required", i) - } - if selection.OccurrenceID == "base" && selection.OccurrenceID != "" { /* base is valid */ - } - if selection.OccurrenceID != "" && emptyID(selection.OccurrenceID) { - return fmt.Errorf("selections[%d].occurrenceId is invalid", i) - } - key := selection.CandidateID + "\x00" + selection.OccurrenceID + "\x00" + selection.ProjectionMode - if seenSelections[key] { - return fmt.Errorf("duplicate selection %q", selection.CandidateID) - } - seenSelections[key] = true - } - for key, p := range d.Presentation { - if emptyID(key) { - return fmt.Errorf("presentation keys must be non-empty IDs") - } - if p.Order != nil && *p.Order < 0 { - return fmt.Errorf("presentation[%q].order must not be negative", key) - } - } - return nil -} - -func (w Workspace) Validate() error { - if w.APIVersion != APIVersion || w.Kind != WorkspaceKind { - return fmt.Errorf("unsupported V2 workspace protocol or kind") - } - semanticWorkspace := false - for _, document := range w.Documents { - semanticWorkspace = semanticWorkspace || document.semantic() - } - if semanticWorkspace && strings.TrimSpace(w.Explorer.Title) == "" { - return fmt.Errorf("explorer.title is required") - } - outputs, tabs, tabOutputs, orders := map[string]bool{}, map[string]bool{}, map[string]bool{}, map[int]bool{} - for i, d := range w.Documents { - if err := d.Validate(); err != nil { - return fmt.Errorf("documents[%d]: %w", i, err) - } - if outputs[d.Output.ID] { - return fmt.Errorf("DUPLICATE_OUTPUT_ID: documents[%d].output.id", i) - } - outputs[d.Output.ID] = true - } - for i, tab := range w.Tabs { - if emptyID(tab.ID) || strings.TrimSpace(tab.Title) == "" || emptyID(tab.OutputID) || tab.Order < 0 { - return fmt.Errorf("tabs[%d] is invalid", i) - } - if tabs[tab.ID] { - return fmt.Errorf("DUPLICATE_TAB_ID: tabs[%d].id", i) - } - if tabOutputs[tab.OutputID] || !outputs[tab.OutputID] { - return fmt.Errorf("INVALID_TAB_OUTPUT_MAPPING: tabs[%d].outputId", i) - } - if orders[tab.Order] { - return fmt.Errorf("INVALID_TAB_ORDER: tabs[%d].order", i) - } - tabs[tab.ID], tabOutputs[tab.OutputID], orders[tab.Order] = true, true, true - } - if len(w.Tabs) != len(w.Documents) { - return fmt.Errorf("INVALID_TAB_OUTPUT_MAPPING: exactly one tab is required per document") - } - for output := range outputs { - if !tabOutputs[output] { - return fmt.Errorf("INVALID_TAB_OUTPUT_MAPPING: output %q has no tab", output) - } - } - for i := 0; i < len(orders); i++ { - if !orders[i] { - return fmt.Errorf("INVALID_TAB_ORDER: orders must be contiguous from zero") - } - } - if err := w.validateSemanticBindings(); err != nil { - return err - } - return nil -} - -// ValidateForPublication applies constraints that are intentionally too strict -// for mutable Builder state. Changing a table root or route temporarily clears -// its selections; that intermediate workspace remains compilable, but a visible -// table must have at least one visible column before publication. -func (w Workspace) ValidateForPublication() error { - visibleOutputs := make(map[string]bool, len(w.Tabs)) - for _, tab := range w.Tabs { - visibleOutputs[tab.OutputID] = tab.Visible - } - for i, document := range w.Documents { - if !visibleOutputs[document.Output.ID] { - continue - } - if document.semantic() { - visible := 0 - for _, column := range document.Columns { - if column.Table != nil && (column.Table.Visible == nil || *column.Table.Visible) { - visible++ - } - } - if visible == 0 { - return fmt.Errorf("NO_VISIBLE_COLUMNS: documents[%d]", i) - } - continue - } - hidden := 0 - for _, presentation := range document.Presentation { - if presentation.Visible != nil && !*presentation.Visible { - hidden++ - } - } - if len(document.Selections) == 0 || hidden == len(document.Selections) { - return fmt.Errorf("NO_VISIBLE_COLUMNS: documents[%d]", i) - } - } - return nil -} - -func (c CatalogSnapshot) Validate() error { - if c.APIVersion != APIVersion || c.Kind != CatalogKind { - return fmt.Errorf("unsupported V2 catalog protocol or kind") - } - if strings.TrimSpace(c.SnapshotToken) == "" { - return fmt.Errorf("catalog snapshotToken is required") - } - if strings.TrimSpace(c.Project) == "" || strings.TrimSpace(c.ExplorerID) == "" || strings.TrimSpace(c.SourceGeneration) == "" || strings.TrimSpace(c.AuthorizationScopeDigest) == "" { - return fmt.Errorf("catalog project, explorerId, sourceGeneration, and authorizationScopeDigest are required") - } - if !c.Complete || c.Truncated { - return fmt.Errorf("catalog snapshot is incomplete or truncated") - } - if c.RoutePolicy.MaxHops != nil && *c.RoutePolicy.MaxHops < 0 { - return fmt.Errorf("routePolicy.maxHops must not be negative") - } - if c.RoutePolicy.MaxHops == nil && !c.RoutePolicy.Unbounded { - return fmt.Errorf("routePolicy must explicitly declare an unbounded route when maxHops is absent") - } - if c.RoutePolicy.MaxHops != nil && c.RoutePolicy.Unbounded { - return fmt.Errorf("routePolicy cannot be both bounded and unbounded") - } - nodes := map[string]CatalogNode{} - for i, n := range c.Nodes { - if emptyID(n.ID) || strings.TrimSpace(n.ResourceType) == "" { - return fmt.Errorf("nodes[%d] is invalid", i) - } - if _, ok := nodes[n.ID]; ok { - return fmt.Errorf("duplicate catalog node %q", n.ID) - } - nodes[n.ID] = n - } - edges := map[string]CatalogEdge{} - for i, e := range c.Edges { - if emptyID(e.ID) || nodes[e.FromNodeID].ID == "" || nodes[e.ToNodeID].ID == "" { - return fmt.Errorf("edges[%d] has stale node reference", i) - } - if _, ok := edges[e.ID]; ok { - return fmt.Errorf("duplicate catalog edge %q", e.ID) - } - if e.FromNodeID == e.ToNodeID && !c.RoutePolicy.AllowSelfLoops { - return fmt.Errorf("self-loop edge %q is not allowed by route policy", e.ID) - } - edges[e.ID] = e - } - candidates := map[string]CatalogCandidate{} - for i, candidate := range c.Candidates { - if emptyID(candidate.ID) || nodes[candidate.NodeID].ID == "" { - return fmt.Errorf("candidates[%d] has stale node reference", i) - } - if _, ok := candidates[candidate.ID]; ok { - return fmt.Errorf("duplicate catalog candidate %q", candidate.ID) - } - if len(candidate.ProjectionModes) == 0 || candidate.DefaultProjectionMode == "" { - return fmt.Errorf("candidate %q must advertise projection modes and a default", candidate.ID) - } - if candidate.DefaultProjectionMode != "" { - foundMode := false - for _, mode := range candidate.ProjectionModes { - if strings.TrimSpace(mode) == "" { - return fmt.Errorf("candidates[%d] contains an empty projection mode", i) - } - if mode == candidate.DefaultProjectionMode { - foundMode = true - } - } - if len(candidate.ProjectionModes) > 0 && !foundMode { - return fmt.Errorf("candidate %q default projection mode is not listed", candidate.ID) - } - } - if candidate.Count != nil && *candidate.Count < 0 { - return fmt.Errorf("candidate %q count must not be negative", candidate.ID) - } - if candidate.SuggestionCount < 0 { - return fmt.Errorf("candidate %q suggestionCount must not be negative", candidate.ID) - } - if candidate.SuggestionsComplete && candidate.SuggestionsTruncated { - return fmt.Errorf("candidate %q suggestions cannot be complete and truncated", candidate.ID) - } - candidates[candidate.ID] = candidate - } - return nil -} - -func (s BuilderState) Validate() error { - if s.DraftVersion < 0 { - return fmt.Errorf("draftVersion must not be negative") - } - if s.APIVersion != APIVersion || s.Kind != StateKind { - return fmt.Errorf("unsupported V2 builder state protocol or kind") - } - if err := s.Catalog.Validate(); err != nil { - return err - } - if s.LifecycleState == "" { - if s.Workspace == nil { - s.LifecycleState = LifecycleNew - } else { - s.LifecycleState = LifecycleReady - } - } - if s.LifecycleState != LifecycleNew && s.LifecycleState != LifecycleReady { - return fmt.Errorf("unsupported lifecycleState %q", s.LifecycleState) - } - if s.LifecycleState == LifecycleNew && s.Workspace != nil { - return fmt.Errorf("NEW Builder state must have workspace null") - } - if s.LifecycleState == LifecycleReady && s.Workspace == nil { - return fmt.Errorf("READY Builder state requires workspace") - } - workspace := s.Workspace - if workspace == nil && s.Document != nil { - workspace = &Workspace{APIVersion: APIVersion, Kind: WorkspaceKind, Documents: []Document{*s.Document}, Tabs: []Tab{{ID: s.Document.Output.ID, Title: s.Document.Output.Title, OutputID: s.Document.Output.ID, Order: 0, Visible: true}}} - } - if workspace == nil { - return nil - } - if err := workspace.Validate(); err != nil { - return err - } - for i := range workspace.Documents { - document := workspace.Documents[i] - if document.semantic() { - continue - } - one := s - one.Workspace = nil - one.Document = &document - if err := one.validateDocument(); err != nil { - return fmt.Errorf("documents[%d]: %w", i, err) - } - } - return nil -} - -func (s BuilderState) validateDocument() error { - d := s.Document - if d == nil { - return nil - } - edges, candidates, nodes := s.Catalog.edgeIndex(), s.Catalog.candidateIndex(), s.Catalog.nodeIndex() - if nodes[d.RootNodeID].ID == "" { - return fmt.Errorf("document rootNodeId %q is stale", d.RootNodeID) - } - if !nodes[d.RootNodeID].RowRootEligible { - return fmt.Errorf("ROW_ROOT_NOT_ELIGIBLE: rootNodeId %q", d.RootNodeID) - } - seenEdges := map[string]bool{} - current := d.RootNodeID - for i, step := range d.RouteSteps { - e, ok := edges[step.EdgeID] - if !ok { - return fmt.Errorf("routeSteps[%d] references stale edge %q", i, step.EdgeID) - } - if e.FromNodeID != current { - return fmt.Errorf("routeSteps[%d] is disconnected: edge starts at %q, expected %q", i, e.FromNodeID, current) - } - if seenEdges[e.ID] && !s.Catalog.RoutePolicy.AllowRepeatedEdges { - return fmt.Errorf("repeated edge %q is not allowed by route policy", e.ID) - } - seenEdges[e.ID] = true - current = e.ToNodeID - } - if s.Catalog.RoutePolicy.MaxHops != nil && len(d.RouteSteps) > *s.Catalog.RoutePolicy.MaxHops { - return fmt.Errorf("route exceeds routePolicy.maxHops") - } - occ, err := d.Occurrences(s.Catalog) - if err != nil { - return err - } - occByID := map[string]RouteOccurrence{} - for _, item := range occ { - occByID[item.ID] = item - } - for i, selection := range d.Selections { - candidate, ok := candidates[selection.CandidateID] - if !ok { - return fmt.Errorf("selections[%d] references stale candidate %q", i, selection.CandidateID) - } - id := selection.OccurrenceID - if id == "" { - id = occ[len(occ)-1].ID - } - item, ok := occByID[id] - if !ok { - return fmt.Errorf("selections[%d] references stale occurrence %q", i, id) - } - if candidate.NodeID != item.NodeID { - return fmt.Errorf("selection %q belongs to node %q, not occurrence %q node %q", selection.CandidateID, candidate.NodeID, id, item.NodeID) - } - projectionAllowed := false - for _, mode := range candidate.ProjectionModes { - if selection.ProjectionMode == mode { - projectionAllowed = true - break - } - } - if !projectionAllowed { - return fmt.Errorf("selection %q projection mode %q is not advertised", selection.CandidateID, selection.ProjectionMode) - } - } - seenResolvedSelections := map[string]bool{} - for i, selection := range d.Selections { - occurrenceID := effectiveOccurrence(*d, s.Catalog, selection.OccurrenceID) - key := selection.CandidateID + "\x00" + occurrenceID + "\x00" + selection.ProjectionMode - if seenResolvedSelections[key] { - return fmt.Errorf("duplicate selection at selections[%d]", i) - } - seenResolvedSelections[key] = true - } - selectionKeys := map[string]bool{} - for _, selection := range d.Selections { - selectionKeys[PresentationKey(selection.CandidateID, effectiveOccurrence(*d, s.Catalog, selection.OccurrenceID), selection.ProjectionMode)] = true - } - for key, p := range d.Presentation { - if !selectionKeys[key] { - return fmt.Errorf("presentation %q does not resolve to a selection", key) - } - for _, selection := range d.Selections { - if PresentationKey(selection.CandidateID, effectiveOccurrence(*d, s.Catalog, selection.OccurrenceID), selection.ProjectionMode) != key { - continue - } - candidate := candidates[selection.CandidateID] - if p.Filter != nil && !candidate.Filterable { - return fmt.Errorf("UNSUPPORTED_FILTER: presentation %q", key) - } - if p.Chart != nil && !candidate.Chartable { - return fmt.Errorf("UNSUPPORTED_CHART: presentation %q", key) - } - } - } - return nil -} - -func effectiveOccurrence(d Document, c CatalogSnapshot, authored string) string { - if authored != "" { - return authored - } - occ, err := d.Occurrences(c) - if err != nil || len(occ) == 0 { - return authored - } - return occ[len(occ)-1].ID -} - -func (c CatalogSnapshot) nodeIndex() map[string]CatalogNode { - out := map[string]CatalogNode{} - for _, n := range c.Nodes { - out[n.ID] = n - } - return out -} -func (c CatalogSnapshot) edgeIndex() map[string]*CatalogEdge { - out := map[string]*CatalogEdge{} - for i := range c.Edges { - out[c.Edges[i].ID] = &c.Edges[i] - } - return out -} -func (c CatalogSnapshot) candidateIndex() map[string]CatalogCandidate { - out := map[string]CatalogCandidate{} - for _, n := range c.Candidates { - out[n.ID] = n - } - return out -} - -func emptyID(value string) bool { - return strings.TrimSpace(value) == "" || value != strings.TrimSpace(value) -} - -// CanonicalJSON and Digest provide content-addressed, deterministic wire -// representations. Catalog collections and unordered selections are sorted; -// routeSteps retain their authored path order. -func (d Document) CanonicalJSON() ([]byte, error) { - if err := d.Validate(); err != nil { - return nil, err - } - n := d - n.RouteSteps = append([]RouteStep(nil), d.RouteSteps...) - n.Selections = append([]Selection(nil), d.Selections...) - sort.SliceStable(n.Selections, func(i, j int) bool { - left := n.Selections[i].CandidateID + "\x00" + n.Selections[i].OccurrenceID - right := n.Selections[j].CandidateID + "\x00" + n.Selections[j].OccurrenceID - return left < right - }) - if n.RouteSteps == nil { - n.RouteSteps = []RouteStep{} - } - if n.Selections == nil { - n.Selections = []Selection{} - } - if n.Presentation == nil { - n.Presentation = map[string]Presentation{} - } - return json.Marshal(n) -} - -func (w Workspace) CanonicalJSON() ([]byte, error) { - if err := w.Validate(); err != nil { - return nil, err - } - n := w.NormalizePresentationOrders() - n.Documents = append([]Document(nil), n.Documents...) - for i := range n.Documents { - n.Documents[i].APIVersion = "" - if n.Documents[i].Columns == nil { - n.Documents[i].Columns = []Column{} - } - n.Documents[i].Selections = append([]Selection(nil), n.Documents[i].Selections...) - sort.SliceStable(n.Documents[i].Selections, func(a, b int) bool { - left := n.Documents[i].Selections[a] - right := n.Documents[i].Selections[b] - return left.CandidateID+"\x00"+left.OccurrenceID+"\x00"+left.ProjectionMode < right.CandidateID+"\x00"+right.OccurrenceID+"\x00"+right.ProjectionMode - }) - if n.Documents[i].RouteSteps == nil { - n.Documents[i].RouteSteps = []RouteStep{} - } - if n.Documents[i].Selections == nil { - n.Documents[i].Selections = []Selection{} - } - if n.Documents[i].Presentation == nil { - n.Documents[i].Presentation = map[string]Presentation{} - } - } - n.Tabs = append([]Tab(nil), w.Tabs...) - if n.Documents == nil { - n.Documents = []Document{} - } - if n.Tabs == nil { - n.Tabs = []Tab{} - } - return json.Marshal(n) -} - -// NormalizePresentationOrders gives every table column one unambiguous, -// contiguous presentation position. Authored order is the primary key and the -// stable public column identity breaks ties. The normalized order also becomes -// the recipe projection order, so presentation and execution cannot disagree. -// -// Duplicate presentation positions are valid mutable Builder input. Freezing -// them here keeps equivalent requests from depending on frontend collection or -// map iteration order and makes the normalized workspace safe to persist and -// return to the Builder. -func (w Workspace) NormalizePresentationOrders() Workspace { - n := w - n.Documents = append([]Document(nil), w.Documents...) - for documentIndex := range n.Documents { - document := &n.Documents[documentIndex] - columns := append([]Column(nil), document.Columns...) - if columns == nil { - columns = []Column{} - } - for columnIndex := range columns { - column := &columns[columnIndex] - if column.Table != nil { - table := *column.Table - column.Table = &table - } - if column.Filter != nil { - filter := *column.Filter - column.Filter = &filter - } - if column.Chart != nil { - chart := *column.Chart - column.Chart = &chart - } - } - sort.SliceStable(columns, func(i, j int) bool { - left, right := columns[i], columns[j] - leftClass, leftOrder := presentationOrder(left) - rightClass, rightOrder := presentationOrder(right) - if leftClass != rightClass { - return leftClass < rightClass - } - if leftOrder != rightOrder { - return leftOrder < rightOrder - } - return left.Column < right.Column - }) - tableOrder := 0 - for columnIndex := range columns { - if columns[columnIndex].Table == nil { - continue - } - value := tableOrder - columns[columnIndex].Table.Order = &value - tableOrder++ - } - normalizeFilterOrders(columns) - normalizeChartOrders(columns) - document.Columns = columns - } - return n -} - -func normalizeFilterOrders(columns []Column) { - indexes := make([]int, 0, len(columns)) - for index := range columns { - if columns[index].Filter != nil { - indexes = append(indexes, index) - } - } - sort.SliceStable(indexes, func(i, j int) bool { - left, right := columns[indexes[i]], columns[indexes[j]] - return auxiliaryPresentationLess(left.Filter.Order, left.Column, right.Filter.Order, right.Column) - }) - for order, index := range indexes { - value := order - columns[index].Filter.Order = &value - } -} - -func normalizeChartOrders(columns []Column) { - indexes := make([]int, 0, len(columns)) - for index := range columns { - if columns[index].Chart != nil { - indexes = append(indexes, index) - } - } - sort.SliceStable(indexes, func(i, j int) bool { - left, right := columns[indexes[i]], columns[indexes[j]] - return auxiliaryPresentationLess(left.Chart.Order, left.Column, right.Chart.Order, right.Column) - }) - for order, index := range indexes { - value := order - columns[index].Chart.Order = &value - } -} - -func auxiliaryPresentationLess(leftOrder *int, leftColumn string, rightOrder *int, rightColumn string) bool { - if (leftOrder == nil) != (rightOrder == nil) { - return leftOrder != nil - } - if leftOrder != nil && *leftOrder != *rightOrder { - return *leftOrder < *rightOrder - } - return leftColumn < rightColumn -} - -func presentationOrder(column Column) (class, order int) { - if column.Table == nil { - return 2, 0 - } - if column.Table.Order == nil { - return 1, 0 - } - return 0, *column.Table.Order -} - -func (w Workspace) Digest() (string, error) { - raw, err := w.CanonicalJSON() - if err != nil { - return "", err - } - sum := sha256.Sum256(raw) - return "sha256:" + hex.EncodeToString(sum[:]), nil -} - -func (d Document) Digest() (string, error) { - raw, err := d.CanonicalJSON() - if err != nil { - return "", err - } - sum := sha256.Sum256(raw) - return "sha256:" + hex.EncodeToString(sum[:]), nil -} - -func (c CatalogSnapshot) CanonicalJSON() ([]byte, error) { - if err := c.Validate(); err != nil { - return nil, err - } - n := c - n.Nodes = append([]CatalogNode(nil), c.Nodes...) - n.Edges = append([]CatalogEdge(nil), c.Edges...) - n.Candidates = append([]CatalogCandidate(nil), c.Candidates...) - n.Diagnostics = append([]CatalogDiagnostic(nil), c.Diagnostics...) - for i := range n.Candidates { - n.Candidates[i].ProjectionModes = append([]string(nil), n.Candidates[i].ProjectionModes...) - n.Candidates[i].FilterOperators = append([]string(nil), n.Candidates[i].FilterOperators...) - n.Candidates[i].ChartOperations = append([]string(nil), n.Candidates[i].ChartOperations...) - sort.Strings(n.Candidates[i].ProjectionModes) - sort.Strings(n.Candidates[i].FilterOperators) - sort.Strings(n.Candidates[i].ChartOperations) - } - sort.Slice(n.Nodes, func(i, j int) bool { return n.Nodes[i].ID < n.Nodes[j].ID }) - sort.Slice(n.Edges, func(i, j int) bool { return n.Edges[i].ID < n.Edges[j].ID }) - sort.Slice(n.Candidates, func(i, j int) bool { return n.Candidates[i].ID < n.Candidates[j].ID }) - sort.Slice(n.Diagnostics, func(i, j int) bool { - if n.Diagnostics[i].Code != n.Diagnostics[j].Code { - return n.Diagnostics[i].Code < n.Diagnostics[j].Code - } - return n.Diagnostics[i].Message < n.Diagnostics[j].Message - }) - return json.Marshal(n) -} - -func (c CatalogSnapshot) Digest() (string, error) { - raw, err := c.CanonicalJSON() - if err != nil { - return "", err - } - sum := sha256.Sum256(raw) - return "sha256:" + hex.EncodeToString(sum[:]), nil -} - -func (s BuilderState) CanonicalJSON() ([]byte, error) { - if err := s.Validate(); err != nil { - return nil, err - } - var workspace []byte - var err error - if s.Workspace == nil { - workspace = []byte("null") - } else { - workspace, err = s.Workspace.CanonicalJSON() - if err != nil { - return nil, err - } - } - catalog, err := s.Catalog.CanonicalJSON() - if err != nil { - return nil, err - } - return json.Marshal(struct { - APIVersion string `json:"apiVersion"` - Kind string `json:"kind"` - Workspace json.RawMessage `json:"workspace"` - Catalog json.RawMessage `json:"catalog"` - }{s.APIVersion, s.Kind, workspace, catalog}) -} - -func (s BuilderState) Digest() (string, error) { - raw, err := s.CanonicalJSON() - if err != nil { - return "", err - } - sum := sha256.Sum256(raw) - return "sha256:" + hex.EncodeToString(sum[:]), nil -} - -func DecodeDocument(raw []byte) (Document, error) { - var wire struct { - APIVersion string `json:"apiVersion,omitempty"` - Kind string `json:"kind"` - Output Output `json:"output"` - RootNodeID string `json:"rootNodeId"` - RouteSteps []RouteStep `json:"routeSteps"` - Selections []Selection `json:"selections"` - Presentation map[string]Presentation `json:"presentation"` - } - if err := strictDecode(raw, &wire); err != nil { - return Document{}, err - } - out := Document{APIVersion: wire.APIVersion, Kind: wire.Kind, Output: wire.Output, RootNodeID: wire.RootNodeID, RouteSteps: wire.RouteSteps, Selections: wire.Selections, Presentation: wire.Presentation} - if err := out.Validate(); err != nil { - return out, err - } - return out, nil -} - -func DecodeWorkspace(raw []byte) (Workspace, error) { - var out Workspace - if err := strictDecode(raw, &out); err != nil { - return out, err - } - if err := out.Validate(); err != nil { - return out, err - } - for i := range out.Documents { - if out.Documents[i].Columns == nil { - out.Documents[i].Columns = []Column{} - } - } - return out, nil -} - -func strictDecode(raw []byte, target any) error { - if err := rejectDuplicateKeys(raw); err != nil { - return fmt.Errorf("strict decode: %w", err) - } - dec := json.NewDecoder(bytes.NewReader(raw)) - dec.DisallowUnknownFields() - if err := dec.Decode(target); err != nil { - return fmt.Errorf("strict decode: %w", err) - } - var trailing any - if err := dec.Decode(&trailing); err != io.EOF { - if err == nil { - return fmt.Errorf("strict decode: trailing JSON value") - } - return fmt.Errorf("strict decode: %w", err) - } - return nil -} - -func rejectDuplicateKeys(raw []byte) error { - dec := json.NewDecoder(bytes.NewReader(raw)) - var walk func() error - walk = func() error { - tok, err := dec.Token() - if err != nil { - return err - } - delim, ok := tok.(json.Delim) - if !ok { - return nil - } - switch delim { - case '{': - seen := map[string]bool{} - for dec.More() { - key, err := dec.Token() - if err != nil { - return err - } - name, ok := key.(string) - if !ok { - return fmt.Errorf("object key is not a string") - } - if seen[name] { - return fmt.Errorf("duplicate JSON key %q", name) - } - seen[name] = true - if err := walk(); err != nil { - return err - } - } - _, err = dec.Token() - return err - case '[': - for dec.More() { - if err := walk(); err != nil { - return err - } - } - _, err = dec.Token() - return err - } - return nil - } - if err := walk(); err != nil { - return err - } - return nil -} diff --git a/internal/explorer/authoringv2/types_test.go b/internal/explorer/authoringv2/types_test.go index 5d86f1bf..1e00188a 100644 --- a/internal/explorer/authoringv2/types_test.go +++ b/internal/explorer/authoringv2/types_test.go @@ -70,21 +70,6 @@ func TestBuilderStateRejectsStaleAndDuplicateStructure(t *testing.T) { } } -func TestStrictV2DecodeRejectsUnknownDuplicateAndTrailingFields(t *testing.T) { - raw := `{"apiVersion":"` + APIVersion + `","kind":"ExplorerBuilderDocument","output":{"id":"out","title":"Title"},"rootNodeId":"patient","routeSteps":[],"selections":[],"presentation":{},"aql":"for x in c return x"}` - if _, err := DecodeDocument([]byte(raw)); err == nil || !strings.Contains(err.Error(), "unknown field") { - t.Fatalf("unknown field error=%v", err) - } - raw = strings.Replace(raw, `,"aql":"for x in c return x"`, `,"presentation":{},"presentation":{}`, 1) - if _, err := DecodeDocument([]byte(raw)); err == nil || !strings.Contains(err.Error(), "duplicate JSON key") { - t.Fatalf("duplicate field error=%v", err) - } - valid := `{"apiVersion":"` + APIVersion + `","kind":"ExplorerBuilderDocument","output":{"id":"out","title":"Title"},"rootNodeId":"patient","routeSteps":[],"selections":[],"presentation":{}} {}` - if _, err := DecodeDocument([]byte(valid)); err == nil || !strings.Contains(err.Error(), "trailing JSON") { - t.Fatalf("trailing value error=%v", err) - } -} - func TestCanonicalizationAndDigestAreStableAcrossUnorderedCollections(t *testing.T) { first := testDocument() second := testDocument() diff --git a/internal/explorer/authoringv2/validation.go b/internal/explorer/authoringv2/validation.go new file mode 100644 index 00000000..a9cbd589 --- /dev/null +++ b/internal/explorer/authoringv2/validation.go @@ -0,0 +1,487 @@ +package authoringv2 + +import ( + "fmt" + "strings" +) + +func (d Document) Occurrences(c CatalogSnapshot) ([]RouteOccurrence, error) { + if err := d.Validate(); err != nil { + return nil, err + } + edges := c.edgeIndex() + current := d.RootNodeID + occ := []RouteOccurrence{{ID: RootOccurrenceID, NodeID: current}} + for i, step := range d.RouteSteps { + e := edges[step.EdgeID] + if e == nil { + return nil, fmt.Errorf("route step %d references unknown edge %q", i, step.EdgeID) + } + if e.FromNodeID != current { + return nil, fmt.Errorf("route step %d is disconnected: edge starts at %q, expected %q", i, e.FromNodeID, current) + } + id := step.OccurrenceID + if id == "" { + id = DerivedOccurrenceID(i) + } + occ = append(occ, RouteOccurrence{ID: id, NodeID: e.ToNodeID, IncomingEdgeID: e.ID}) + current = e.ToNodeID + } + return occ, nil +} + +func (d Document) TailOccurrence(c CatalogSnapshot) (RouteOccurrence, error) { + occ, err := d.Occurrences(c) + if err != nil { + return RouteOccurrence{}, err + } + return occ[len(occ)-1], nil +} + +func (d Document) TailOccurrenceID(c CatalogSnapshot) (string, error) { + tail, err := d.TailOccurrence(c) + if err != nil { + return "", err + } + return tail.ID, nil +} + +func DerivedOccurrenceID(stepIndex int) string { + return fmt.Sprintf("step-%d", stepIndex+1) +} + +func (d Document) Validate() error { + if d.Kind != Kind { + return fmt.Errorf("unsupported V2 document protocol or kind") + } + if emptyID(d.Output.ID) || strings.TrimSpace(d.Output.Title) == "" { + return fmt.Errorf("output id and title are required") + } + if !physicalColumnPattern.MatchString(d.Output.ID) { + return fmt.Errorf("output id must contain only letters, digits, and underscores and may not start with a digit") + } + if d.semantic() { + return d.validateSemantic() + } + if emptyID(d.RootNodeID) { + return fmt.Errorf("rootNodeId is required") + } + seenOccurrences := map[string]bool{RootOccurrenceID: true} + for i, step := range d.RouteSteps { + if emptyID(step.EdgeID) { + return fmt.Errorf("routeSteps[%d].edgeId is required", i) + } + occurrenceID := step.OccurrenceID + if occurrenceID == "" { + occurrenceID = DerivedOccurrenceID(i) + } + if step.OccurrenceID != "" { + if step.OccurrenceID == RootOccurrenceID { + return fmt.Errorf("routeSteps[%d] cannot author the derived base occurrence", i) + } + if emptyID(step.OccurrenceID) { + return fmt.Errorf("routeSteps[%d].occurrenceId is invalid", i) + } + } + if seenOccurrences[occurrenceID] { + return fmt.Errorf("duplicate route occurrence id %q", occurrenceID) + } + seenOccurrences[occurrenceID] = true + } + seenSelections := map[string]bool{} + for i, selection := range d.Selections { + if emptyID(selection.CandidateID) { + return fmt.Errorf("selections[%d].candidateId is required", i) + } + if strings.TrimSpace(selection.ProjectionMode) == "" { + return fmt.Errorf("selections[%d].projectionMode is required", i) + } + if selection.OccurrenceID == "base" && selection.OccurrenceID != "" { /* base is valid */ + } + if selection.OccurrenceID != "" && emptyID(selection.OccurrenceID) { + return fmt.Errorf("selections[%d].occurrenceId is invalid", i) + } + key := selection.CandidateID + "\x00" + selection.OccurrenceID + "\x00" + selection.ProjectionMode + if seenSelections[key] { + return fmt.Errorf("duplicate selection %q", selection.CandidateID) + } + seenSelections[key] = true + } + for key, p := range d.Presentation { + if emptyID(key) { + return fmt.Errorf("presentation keys must be non-empty IDs") + } + if p.Order != nil && *p.Order < 0 { + return fmt.Errorf("presentation[%q].order must not be negative", key) + } + } + return nil +} + +func (w Workspace) Validate() error { + if w.APIVersion != APIVersion || w.Kind != WorkspaceKind { + return fmt.Errorf("unsupported V2 workspace protocol or kind") + } + semanticWorkspace := false + for _, document := range w.Documents { + semanticWorkspace = semanticWorkspace || document.semantic() + } + if semanticWorkspace && strings.TrimSpace(w.Explorer.Title) == "" { + return fmt.Errorf("explorer.title is required") + } + outputs, tabs, tabOutputs, orders := map[string]bool{}, map[string]bool{}, map[string]bool{}, map[int]bool{} + for i, d := range w.Documents { + if err := d.Validate(); err != nil { + return fmt.Errorf("documents[%d]: %w", i, err) + } + if outputs[d.Output.ID] { + return fmt.Errorf("DUPLICATE_OUTPUT_ID: documents[%d].output.id", i) + } + outputs[d.Output.ID] = true + } + for i, tab := range w.Tabs { + if emptyID(tab.ID) || strings.TrimSpace(tab.Title) == "" || emptyID(tab.OutputID) || tab.Order < 0 { + return fmt.Errorf("tabs[%d] is invalid", i) + } + if tabs[tab.ID] { + return fmt.Errorf("DUPLICATE_TAB_ID: tabs[%d].id", i) + } + if tabOutputs[tab.OutputID] || !outputs[tab.OutputID] { + return fmt.Errorf("INVALID_TAB_OUTPUT_MAPPING: tabs[%d].outputId", i) + } + if orders[tab.Order] { + return fmt.Errorf("INVALID_TAB_ORDER: tabs[%d].order", i) + } + tabs[tab.ID], tabOutputs[tab.OutputID], orders[tab.Order] = true, true, true + } + if len(w.Tabs) != len(w.Documents) { + return fmt.Errorf("INVALID_TAB_OUTPUT_MAPPING: exactly one tab is required per document") + } + for output := range outputs { + if !tabOutputs[output] { + return fmt.Errorf("INVALID_TAB_OUTPUT_MAPPING: output %q has no tab", output) + } + } + for i := 0; i < len(orders); i++ { + if !orders[i] { + return fmt.Errorf("INVALID_TAB_ORDER: orders must be contiguous from zero") + } + } + if err := w.validateSemanticBindings(); err != nil { + return err + } + return nil +} + +// ValidateForPublication applies constraints that are intentionally too strict +// for mutable Builder state. Changing a table root or route temporarily clears +// its selections; that intermediate workspace remains compilable, but a visible +// table must have at least one visible column before publication. +func (w Workspace) ValidateForPublication() error { + visibleOutputs := make(map[string]bool, len(w.Tabs)) + for _, tab := range w.Tabs { + visibleOutputs[tab.OutputID] = tab.Visible + } + for i, document := range w.Documents { + if !visibleOutputs[document.Output.ID] { + continue + } + if document.semantic() { + visible := 0 + for _, column := range document.Columns { + if column.Table != nil && (column.Table.Visible == nil || *column.Table.Visible) { + visible++ + } + } + if visible == 0 { + return fmt.Errorf("NO_VISIBLE_COLUMNS: documents[%d]", i) + } + continue + } + hidden := 0 + for _, presentation := range document.Presentation { + if presentation.Visible != nil && !*presentation.Visible { + hidden++ + } + } + if len(document.Selections) == 0 || hidden == len(document.Selections) { + return fmt.Errorf("NO_VISIBLE_COLUMNS: documents[%d]", i) + } + } + return nil +} + +func (c CatalogSnapshot) Validate() error { + if c.APIVersion != APIVersion || c.Kind != CatalogKind { + return fmt.Errorf("unsupported V2 catalog protocol or kind") + } + if strings.TrimSpace(c.SnapshotToken) == "" { + return fmt.Errorf("catalog snapshotToken is required") + } + if strings.TrimSpace(c.Project) == "" || strings.TrimSpace(c.ExplorerID) == "" || strings.TrimSpace(c.SourceGeneration) == "" || strings.TrimSpace(c.AuthorizationScopeDigest) == "" { + return fmt.Errorf("catalog project, explorerId, sourceGeneration, and authorizationScopeDigest are required") + } + if !c.Complete || c.Truncated { + return fmt.Errorf("catalog snapshot is incomplete or truncated") + } + if c.RoutePolicy.MaxHops != nil && *c.RoutePolicy.MaxHops < 0 { + return fmt.Errorf("routePolicy.maxHops must not be negative") + } + if c.RoutePolicy.MaxHops == nil && !c.RoutePolicy.Unbounded { + return fmt.Errorf("routePolicy must explicitly declare an unbounded route when maxHops is absent") + } + if c.RoutePolicy.MaxHops != nil && c.RoutePolicy.Unbounded { + return fmt.Errorf("routePolicy cannot be both bounded and unbounded") + } + nodes := map[string]CatalogNode{} + for i, n := range c.Nodes { + if emptyID(n.ID) || strings.TrimSpace(n.ResourceType) == "" { + return fmt.Errorf("nodes[%d] is invalid", i) + } + if _, ok := nodes[n.ID]; ok { + return fmt.Errorf("duplicate catalog node %q", n.ID) + } + nodes[n.ID] = n + } + edges := map[string]CatalogEdge{} + for i, e := range c.Edges { + if emptyID(e.ID) || nodes[e.FromNodeID].ID == "" || nodes[e.ToNodeID].ID == "" { + return fmt.Errorf("edges[%d] has stale node reference", i) + } + if _, ok := edges[e.ID]; ok { + return fmt.Errorf("duplicate catalog edge %q", e.ID) + } + if e.FromNodeID == e.ToNodeID && !c.RoutePolicy.AllowSelfLoops { + return fmt.Errorf("self-loop edge %q is not allowed by route policy", e.ID) + } + edges[e.ID] = e + } + candidates := map[string]CatalogCandidate{} + for i, candidate := range c.Candidates { + if emptyID(candidate.ID) || nodes[candidate.NodeID].ID == "" { + return fmt.Errorf("candidates[%d] has stale node reference", i) + } + if _, ok := candidates[candidate.ID]; ok { + return fmt.Errorf("duplicate catalog candidate %q", candidate.ID) + } + if len(candidate.ProjectionModes) == 0 || candidate.DefaultProjectionMode == "" { + return fmt.Errorf("candidate %q must advertise projection modes and a default", candidate.ID) + } + if candidate.DefaultProjectionMode != "" { + foundMode := false + for _, mode := range candidate.ProjectionModes { + if strings.TrimSpace(mode) == "" { + return fmt.Errorf("candidates[%d] contains an empty projection mode", i) + } + if mode == candidate.DefaultProjectionMode { + foundMode = true + } + } + if len(candidate.ProjectionModes) > 0 && !foundMode { + return fmt.Errorf("candidate %q default projection mode is not listed", candidate.ID) + } + } + if candidate.Count != nil && *candidate.Count < 0 { + return fmt.Errorf("candidate %q count must not be negative", candidate.ID) + } + if candidate.SuggestionCount < 0 { + return fmt.Errorf("candidate %q suggestionCount must not be negative", candidate.ID) + } + if candidate.SuggestionsComplete && candidate.SuggestionsTruncated { + return fmt.Errorf("candidate %q suggestions cannot be complete and truncated", candidate.ID) + } + candidates[candidate.ID] = candidate + } + return nil +} + +func (s BuilderState) Validate() error { + if s.DraftVersion < 0 { + return fmt.Errorf("draftVersion must not be negative") + } + if s.APIVersion != APIVersion || s.Kind != StateKind { + return fmt.Errorf("unsupported V2 builder state protocol or kind") + } + if err := s.Catalog.Validate(); err != nil { + return err + } + if s.LifecycleState == "" { + if s.Workspace == nil { + s.LifecycleState = LifecycleNew + } else { + s.LifecycleState = LifecycleReady + } + } + if s.LifecycleState != LifecycleNew && s.LifecycleState != LifecycleReady { + return fmt.Errorf("unsupported lifecycleState %q", s.LifecycleState) + } + if s.LifecycleState == LifecycleNew && s.Workspace != nil { + return fmt.Errorf("NEW Builder state must have workspace null") + } + if s.LifecycleState == LifecycleReady && s.Workspace == nil { + return fmt.Errorf("READY Builder state requires workspace") + } + workspace := s.Workspace + if workspace == nil && s.Document != nil { + workspace = &Workspace{APIVersion: APIVersion, Kind: WorkspaceKind, Documents: []Document{*s.Document}, Tabs: []Tab{{ID: s.Document.Output.ID, Title: s.Document.Output.Title, OutputID: s.Document.Output.ID, Order: 0, Visible: true}}} + } + if workspace == nil { + return nil + } + if err := workspace.Validate(); err != nil { + return err + } + for i := range workspace.Documents { + document := workspace.Documents[i] + if document.semantic() { + continue + } + one := s + one.Workspace = nil + one.Document = &document + if err := one.validateDocument(); err != nil { + return fmt.Errorf("documents[%d]: %w", i, err) + } + } + return nil +} + +func (s BuilderState) validateDocument() error { + d := s.Document + if d == nil { + return nil + } + edges, candidates, nodes := s.Catalog.edgeIndex(), s.Catalog.candidateIndex(), s.Catalog.nodeIndex() + if nodes[d.RootNodeID].ID == "" { + return fmt.Errorf("document rootNodeId %q is stale", d.RootNodeID) + } + if !nodes[d.RootNodeID].RowRootEligible { + return fmt.Errorf("ROW_ROOT_NOT_ELIGIBLE: rootNodeId %q", d.RootNodeID) + } + seenEdges := map[string]bool{} + current := d.RootNodeID + for i, step := range d.RouteSteps { + e, ok := edges[step.EdgeID] + if !ok { + return fmt.Errorf("routeSteps[%d] references stale edge %q", i, step.EdgeID) + } + if e.FromNodeID != current { + return fmt.Errorf("routeSteps[%d] is disconnected: edge starts at %q, expected %q", i, e.FromNodeID, current) + } + if seenEdges[e.ID] && !s.Catalog.RoutePolicy.AllowRepeatedEdges { + return fmt.Errorf("repeated edge %q is not allowed by route policy", e.ID) + } + seenEdges[e.ID] = true + current = e.ToNodeID + } + if s.Catalog.RoutePolicy.MaxHops != nil && len(d.RouteSteps) > *s.Catalog.RoutePolicy.MaxHops { + return fmt.Errorf("route exceeds routePolicy.maxHops") + } + occ, err := d.Occurrences(s.Catalog) + if err != nil { + return err + } + occByID := map[string]RouteOccurrence{} + for _, item := range occ { + occByID[item.ID] = item + } + for i, selection := range d.Selections { + candidate, ok := candidates[selection.CandidateID] + if !ok { + return fmt.Errorf("selections[%d] references stale candidate %q", i, selection.CandidateID) + } + id := selection.OccurrenceID + if id == "" { + id = occ[len(occ)-1].ID + } + item, ok := occByID[id] + if !ok { + return fmt.Errorf("selections[%d] references stale occurrence %q", i, id) + } + if candidate.NodeID != item.NodeID { + return fmt.Errorf("selection %q belongs to node %q, not occurrence %q node %q", selection.CandidateID, candidate.NodeID, id, item.NodeID) + } + projectionAllowed := false + for _, mode := range candidate.ProjectionModes { + if selection.ProjectionMode == mode { + projectionAllowed = true + break + } + } + if !projectionAllowed { + return fmt.Errorf("selection %q projection mode %q is not advertised", selection.CandidateID, selection.ProjectionMode) + } + } + seenResolvedSelections := map[string]bool{} + for i, selection := range d.Selections { + occurrenceID := effectiveOccurrence(*d, s.Catalog, selection.OccurrenceID) + key := selection.CandidateID + "\x00" + occurrenceID + "\x00" + selection.ProjectionMode + if seenResolvedSelections[key] { + return fmt.Errorf("duplicate selection at selections[%d]", i) + } + seenResolvedSelections[key] = true + } + selectionKeys := map[string]bool{} + for _, selection := range d.Selections { + selectionKeys[PresentationKey(selection.CandidateID, effectiveOccurrence(*d, s.Catalog, selection.OccurrenceID), selection.ProjectionMode)] = true + } + for key, p := range d.Presentation { + if !selectionKeys[key] { + return fmt.Errorf("presentation %q does not resolve to a selection", key) + } + for _, selection := range d.Selections { + if PresentationKey(selection.CandidateID, effectiveOccurrence(*d, s.Catalog, selection.OccurrenceID), selection.ProjectionMode) != key { + continue + } + candidate := candidates[selection.CandidateID] + if p.Filter != nil && !candidate.Filterable { + return fmt.Errorf("UNSUPPORTED_FILTER: presentation %q", key) + } + if p.Chart != nil && !candidate.Chartable { + return fmt.Errorf("UNSUPPORTED_CHART: presentation %q", key) + } + } + } + return nil +} + +func effectiveOccurrence(d Document, c CatalogSnapshot, authored string) string { + if authored != "" { + return authored + } + occ, err := d.Occurrences(c) + if err != nil || len(occ) == 0 { + return authored + } + return occ[len(occ)-1].ID +} + +func (c CatalogSnapshot) nodeIndex() map[string]CatalogNode { + out := map[string]CatalogNode{} + for _, n := range c.Nodes { + out[n.ID] = n + } + return out +} +func (c CatalogSnapshot) edgeIndex() map[string]*CatalogEdge { + out := map[string]*CatalogEdge{} + for i := range c.Edges { + out[c.Edges[i].ID] = &c.Edges[i] + } + return out +} +func (c CatalogSnapshot) candidateIndex() map[string]CatalogCandidate { + out := map[string]CatalogCandidate{} + for _, n := range c.Candidates { + out[n.ID] = n + } + return out +} + +func emptyID(value string) bool { + return strings.TrimSpace(value) == "" || value != strings.TrimSpace(value) +} + +// CanonicalJSON and Digest provide content-addressed, deterministic wire +// representations. Catalog collections and unordered selections are sorted; +// routeSteps retain their authored path order. diff --git a/internal/explorer/authoringv2/workspace_test.go b/internal/explorer/authoringv2/workspace_test.go index 150f6c90..f9578ba3 100644 --- a/internal/explorer/authoringv2/workspace_test.go +++ b/internal/explorer/authoringv2/workspace_test.go @@ -159,6 +159,17 @@ func TestDecodeWorkspaceRejectsUnknownFields(t *testing.T) { } } +func TestDecodeWorkspaceRejectsDuplicateAndTrailingJSON(t *testing.T) { + duplicate := `{"apiVersion":"` + APIVersion + `","kind":"` + WorkspaceKind + `","documents":[],"tabs":[],"tabs":[]}` + if _, err := DecodeWorkspace([]byte(duplicate)); err == nil || !strings.Contains(err.Error(), "duplicate JSON key") { + t.Fatalf("duplicate field error=%v", err) + } + trailing := `{"apiVersion":"` + APIVersion + `","kind":"` + WorkspaceKind + `","documents":[],"tabs":[]} {}` + if _, err := DecodeWorkspace([]byte(trailing)); err == nil || !strings.Contains(err.Error(), "trailing JSON") { + t.Fatalf("trailing value error=%v", err) + } +} + func TestDecodeWorkspaceRepairsPreviouslyOmittedEmptyColumns(t *testing.T) { raw := `{"apiVersion":"` + APIVersion + `","kind":"` + WorkspaceKind + `","explorer":{"title":"Patients"},"documents":[{"kind":"` + Kind + `","output":{"id":"patients","title":"Patients"},"rootResourceType":"Patient","route":{"occurrenceId":"base","resourceType":"Patient"}}],"tabs":[{"id":"tab-patients","title":"Patients","outputId":"patients","order":0,"visible":true}]}` workspace, err := DecodeWorkspace([]byte(raw)) diff --git a/internal/explorer/compilation.go b/internal/explorer/compilation.go index 8a437017..89bdc907 100644 --- a/internal/explorer/compilation.go +++ b/internal/explorer/compilation.go @@ -1,9 +1,6 @@ package explorer import ( - "crypto/sha256" - "encoding/hex" - "github.com/calypr/loom/internal/dataframe/recipe" ) @@ -30,8 +27,3 @@ type EmittedColumn struct { Filterable bool `json:"filterable"` Chartable bool `json:"chartable"` } - -func OpaqueID(prefix, identity string) string { - sum := sha256.Sum256([]byte(identity)) - return prefix + hex.EncodeToString(sum[:]) -} diff --git a/internal/explorer/config_v2.go b/internal/explorer/config_v2.go index 90e8f425..bb9952be 100644 --- a/internal/explorer/config_v2.go +++ b/internal/explorer/config_v2.go @@ -1,23 +1,11 @@ package explorer import ( - "bytes" - "crypto/sha256" - "encoding/hex" "encoding/json" - "fmt" - "io" - "regexp" - "strings" - - "github.com/calypr/loom/internal/dataframe/recipe" - "github.com/calypr/loom/internal/projectid" ) const ConfigV2APIVersion = "loom.calypr.org/explorer-config/v2" -var idPattern = regexp.MustCompile(`^[a-z][a-z0-9-]{0,63}$`) - func ConfigManagementForID(explorerID string) string { if explorerID == "default" { return "repository" @@ -90,92 +78,3 @@ type FileActions struct { Extensions map[string][]string `json:"extensions,omitempty"` Actions map[string]string `json:"actions,omitempty"` } - -func DecodeConfigV2(raw []byte, project string) (ConfigV2, recipe.Bundle, error) { - return DecodeDefaultConfigV2(raw, project) -} - -func DecodeDefaultConfigV2(raw []byte, project string) (ConfigV2, recipe.Bundle, error) { - return decodeConfigV2(raw, project, "default", "repository") -} - -func DecodeInteractiveConfigV2(raw []byte, project, explorerID string) (ConfigV2, recipe.Bundle, error) { - return decodeConfigV2(raw, project, explorerID, "interactive") -} - -func CanonicalConfigV2(raw []byte, project, explorerID, management string) (ConfigV2, recipe.Bundle, []byte, string, error) { - var cfg ConfigV2 - var bundle recipe.Bundle - var err error - if management == "interactive" { - cfg, bundle, err = DecodeInteractiveConfigV2(raw, project, explorerID) - } else { - cfg, bundle, err = decodeConfigV2(raw, project, explorerID, management) - } - if err != nil { - return cfg, bundle, nil, "", err - } - canonical, err := canonicalJSONBytes(raw) - if err != nil { - return cfg, bundle, nil, "", fmt.Errorf("canonicalize ExplorerConfigV2: %w", err) - } - sum := sha256.Sum256(canonical) - return cfg, bundle, canonical, "sha256:" + hex.EncodeToString(sum[:]), nil -} - -func decodeConfigV2(raw []byte, project, explorerID, management string) (ConfigV2, recipe.Bundle, error) { - var cfg ConfigV2 - decoder := json.NewDecoder(bytes.NewReader(raw)) - decoder.DisallowUnknownFields() - if err := decoder.Decode(&cfg); err != nil { - return cfg, recipe.Bundle{}, fmt.Errorf("decode ExplorerConfigV2: %w", err) - } - var trailing any - if err := decoder.Decode(&trailing); err != io.EOF { - return cfg, recipe.Bundle{}, fmt.Errorf("decode ExplorerConfigV2: multiple JSON values") - } - if cfg.APIVersion != ConfigV2APIVersion || cfg.Kind != "ExplorerConfig" { - return cfg, recipe.Bundle{}, fmt.Errorf("apiVersion must be %q and kind must be ExplorerConfig", ConfigV2APIVersion) - } - if projectid.Canonical(cfg.Project) != projectid.Canonical(project) { - return cfg, recipe.Bundle{}, fmt.Errorf("config project must match deployment project") - } - cfg.Project = projectid.Canonical(project) - if cfg.Explorer.ID != explorerID || !strings.EqualFold(cfg.Explorer.Management, management) { - return cfg, recipe.Bundle{}, fmt.Errorf("config explorer identity or management mode does not match deployment") - } - if strings.TrimSpace(cfg.Explorer.Title) == "" { - return cfg, recipe.Bundle{}, fmt.Errorf("ExplorerConfigV2 requires a title") - } - hasPresentation := len(cfg.Views) > 0 || len(cfg.SharedFilters) > 0 || len(cfg.FileActions.Extensions) > 0 || len(cfg.FileActions.Actions) > 0 - if strings.EqualFold(management, "interactive") && len(cfg.Views) == 0 { - return cfg, recipe.Bundle{}, fmt.Errorf("interactive ExplorerConfigV2 requires at least one view") - } - if strings.EqualFold(management, "repository") && hasPresentation && len(cfg.Views) == 0 { - return cfg, recipe.Bundle{}, fmt.Errorf("repository ExplorerConfigV2 presentation requires at least one view") - } - bundle, err := recipe.Parse(cfg.Recipe) - if err != nil { - return cfg, recipe.Bundle{}, fmt.Errorf("invalid recipe: %w", err) - } - outputs := map[string]bool{} - for _, output := range bundle.Outputs { - outputs[output.Name] = true - } - views := map[string]bool{} - for i, view := range cfg.Views { - if !idPattern.MatchString(view.ID) || views[view.ID] || strings.TrimSpace(view.Title) == "" || !outputs[view.Output] { - return cfg, recipe.Bundle{}, fmt.Errorf("views[%d] must have a unique id, title, and recipe output", i) - } - views[view.ID] = true - if len(view.Table.Columns) == 0 { - return cfg, recipe.Bundle{}, fmt.Errorf("views[%d].table.columns is required", i) - } - for _, column := range view.Table.Columns { - if strings.TrimSpace(column.Column) == "" { - return cfg, recipe.Bundle{}, fmt.Errorf("views[%d] has an empty table column", i) - } - } - } - return cfg, bundle, nil -} diff --git a/internal/explorer/config_v2_test.go b/internal/explorer/config_v2_test.go deleted file mode 100644 index c84f5460..00000000 --- a/internal/explorer/config_v2_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package explorer - -import "testing" - -func TestDecodeDefaultConfigV2AcceptsExecutableRecipeWithoutPresentation(t *testing.T) { - raw := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Default","management":"repository"},"recipe":{"recipeSchemaVersion":1,"name":"repository","translationVersion":"v1","outputs":[{"name":"Patient","rootResourceType":"Patient","rowGrain":"patient","fields":[{"name":"id","expr":{"select":"root.id"}}]}]}}`) - cfg, bundle, err := DecodeDefaultConfigV2(raw, "project-a") - if err != nil { - t.Fatal(err) - } - if len(cfg.Views) != 0 || bundle.Outputs[0].Name != "Patient" { - t.Fatalf("decoded %#v %#v", cfg, bundle) - } -} - -func TestDecodeInteractiveConfigV2AcceptsPresentation(t *testing.T) { - raw := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"custom","title":"Custom","management":"interactive"},"recipe":{"recipeSchemaVersion":1,"name":"repository","translationVersion":"v1","outputs":[{"name":"Patient","rootResourceType":"Patient","rowGrain":"patient","fields":[{"name":"id","expr":{"select":"root.id"}}]}]},"views":[{"id":"patient","title":"Patients","output":"Patient","table":{"columns":[{"column":"id","visible":true}]}}]}`) - cfg, bundle, err := DecodeInteractiveConfigV2(raw, "project-a", "custom") - if err != nil { - t.Fatal(err) - } - if cfg.Views[0].Output != "Patient" || bundle.Outputs[0].Name != "Patient" { - t.Fatalf("decoded %#v %#v", cfg, bundle) - } -} - -func TestDecodeDefaultConfigV2AcceptsCompletePresentation(t *testing.T) { - raw := []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Default","management":"repository"},"recipe":{"recipeSchemaVersion":1,"name":"repository","translationVersion":"v1","outputs":[{"name":"Patient","rootResourceType":"Patient","rowGrain":"patient","fields":[{"name":"id","expr":{"select":"root.id"}}]}]},"views":[{"id":"patient","title":"Patients","output":"Patient","table":{"columns":[{"column":"id","visible":true}]}}],"sharedFilters":{"patient":[{"output":"Patient","column":"id"}]}}`) - cfg, bundle, err := DecodeDefaultConfigV2(raw, "project-a") - if err != nil { - t.Fatal(err) - } - if len(cfg.Views) != 1 || len(cfg.SharedFilters["patient"]) != 1 || bundle.Outputs[0].Name != "Patient" { - t.Fatalf("decoded %#v %#v", cfg, bundle) - } -} - -func TestDecodeConfigV2RejectsLegacyAndUnknownFields(t *testing.T) { - for _, raw := range [][]byte{ - []byte(`{"explorerConfig":[]}`), - []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Default","management":"repository"},"recipe":{},"views":[],"tabs":[]}`), - []byte(`{"apiVersion":"loom.calypr.org/explorer-config/v2","kind":"ExplorerConfig","project":"project-a","explorer":{"id":"default","title":"Default","management":"repository"},"recipe":{"recipeSchemaVersion":1,"name":"repository","translationVersion":"v1","outputs":[]},"sharedFilters":{"patient":[{"output":"Patient","column":"id"}]}}`), - } { - if _, _, err := DecodeConfigV2(raw, "project-a"); err == nil { - t.Fatalf("accepted %s", raw) - } - } -} diff --git a/internal/explorer/service.go b/internal/explorer/service.go index eb4bf01e..34a4f040 100644 --- a/internal/explorer/service.go +++ b/internal/explorer/service.go @@ -346,10 +346,6 @@ func (s *Service) CompilationReceiptForExplorer(ctx context.Context, project, ex return s.store.GetCompilationReceiptForExplorer(ctx, projectid.Canonical(project), explorerID, id) } -func (s *Service) CompilationReceiptByCompilationKey(ctx context.Context, project, explorerID, compilationKey string) (*CompilationReceipt, error) { - return s.store.GetCompilationReceiptByCompilationKey(ctx, projectid.Canonical(project), explorerID, compilationKey) -} - func (s *Service) StoreCompilationReceipt(ctx context.Context, receipt CompilationReceipt) (*CompilationReceipt, error) { return s.store.InsertCompilationReceipt(ctx, receipt) } diff --git a/internal/explorer/store.go b/internal/explorer/store.go index a6f1f793..220f42a0 100644 --- a/internal/explorer/store.go +++ b/internal/explorer/store.go @@ -33,7 +33,6 @@ type Store interface { SaveDraft(context.Context, Explorer, int64, ...string) (*Explorer, error) InsertCompilationReceipt(context.Context, CompilationReceipt) (*CompilationReceipt, error) GetCompilationReceiptForExplorer(context.Context, string, string, string) (*CompilationReceipt, error) - GetCompilationReceiptByCompilationKey(context.Context, string, string, string) (*CompilationReceipt, error) PublishAuthoring(context.Context, CompilationReceipt, Revision) (*Revision, error) InsertRevision(context.Context, Revision) (*Revision, error) GetRevision(context.Context, string) (*Revision, error) diff --git a/internal/explorer/viewer_projection.go b/internal/explorer/viewer_projection.go index 4cb9e719..036a5ca7 100644 --- a/internal/explorer/viewer_projection.go +++ b/internal/explorer/viewer_projection.go @@ -294,104 +294,6 @@ func projectionSelector(output string, datasetOutputs map[string]DatasetOutput, return selector, selector.Validate() == nil } -func projectionAliases(emitted map[string]map[string]EmittedColumn, physicalColumns map[string]map[string]publication.PhysicalColumn) map[string]map[string]string { - aliases := map[string]map[string]string{} - for outputID, columns := range emitted { - for publicName := range columns { - matches := []string{} - for physicalName := range physicalColumns[outputID] { - if physicalName == publicName || strings.HasSuffix(physicalName, "_"+publicName) { - matches = append(matches, physicalName) - } - } - if len(matches) == 1 { - if aliases[outputID] == nil { - aliases[outputID] = map[string]string{} - } - aliases[outputID][publicName] = matches[0] - } - } - } - return aliases -} - -func emissionForPhysicalColumn(outputID, physical string, emitted map[string]map[string]EmittedColumn, aliases map[string]map[string]string) EmittedColumn { - publicNames := make([]string, 0, len(aliases[outputID])) - for publicName, physicalName := range aliases[outputID] { - if physicalName == physical { - publicNames = append(publicNames, publicName) - } - } - sort.Strings(publicNames) - for _, publicName := range publicNames { - if emission := emitted[outputID][publicName]; emission.PublicColumn != "" { - return emission - } - } - return EmittedColumn{} -} - -func recipeColumnLabels(bundle recipe.Bundle) map[string]map[string]string { - labels := map[string]map[string]string{} - var collect func(string, []recipe.Field, []recipe.Traversal) - collect = func(output string, fields []recipe.Field, traversals []recipe.Traversal) { - if labels[output] == nil { - labels[output] = map[string]string{} - } - for _, field := range fields { - if field.Name == "" { - continue - } - fieldRef := strings.TrimSpace(field.FieldRef) - if fieldRef == "" { - fieldRef = firstExpressionSelector(field.Expr) - } - if fieldRef != "" { - labels[output][field.Name] = humanizeFieldRef(fieldRef) - } - } - for _, traversal := range traversals { - collect(output, traversal.Fields, traversal.Traversals) - } - } - for _, output := range bundle.Outputs { - collect(output.Name, output.Fields, output.Traversals) - } - return labels -} - -func firstExpressionSelector(expr recipe.Expression) string { - if strings.TrimSpace(expr.Select) != "" { - return strings.TrimSpace(expr.Select) - } - for _, argument := range expr.Args { - if selector := firstExpressionSelector(argument); selector != "" { - return selector - } - } - return "" -} - -func humanizeFieldRef(fieldRef string) string { - value := strings.TrimSpace(fieldRef) - if index := strings.IndexByte(value, '.'); index >= 0 { - value = value[index+1:] - } - parts := strings.FieldsFunc(value, func(r rune) bool { return r == '.' || r == '_' || r == '-' || r == '[' || r == ']' }) - for index, part := range parts { - lower := strings.ToLower(part) - if lower == "id" || lower == "url" || lower == "uri" || lower == "uuid" { - parts[index] = strings.ToUpper(lower) - } else if part != "" { - parts[index] = strings.ToUpper(part[:1]) + part[1:] - } - } - if len(parts) == 0 { - return fieldRef - } - return strings.Join(parts, " ") -} - func runtimeColumnIsInternal(name string) bool { return name == "auth_resource_path" || strings.HasPrefix(name, "__loom_") } diff --git a/internal/fhir/schema/generated_metadata.go b/internal/fhir/schema/generated_metadata.go index 8febb0ac..3df13dea 100644 --- a/internal/fhir/schema/generated_metadata.go +++ b/internal/fhir/schema/generated_metadata.go @@ -5,7 +5,6 @@ import generatedschema "github.com/calypr/loom/generated/fhirschema" // These aliases keep generated FHIR metadata private to this package while // allowing the schema facade to expose stable, hand-written semantics. type TraversalSpec = generatedschema.Traversal -type generatedDefinition = generatedschema.Definition type generatedProperty = generatedschema.Property var ( diff --git a/internal/server/http_test_helpers_test.go b/internal/server/http_test_helpers_test.go index 29ca10f2..8523ef25 100644 --- a/internal/server/http_test_helpers_test.go +++ b/internal/server/http_test_helpers_test.go @@ -199,18 +199,6 @@ func (s *testExplorerStore) GetCompilationReceiptForExplorer(ctx context.Context return value, nil } -func (s *testExplorerStore) GetCompilationReceiptByCompilationKey(_ context.Context, project, explorerID, key string) (*explorer.CompilationReceipt, error) { - s.mu.Lock() - defer s.mu.Unlock() - for _, value := range s.receipts { - if value.Project == project && value.ExplorerID == explorerID && value.CompilationKey == key { - copy := value - return ©, nil - } - } - return nil, explorer.ErrNotFound -} - func (s *testExplorerStore) InsertRevision(_ context.Context, value explorer.Revision) (*explorer.Revision, error) { s.mu.Lock() defer s.mu.Unlock() diff --git a/internal/server/openapi_data_routes.go b/internal/server/openapi_data_routes.go new file mode 100644 index 00000000..36255b6d --- /dev/null +++ b/internal/server/openapi_data_routes.go @@ -0,0 +1,529 @@ +package server + +import ( + "context" + "net/http" + + loomapi "github.com/calypr/loom/generated/loomapi" +) + +func (r *HTTPRoutes) GetHealth(ctx context.Context, _ loomapi.GetHealthRequestObject) (loomapi.GetHealthResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.server.HandleHealth) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.GetHealth200JSONResponse](body) + return response, decodeErr + } + if status == http.StatusServiceUnavailable { + response, decodeErr := decodeResponse[loomapi.GetHealth503JSONResponse](body) + return response, decodeErr + } + return nil, unexpectedResponseStatus("getHealth", status) +} + +func (r *HTTPRoutes) GetLiveness(ctx context.Context, _ loomapi.GetLivenessRequestObject) (loomapi.GetLivenessResponseObject, error) { + _, body, err := runFiberHandler(ctx, r.server.HandleLiveness) + if err != nil { + return nil, err + } + response, decodeErr := decodeResponse[loomapi.GetLiveness200JSONResponse](body) + return response, decodeErr +} + +func (r *HTTPRoutes) GetReadiness(ctx context.Context, _ loomapi.GetReadinessRequestObject) (loomapi.GetReadinessResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.server.HandleReadiness) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.GetReadiness200JSONResponse](body) + return response, decodeErr + } + response, decodeErr := decodeResponse[loomapi.GetReadiness503JSONResponse](body) + return response, decodeErr +} + +func (r *HTTPRoutes) UploadProjectResource(ctx context.Context, _ loomapi.UploadProjectResourceRequestObject) (loomapi.UploadProjectResourceResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleResource) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.UploadProjectResource200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case http.StatusBadRequest: + return loomapi.UploadProjectResource400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case http.StatusUnauthorized: + return loomapi.UploadProjectResource401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case http.StatusForbidden: + return loomapi.UploadProjectResource403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case http.StatusUnsupportedMediaType: + return loomapi.UploadProjectResource415JSONResponse{ServiceUnsupportedMediaTypeJSONResponse: loomapi.ServiceUnsupportedMediaTypeJSONResponse(value)}, nil + case http.StatusUnprocessableEntity: + return loomapi.UploadProjectResource422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil + case http.StatusInternalServerError: + return loomapi.UploadProjectResource500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case http.StatusServiceUnavailable: + return loomapi.UploadProjectResource503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("uploadProjectResource", status) + } +} + +func (r *HTTPRoutes) CreateDatasetGeneration(ctx context.Context, _ loomapi.CreateDatasetGenerationRequestObject) (loomapi.CreateDatasetGenerationResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleCreateGeneration) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.CreateDatasetGeneration200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case http.StatusBadRequest: + return loomapi.CreateDatasetGeneration400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case http.StatusUnauthorized: + return loomapi.CreateDatasetGeneration401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case http.StatusForbidden: + return loomapi.CreateDatasetGeneration403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case http.StatusConflict: + return loomapi.CreateDatasetGeneration409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil + case http.StatusUnsupportedMediaType: + return loomapi.CreateDatasetGeneration415JSONResponse{ServiceUnsupportedMediaTypeJSONResponse: loomapi.ServiceUnsupportedMediaTypeJSONResponse(value)}, nil + case http.StatusUnprocessableEntity: + return loomapi.CreateDatasetGeneration422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil + case http.StatusInternalServerError: + return loomapi.CreateDatasetGeneration500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case http.StatusServiceUnavailable: + return loomapi.CreateDatasetGeneration503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("createDatasetGeneration", status) + } +} + +func (r *HTTPRoutes) ActivateDatasetGeneration(ctx context.Context, _ loomapi.ActivateDatasetGenerationRequestObject) (loomapi.ActivateDatasetGenerationResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleActivateGeneration) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.ActivateDatasetGeneration200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case http.StatusBadRequest: + return loomapi.ActivateDatasetGeneration400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case http.StatusUnauthorized: + return loomapi.ActivateDatasetGeneration401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case http.StatusForbidden: + return loomapi.ActivateDatasetGeneration403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case http.StatusConflict: + return loomapi.ActivateDatasetGeneration409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil + case http.StatusInternalServerError: + return loomapi.ActivateDatasetGeneration500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case http.StatusServiceUnavailable: + return loomapi.ActivateDatasetGeneration503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("activateDatasetGeneration", status) + } +} + +func (r *HTTPRoutes) UploadRawNDJSON(ctx context.Context, _ loomapi.UploadRawNDJSONRequestObject) (loomapi.UploadRawNDJSONResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleLoadRaw) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.UploadRawNDJSON200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case http.StatusBadRequest: + return loomapi.UploadRawNDJSON400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case http.StatusUnauthorized: + return loomapi.UploadRawNDJSON401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case http.StatusForbidden: + return loomapi.UploadRawNDJSON403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case http.StatusUnsupportedMediaType: + return loomapi.UploadRawNDJSON415JSONResponse{ServiceUnsupportedMediaTypeJSONResponse: loomapi.ServiceUnsupportedMediaTypeJSONResponse(value)}, nil + case http.StatusUnprocessableEntity: + return loomapi.UploadRawNDJSON422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil + case http.StatusInternalServerError: + return loomapi.UploadRawNDJSON500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case http.StatusServiceUnavailable: + return loomapi.UploadRawNDJSON503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("uploadRawNDJSON", status) + } +} + +func (r *HTTPRoutes) CreateSnapshot(ctx context.Context, _ loomapi.CreateSnapshotRequestObject) (loomapi.CreateSnapshotResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleCreateSnapshot) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.CreateSnapshot200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.CreateSnapshot400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case 401: + return loomapi.CreateSnapshot401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.CreateSnapshot403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 409: + return loomapi.CreateSnapshot409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil + case 500: + return loomapi.CreateSnapshot500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.CreateSnapshot503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("createSnapshot", status) + } +} + +func (r *HTTPRoutes) GetSnapshot(ctx context.Context, _ loomapi.GetSnapshotRequestObject) (loomapi.GetSnapshotResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleSnapshotStatus) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.GetSnapshot200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 401: + return loomapi.GetSnapshot401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.GetSnapshot403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.GetSnapshot404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil + case 500: + return loomapi.GetSnapshot500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.GetSnapshot503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("getSnapshot", status) + } +} + +func (r *HTTPRoutes) AbortSnapshot(ctx context.Context, _ loomapi.AbortSnapshotRequestObject) (loomapi.AbortSnapshotResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleAbortSnapshot) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.AbortSnapshot200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 401: + return loomapi.AbortSnapshot401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.AbortSnapshot403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.AbortSnapshot404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.AbortSnapshot409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil + case 500: + return loomapi.AbortSnapshot500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.AbortSnapshot503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("abortSnapshot", status) + } +} + +func (r *HTTPRoutes) UploadSnapshotResource(ctx context.Context, _ loomapi.UploadSnapshotResourceRequestObject) (loomapi.UploadSnapshotResourceResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleUploadSnapshotResource) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.UploadSnapshotResource200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.UploadSnapshotResource400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case 401: + return loomapi.UploadSnapshotResource401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.UploadSnapshotResource403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.UploadSnapshotResource404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.UploadSnapshotResource409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil + case 422: + return loomapi.UploadSnapshotResource422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.UploadSnapshotResource500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.UploadSnapshotResource503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("uploadSnapshotResource", status) + } +} + +func (r *HTTPRoutes) FinalizeSnapshot(ctx context.Context, _ loomapi.FinalizeSnapshotRequestObject) (loomapi.FinalizeSnapshotResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleFinalizeSnapshot) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.FinalizeSnapshot200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.FinalizeSnapshot400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case 401: + return loomapi.FinalizeSnapshot401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.FinalizeSnapshot403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.FinalizeSnapshot404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.FinalizeSnapshot409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil + case 422: + return loomapi.FinalizeSnapshot422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.FinalizeSnapshot500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.FinalizeSnapshot503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("finalizeSnapshot", status) + } +} + +func (r *HTTPRoutes) CreateRelease(ctx context.Context, _ loomapi.CreateReleaseRequestObject) (loomapi.CreateReleaseResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleCreateRelease) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.CreateRelease200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.CreateRelease400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case 401: + return loomapi.CreateRelease401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.CreateRelease403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.CreateRelease404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.CreateRelease409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil + case 422: + return loomapi.CreateRelease422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.CreateRelease500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.CreateRelease503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("createRelease", status) + } +} + +func (r *HTTPRoutes) GetActiveRelease(ctx context.Context, _ loomapi.GetActiveReleaseRequestObject) (loomapi.GetActiveReleaseResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleActiveRelease) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.GetActiveRelease200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 401: + return loomapi.GetActiveRelease401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.GetActiveRelease403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.GetActiveRelease404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil + case 500: + return loomapi.GetActiveRelease500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.GetActiveRelease503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("getActiveRelease", status) + } +} + +func (r *HTTPRoutes) GetRelease(ctx context.Context, _ loomapi.GetReleaseRequestObject) (loomapi.GetReleaseResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleReleaseStatus) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.GetRelease200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 401: + return loomapi.GetRelease401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.GetRelease403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.GetRelease404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil + case 500: + return loomapi.GetRelease500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.GetRelease503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("getRelease", status) + } +} + +func (r *HTTPRoutes) ActivateRelease(ctx context.Context, _ loomapi.ActivateReleaseRequestObject) (loomapi.ActivateReleaseResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleActivateRelease) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.ActivateRelease200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.ActivateRelease400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case 401: + return loomapi.ActivateRelease401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.ActivateRelease403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.ActivateRelease404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.ActivateRelease409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil + case 422: + return loomapi.ActivateRelease422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.ActivateRelease500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.ActivateRelease503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("activateRelease", status) + } +} + +func (r *HTTPRoutes) ActivateReleaseCompatibility(ctx context.Context, _ loomapi.ActivateReleaseCompatibilityRequestObject) (loomapi.ActivateReleaseCompatibilityResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.load.HandleActivateReleaseCompatibility) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.ActivateReleaseCompatibility200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := serviceError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.ActivateReleaseCompatibility400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil + case 401: + return loomapi.ActivateReleaseCompatibility401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil + case 403: + return loomapi.ActivateReleaseCompatibility403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.ActivateReleaseCompatibility404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.ActivateReleaseCompatibility409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil + case 422: + return loomapi.ActivateReleaseCompatibility422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.ActivateReleaseCompatibility500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.ActivateReleaseCompatibility503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("activateReleaseCompatibility", status) + } +} + +func (r *HTTPRoutes) GetRecipeExecution(ctx context.Context, _ loomapi.GetRecipeExecutionRequestObject) (loomapi.GetRecipeExecutionResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.recipe.Handle) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.GetRecipeExecution200JSONResponse](body) + return response, decodeErr + } + if status == http.StatusUnauthorized { + response, decodeErr := decodeResponse[loomapi.GetRecipeExecution401JSONResponse](body) + return response, decodeErr + } + value, decodeErr := legacyError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 403: + return loomapi.GetRecipeExecution403JSONResponse{LegacyForbiddenJSONResponse: loomapi.LegacyForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.GetRecipeExecution404JSONResponse{LegacyNotFoundJSONResponse: loomapi.LegacyNotFoundJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("getRecipeExecution", status) + } +} diff --git a/internal/server/openapi_explorer_routes.go b/internal/server/openapi_explorer_routes.go new file mode 100644 index 00000000..762491e5 --- /dev/null +++ b/internal/server/openapi_explorer_routes.go @@ -0,0 +1,512 @@ +package server + +import ( + "context" + "net/http" + + loomapi "github.com/calypr/loom/generated/loomapi" + "github.com/gofiber/fiber/v3" +) + +func (r *HTTPRoutes) ListExplorers(ctx context.Context, _ loomapi.ListExplorersRequestObject) (loomapi.ListExplorersResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.lifecycle.list) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.ListExplorers200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := legacyError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 403: + return loomapi.ListExplorers403JSONResponse{LegacyForbiddenJSONResponse: loomapi.LegacyForbiddenJSONResponse(value)}, nil + case 500: + return loomapi.ListExplorers500JSONResponse{LegacyInternalErrorJSONResponse: loomapi.LegacyInternalErrorJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("listExplorers", status) + } +} + +func (r *HTTPRoutes) CreateExplorer(ctx context.Context, _ loomapi.CreateExplorerRequestObject) (loomapi.CreateExplorerResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.lifecycle.create) + if err != nil { + return nil, err + } + if status == http.StatusCreated { + response, decodeErr := decodeResponse[loomapi.CreateExplorer201JSONResponse](body) + return response, decodeErr + } + value, decodeErr := legacyError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.CreateExplorer400JSONResponse{LegacyBadRequestJSONResponse: loomapi.LegacyBadRequestJSONResponse(value)}, nil + case 403: + return loomapi.CreateExplorer403JSONResponse{LegacyForbiddenJSONResponse: loomapi.LegacyForbiddenJSONResponse(value)}, nil + case 409: + return loomapi.CreateExplorer409JSONResponse{LegacyConflictJSONResponse: loomapi.LegacyConflictJSONResponse(value)}, nil + case 422: + return loomapi.CreateExplorer422JSONResponse{LegacyUnprocessableJSONResponse: loomapi.LegacyUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.CreateExplorer500JSONResponse{LegacyInternalErrorJSONResponse: loomapi.LegacyInternalErrorJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("createExplorer", status) + } +} + +func (r *HTTPRoutes) GetExplorer(ctx context.Context, _ loomapi.GetExplorerRequestObject) (loomapi.GetExplorerResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.lifecycle.get) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.GetExplorer200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := legacyError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 403: + return loomapi.GetExplorer403JSONResponse{LegacyForbiddenJSONResponse: loomapi.LegacyForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.GetExplorer404JSONResponse{LegacyNotFoundJSONResponse: loomapi.LegacyNotFoundJSONResponse(value)}, nil + case 500: + return loomapi.GetExplorer500JSONResponse{LegacyInternalErrorJSONResponse: loomapi.LegacyInternalErrorJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("getExplorer", status) + } +} + +func (r *HTTPRoutes) PublishRepositoryExplorerConfig(ctx context.Context, _ loomapi.PublishRepositoryExplorerConfigRequestObject) (loomapi.PublishRepositoryExplorerConfigResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.publishRepositoryConfig) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.PublishRepositoryExplorerConfig200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := legacyError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.PublishRepositoryExplorerConfig400JSONResponse{LegacyBadRequestJSONResponse: loomapi.LegacyBadRequestJSONResponse(value)}, nil + case 403: + return loomapi.PublishRepositoryExplorerConfig403JSONResponse{LegacyForbiddenJSONResponse: loomapi.LegacyForbiddenJSONResponse(value)}, nil + case 409: + return loomapi.PublishRepositoryExplorerConfig409JSONResponse{LegacyConflictJSONResponse: loomapi.LegacyConflictJSONResponse(value)}, nil + case 422: + return loomapi.PublishRepositoryExplorerConfig422JSONResponse{LegacyUnprocessableJSONResponse: loomapi.LegacyUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.PublishRepositoryExplorerConfig500JSONResponse{LegacyInternalErrorJSONResponse: loomapi.LegacyInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.PublishRepositoryExplorerConfig503JSONResponse{LegacyUnavailableJSONResponse: loomapi.LegacyUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("publishRepositoryExplorerConfig", status) + } +} + +func (r *HTTPRoutes) GetRepositoryExplorerConfig(ctx context.Context, _ loomapi.GetRepositoryExplorerConfigRequestObject) (loomapi.GetRepositoryExplorerConfigResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.getRepositoryConfig) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.GetRepositoryExplorerConfig200JSONResponse](body) + return response, decodeErr + } + value, decodeErr := legacyError(body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 403: + return loomapi.GetRepositoryExplorerConfig403JSONResponse{LegacyForbiddenJSONResponse: loomapi.LegacyForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.GetRepositoryExplorerConfig404JSONResponse{LegacyNotFoundJSONResponse: loomapi.LegacyNotFoundJSONResponse(value)}, nil + case 500: + return loomapi.GetRepositoryExplorerConfig500JSONResponse{LegacyInternalErrorJSONResponse: loomapi.LegacyInternalErrorJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("getRepositoryExplorerConfig", status) + } +} + +func (r *HTTPRoutes) GetExplorerAuthoringCapability(ctx context.Context, _ loomapi.GetExplorerAuthoringCapabilityRequestObject) (loomapi.GetExplorerAuthoringCapabilityResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.authoring.getCapability) + if err != nil { + return nil, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.AuthoringCapability](body) + return loomapi.GetExplorerAuthoringCapability200JSONResponse(value), e + } + value, _, e := authoringError(body, status) + if e != nil { + return nil, e + } + switch status { + case 403: + return loomapi.GetExplorerAuthoringCapability403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil + case 500: + return loomapi.GetExplorerAuthoringCapability500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("getExplorerAuthoringCapability", status) + } +} + +func (r *HTTPRoutes) SearchExplorerCandidates(ctx context.Context, _ loomapi.SearchExplorerCandidatesRequestObject) (loomapi.SearchExplorerCandidatesResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.authoring.searchSuggestions) + if err != nil { + return nil, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.CandidateSearchResponse](body) + return loomapi.SearchExplorerCandidates200JSONResponse(value), e + } + value, _, e := authoringError(body, status) + if e != nil { + return nil, e + } + switch status { + case 400: + return loomapi.SearchExplorerCandidates400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(value)}, nil + case 403: + return loomapi.SearchExplorerCandidates403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil + case 409: + return loomapi.SearchExplorerCandidates409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil + case 500: + return loomapi.SearchExplorerCandidates500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.SearchExplorerCandidates503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("searchExplorerCandidates", status) + } +} + +func (r *HTTPRoutes) GetExplorerCandidateSuggestions(ctx context.Context, _ loomapi.GetExplorerCandidateSuggestionsRequestObject) (loomapi.GetExplorerCandidateSuggestionsResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.authoring.getCandidateSuggestions) + if err != nil { + return nil, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.CandidateSuggestions](body) + return loomapi.GetExplorerCandidateSuggestions200JSONResponse(value), e + } + value, _, e := authoringError(body, status) + if e != nil { + return nil, e + } + switch status { + case 400: + return loomapi.GetExplorerCandidateSuggestions400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(value)}, nil + case 403: + return loomapi.GetExplorerCandidateSuggestions403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.GetExplorerCandidateSuggestions404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.GetExplorerCandidateSuggestions409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil + case 500: + return loomapi.GetExplorerCandidateSuggestions500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.GetExplorerCandidateSuggestions503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("getExplorerCandidateSuggestions", status) + } +} + +func (r *HTTPRoutes) GetExplorerBuilder(ctx context.Context, _ loomapi.GetExplorerBuilderRequestObject) (loomapi.GetExplorerBuilderResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.authoring.getBuilder) + if err != nil { + return nil, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.BuilderState](body) + return loomapi.GetExplorerBuilder200JSONResponse(value), e + } + value, _, e := authoringError(body, status) + if e != nil { + return nil, e + } + switch status { + case 403: + return loomapi.GetExplorerBuilder403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.GetExplorerBuilder404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.GetExplorerBuilder409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil + case 500: + return loomapi.GetExplorerBuilder500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.GetExplorerBuilder503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("getExplorerBuilder", status) + } +} + +func (r *HTTPRoutes) SaveExplorerDraft(ctx context.Context, _ loomapi.SaveExplorerDraftRequestObject) (loomapi.SaveExplorerDraftResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.authoring.saveDraft) + if err != nil { + return nil, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.SaveDraftResponse](body) + return loomapi.SaveExplorerDraft200JSONResponse(value), e + } + value, _, e := authoringError(body, status) + if e != nil { + return nil, e + } + switch status { + case 400: + return loomapi.SaveExplorerDraft400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(value)}, nil + case 403: + return loomapi.SaveExplorerDraft403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.SaveExplorerDraft404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.SaveExplorerDraft409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil + case 422: + return loomapi.SaveExplorerDraft422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.SaveExplorerDraft500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.SaveExplorerDraft503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("saveExplorerDraft", status) + } +} + +func (r *HTTPRoutes) ExportExplorerWorkspace(ctx context.Context, _ loomapi.ExportExplorerWorkspaceRequestObject) (loomapi.ExportExplorerWorkspaceResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.authoring.exportWorkspace) + if err != nil { + return nil, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.Workspace](body) + return loomapi.ExportExplorerWorkspace200JSONResponse(value), e + } + value, _, e := authoringError(body, status) + if e != nil { + return nil, e + } + switch status { + case 403: + return loomapi.ExportExplorerWorkspace403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.ExportExplorerWorkspace404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.ExportExplorerWorkspace409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil + case 500: + return loomapi.ExportExplorerWorkspace500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("exportExplorerWorkspace", status) + } +} + +func (r *HTTPRoutes) ApplyExplorerBuilderCommands(ctx context.Context, _ loomapi.ApplyExplorerBuilderCommandsRequestObject) (loomapi.ApplyExplorerBuilderCommandsResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.authoring.applyCommands) + if err != nil { + return nil, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.ApplyCommandsResponse](body) + return loomapi.ApplyExplorerBuilderCommands200JSONResponse(value), e + } + value, _, e := authoringError(body, status) + if e != nil { + return nil, e + } + switch status { + case 400: + return loomapi.ApplyExplorerBuilderCommands400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(value)}, nil + case 403: + return loomapi.ApplyExplorerBuilderCommands403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil + case 409: + return loomapi.ApplyExplorerBuilderCommands409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil + case 422: + return loomapi.ApplyExplorerBuilderCommands422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.ApplyExplorerBuilderCommands500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.ApplyExplorerBuilderCommands503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("applyExplorerBuilderCommands", status) + } +} + +func (r *HTTPRoutes) compileExplorer(ctx context.Context, handler fiber.Handler) (loomapi.CompileResponse, loomapi.ErrorResponse, int, error) { + status, body, err := runFiberHandler(ctx, handler) + if err != nil { + return loomapi.CompileResponse{}, loomapi.ErrorResponse{}, 0, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.CompileResponse](body) + return value, loomapi.ErrorResponse{}, status, e + } + value, _, e := authoringError(body, status) + return loomapi.CompileResponse{}, value, status, e +} + +func (r *HTTPRoutes) CompileExplorerBuilder(ctx context.Context, _ loomapi.CompileExplorerBuilderRequestObject) (loomapi.CompileExplorerBuilderResponseObject, error) { + value, failure, status, err := r.compileExplorer(ctx, r.explorer.authoring.compileBuilder) + if err != nil { + return nil, err + } + if status == http.StatusOK { + return loomapi.CompileExplorerBuilder200JSONResponse(value), nil + } + switch status { + case 400: + return loomapi.CompileExplorerBuilder400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(failure)}, nil + case 403: + return loomapi.CompileExplorerBuilder403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(failure)}, nil + case 409: + return loomapi.CompileExplorerBuilder409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(failure)}, nil + case 422: + return loomapi.CompileExplorerBuilder422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(failure)}, nil + case 500: + return loomapi.CompileExplorerBuilder500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(failure)}, nil + case 503: + return loomapi.CompileExplorerBuilder503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(failure)}, nil + default: + return nil, unexpectedResponseStatus("compileExplorerBuilder", status) + } +} + +func (r *HTTPRoutes) CompileExplorer(ctx context.Context, _ loomapi.CompileExplorerRequestObject) (loomapi.CompileExplorerResponseObject, error) { + value, failure, status, err := r.compileExplorer(ctx, r.explorer.authoring.compile) + if err != nil { + return nil, err + } + if status == http.StatusOK { + return loomapi.CompileExplorer200JSONResponse(value), nil + } + switch status { + case 400: + return loomapi.CompileExplorer400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(failure)}, nil + case 403: + return loomapi.CompileExplorer403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(failure)}, nil + case 409: + return loomapi.CompileExplorer409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(failure)}, nil + case 422: + return loomapi.CompileExplorer422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(failure)}, nil + case 500: + return loomapi.CompileExplorer500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(failure)}, nil + case 503: + return loomapi.CompileExplorer503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(failure)}, nil + default: + return nil, unexpectedResponseStatus("compileExplorer", status) + } +} + +func (r *HTTPRoutes) ReconcileExplorerBuilder(ctx context.Context, _ loomapi.ReconcileExplorerBuilderRequestObject) (loomapi.ReconcileExplorerBuilderResponseObject, error) { + value, failure, status, err := r.compileExplorer(ctx, r.explorer.authoring.reconcile) + if err != nil { + return nil, err + } + if status == http.StatusOK { + return loomapi.ReconcileExplorerBuilder200JSONResponse(value), nil + } + switch status { + case 400: + return loomapi.ReconcileExplorerBuilder400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(failure)}, nil + case 403: + return loomapi.ReconcileExplorerBuilder403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(failure)}, nil + case 404: + return loomapi.ReconcileExplorerBuilder404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(failure)}, nil + case 409: + return loomapi.ReconcileExplorerBuilder409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(failure)}, nil + case 422: + return loomapi.ReconcileExplorerBuilder422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(failure)}, nil + case 500: + return loomapi.ReconcileExplorerBuilder500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(failure)}, nil + case 503: + return loomapi.ReconcileExplorerBuilder503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(failure)}, nil + default: + return nil, unexpectedResponseStatus("reconcileExplorerBuilder", status) + } +} + +func (r *HTTPRoutes) PreviewExplorer(ctx context.Context, _ loomapi.PreviewExplorerRequestObject) (loomapi.PreviewExplorerResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.authoring.preview) + if err != nil { + return nil, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.PreviewResponse](body) + return loomapi.PreviewExplorer200JSONResponse(value), e + } + value, _, e := authoringError(body, status) + if e != nil { + return nil, e + } + switch status { + case 400: + return loomapi.PreviewExplorer400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(value)}, nil + case 403: + return loomapi.PreviewExplorer403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.PreviewExplorer404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.PreviewExplorer409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil + case 413: + return loomapi.PreviewExplorer413JSONResponse{AuthoringPayloadTooLargeJSONResponse: loomapi.AuthoringPayloadTooLargeJSONResponse(value)}, nil + case 422: + return loomapi.PreviewExplorer422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(value)}, nil + case 429: + return loomapi.PreviewExplorer429JSONResponse{AuthoringTooManyRequestsJSONResponse: loomapi.AuthoringTooManyRequestsJSONResponse(value)}, nil + case 499: + return loomapi.PreviewExplorer499JSONResponse{AuthoringClientClosedRequestJSONResponse: loomapi.AuthoringClientClosedRequestJSONResponse(value)}, nil + case 500: + return loomapi.PreviewExplorer500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.PreviewExplorer503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil + case 504: + return loomapi.PreviewExplorer504JSONResponse{AuthoringGatewayTimeoutJSONResponse: loomapi.AuthoringGatewayTimeoutJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("previewExplorer", status) + } +} + +func (r *HTTPRoutes) PublishExplorer(ctx context.Context, _ loomapi.PublishExplorerRequestObject) (loomapi.PublishExplorerResponseObject, error) { + status, body, err := runFiberHandler(ctx, r.explorer.authoring.publish) + if err != nil { + return nil, err + } + if status == http.StatusOK { + value, e := decodeResponse[loomapi.PublishResponse](body) + return loomapi.PublishExplorer200JSONResponse(value), e + } + value, _, e := authoringError(body, status) + if e != nil { + return nil, e + } + switch status { + case 400: + return loomapi.PublishExplorer400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(value)}, nil + case 403: + return loomapi.PublishExplorer403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil + case 404: + return loomapi.PublishExplorer404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(value)}, nil + case 409: + return loomapi.PublishExplorer409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil + case 422: + return loomapi.PublishExplorer422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.PublishExplorer500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil + case 503: + return loomapi.PublishExplorer503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("publishExplorer", status) + } +} diff --git a/internal/server/openapi_graphql_routes.go b/internal/server/openapi_graphql_routes.go new file mode 100644 index 00000000..e00a0dc0 --- /dev/null +++ b/internal/server/openapi_graphql_routes.go @@ -0,0 +1,98 @@ +package server + +import ( + "bytes" + "context" + "net/http" + + loomapi "github.com/calypr/loom/generated/loomapi" + "github.com/gofiber/fiber/v3" + fiberadaptor "github.com/gofiber/fiber/v3/middleware/adaptor" +) + +func (r *HTTPRoutes) runGraphQL(ctx context.Context, handler http.Handler) (int, []byte, error) { + if handler == nil { + return http.StatusNotFound, []byte(`{"error":"not found"}`), nil + } + return runFiberHandler(ctx, fiberadaptor.HTTPHandlerWithContext(handler)) +} + +func (r *HTTPRoutes) ExecuteGraphQL(ctx context.Context, _ loomapi.ExecuteGraphQLRequestObject) (loomapi.ExecuteGraphQLResponseObject, error) { + status, body, err := r.runGraphQL(ctx, r.graphql.Handler) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.ExecuteGraphQL200JSONResponse](body) + return response, decodeErr + } + if status == http.StatusUnauthorized { + value, decodeErr := serviceError(body) + return loomapi.ExecuteGraphQL401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, decodeErr + } + value, decodeErr := decodeResponse[loomapi.RawJSON](body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.ExecuteGraphQL400JSONResponse{GraphQLBadRequestJSONResponse: loomapi.GraphQLBadRequestJSONResponse(value)}, nil + case 422: + return loomapi.ExecuteGraphQL422JSONResponse{GraphQLUnprocessableJSONResponse: loomapi.GraphQLUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.ExecuteGraphQL500JSONResponse{GraphQLInternalErrorJSONResponse: loomapi.GraphQLInternalErrorJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("executeGraphQL", status) + } +} + +func (r *HTTPRoutes) ExecuteDataframeGraphQL(ctx context.Context, _ loomapi.ExecuteDataframeGraphQLRequestObject) (loomapi.ExecuteDataframeGraphQLResponseObject, error) { + status, body, err := r.runGraphQL(ctx, r.graphql.Handler) + if err != nil { + return nil, err + } + if status == http.StatusOK { + response, decodeErr := decodeResponse[loomapi.ExecuteDataframeGraphQL200JSONResponse](body) + return response, decodeErr + } + if status == http.StatusUnauthorized { + value, decodeErr := serviceError(body) + return loomapi.ExecuteDataframeGraphQL401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, decodeErr + } + value, decodeErr := decodeResponse[loomapi.RawJSON](body) + if decodeErr != nil { + return nil, decodeErr + } + switch status { + case 400: + return loomapi.ExecuteDataframeGraphQL400JSONResponse{GraphQLBadRequestJSONResponse: loomapi.GraphQLBadRequestJSONResponse(value)}, nil + case 422: + return loomapi.ExecuteDataframeGraphQL422JSONResponse{GraphQLUnprocessableJSONResponse: loomapi.GraphQLUnprocessableJSONResponse(value)}, nil + case 500: + return loomapi.ExecuteDataframeGraphQL500JSONResponse{GraphQLInternalErrorJSONResponse: loomapi.GraphQLInternalErrorJSONResponse(value)}, nil + default: + return nil, unexpectedResponseStatus("executeDataframeGraphQL", status) + } +} + +func (r *HTTPRoutes) GetGraphQLPlayground(ctx context.Context, _ loomapi.GetGraphQLPlaygroundRequestObject) (loomapi.GetGraphQLPlaygroundResponseObject, error) { + status, body, err := r.runGraphQL(ctx, r.graphql.Playground) + if err != nil { + return nil, err + } + if status != http.StatusOK { + return nil, fiber.ErrNotFound + } + return loomapi.GetGraphQLPlayground200TexthtmlResponse{HTMLTexthtmlResponse: loomapi.HTMLTexthtmlResponse{Body: bytes.NewReader(body), ContentLength: int64(len(body))}}, nil +} + +func (r *HTTPRoutes) GetApolloSandbox(ctx context.Context, _ loomapi.GetApolloSandboxRequestObject) (loomapi.GetApolloSandboxResponseObject, error) { + status, body, err := r.runGraphQL(ctx, r.graphql.Sandbox) + if err != nil { + return nil, err + } + if status != http.StatusOK { + return nil, fiber.ErrNotFound + } + return loomapi.GetApolloSandbox200TexthtmlResponse{HTMLTexthtmlResponse: loomapi.HTMLTexthtmlResponse{Body: bytes.NewReader(body), ContentLength: int64(len(body))}}, nil +} diff --git a/internal/server/openapi_routes.go b/internal/server/openapi_routes.go index 2e33d908..d654ab10 100644 --- a/internal/server/openapi_routes.go +++ b/internal/server/openapi_routes.go @@ -1,7 +1,6 @@ package server import ( - "bytes" "context" "encoding/json" "fmt" @@ -12,7 +11,6 @@ import ( graphapi "github.com/calypr/loom/internal/api/graphql/graph" httpapi "github.com/calypr/loom/internal/api/http" "github.com/gofiber/fiber/v3" - fiberadaptor "github.com/gofiber/fiber/v3/middleware/adaptor" ) type strictFiberContextKey struct{} @@ -83,1114 +81,3 @@ func legacyError(body []byte) (loomapi.LegacyErrorResponse, error) { func unexpectedResponseStatus(operation string, status int) error { return fmt.Errorf("%s returned undocumented HTTP status %d", operation, status) } - -func (r *HTTPRoutes) GetHealth(ctx context.Context, _ loomapi.GetHealthRequestObject) (loomapi.GetHealthResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.server.HandleHealth) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.GetHealth200JSONResponse](body) - return response, decodeErr - } - if status == http.StatusServiceUnavailable { - response, decodeErr := decodeResponse[loomapi.GetHealth503JSONResponse](body) - return response, decodeErr - } - return nil, unexpectedResponseStatus("getHealth", status) -} - -func (r *HTTPRoutes) GetLiveness(ctx context.Context, _ loomapi.GetLivenessRequestObject) (loomapi.GetLivenessResponseObject, error) { - _, body, err := runFiberHandler(ctx, r.server.HandleLiveness) - if err != nil { - return nil, err - } - response, decodeErr := decodeResponse[loomapi.GetLiveness200JSONResponse](body) - return response, decodeErr -} - -func (r *HTTPRoutes) GetReadiness(ctx context.Context, _ loomapi.GetReadinessRequestObject) (loomapi.GetReadinessResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.server.HandleReadiness) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.GetReadiness200JSONResponse](body) - return response, decodeErr - } - response, decodeErr := decodeResponse[loomapi.GetReadiness503JSONResponse](body) - return response, decodeErr -} - -func (r *HTTPRoutes) UploadProjectResource(ctx context.Context, _ loomapi.UploadProjectResourceRequestObject) (loomapi.UploadProjectResourceResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.load.HandleResource) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.UploadProjectResource200JSONResponse](body) - return response, decodeErr - } - value, decodeErr := serviceError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case http.StatusBadRequest: - return loomapi.UploadProjectResource400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil - case http.StatusUnauthorized: - return loomapi.UploadProjectResource401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil - case http.StatusForbidden: - return loomapi.UploadProjectResource403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil - case http.StatusUnsupportedMediaType: - return loomapi.UploadProjectResource415JSONResponse{ServiceUnsupportedMediaTypeJSONResponse: loomapi.ServiceUnsupportedMediaTypeJSONResponse(value)}, nil - case http.StatusUnprocessableEntity: - return loomapi.UploadProjectResource422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil - case http.StatusInternalServerError: - return loomapi.UploadProjectResource500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil - case http.StatusServiceUnavailable: - return loomapi.UploadProjectResource503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("uploadProjectResource", status) - } -} - -func (r *HTTPRoutes) CreateDatasetGeneration(ctx context.Context, _ loomapi.CreateDatasetGenerationRequestObject) (loomapi.CreateDatasetGenerationResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.load.HandleCreateGeneration) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.CreateDatasetGeneration200JSONResponse](body) - return response, decodeErr - } - value, decodeErr := serviceError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case http.StatusBadRequest: - return loomapi.CreateDatasetGeneration400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil - case http.StatusUnauthorized: - return loomapi.CreateDatasetGeneration401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil - case http.StatusForbidden: - return loomapi.CreateDatasetGeneration403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil - case http.StatusConflict: - return loomapi.CreateDatasetGeneration409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil - case http.StatusUnsupportedMediaType: - return loomapi.CreateDatasetGeneration415JSONResponse{ServiceUnsupportedMediaTypeJSONResponse: loomapi.ServiceUnsupportedMediaTypeJSONResponse(value)}, nil - case http.StatusUnprocessableEntity: - return loomapi.CreateDatasetGeneration422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil - case http.StatusInternalServerError: - return loomapi.CreateDatasetGeneration500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil - case http.StatusServiceUnavailable: - return loomapi.CreateDatasetGeneration503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("createDatasetGeneration", status) - } -} - -func (r *HTTPRoutes) ActivateDatasetGeneration(ctx context.Context, _ loomapi.ActivateDatasetGenerationRequestObject) (loomapi.ActivateDatasetGenerationResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.load.HandleActivateGeneration) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.ActivateDatasetGeneration200JSONResponse](body) - return response, decodeErr - } - value, decodeErr := serviceError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case http.StatusBadRequest: - return loomapi.ActivateDatasetGeneration400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil - case http.StatusUnauthorized: - return loomapi.ActivateDatasetGeneration401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil - case http.StatusForbidden: - return loomapi.ActivateDatasetGeneration403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil - case http.StatusConflict: - return loomapi.ActivateDatasetGeneration409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil - case http.StatusInternalServerError: - return loomapi.ActivateDatasetGeneration500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil - case http.StatusServiceUnavailable: - return loomapi.ActivateDatasetGeneration503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("activateDatasetGeneration", status) - } -} - -func (r *HTTPRoutes) UploadRawNDJSON(ctx context.Context, _ loomapi.UploadRawNDJSONRequestObject) (loomapi.UploadRawNDJSONResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.load.HandleLoadRaw) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.UploadRawNDJSON200JSONResponse](body) - return response, decodeErr - } - value, decodeErr := serviceError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case http.StatusBadRequest: - return loomapi.UploadRawNDJSON400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil - case http.StatusUnauthorized: - return loomapi.UploadRawNDJSON401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil - case http.StatusForbidden: - return loomapi.UploadRawNDJSON403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil - case http.StatusUnsupportedMediaType: - return loomapi.UploadRawNDJSON415JSONResponse{ServiceUnsupportedMediaTypeJSONResponse: loomapi.ServiceUnsupportedMediaTypeJSONResponse(value)}, nil - case http.StatusUnprocessableEntity: - return loomapi.UploadRawNDJSON422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil - case http.StatusInternalServerError: - return loomapi.UploadRawNDJSON500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil - case http.StatusServiceUnavailable: - return loomapi.UploadRawNDJSON503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("uploadRawNDJSON", status) - } -} - -func (r *HTTPRoutes) CreateSnapshot(ctx context.Context, _ loomapi.CreateSnapshotRequestObject) (loomapi.CreateSnapshotResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.load.HandleCreateSnapshot) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.CreateSnapshot200JSONResponse](body) - return response, decodeErr - } - value, decodeErr := serviceError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case 400: - return loomapi.CreateSnapshot400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil - case 401: - return loomapi.CreateSnapshot401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil - case 403: - return loomapi.CreateSnapshot403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil - case 409: - return loomapi.CreateSnapshot409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil - case 500: - return loomapi.CreateSnapshot500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil - case 503: - return loomapi.CreateSnapshot503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("createSnapshot", status) - } -} - -func (r *HTTPRoutes) GetSnapshot(ctx context.Context, _ loomapi.GetSnapshotRequestObject) (loomapi.GetSnapshotResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.load.HandleSnapshotStatus) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.GetSnapshot200JSONResponse](body) - return response, decodeErr - } - value, decodeErr := serviceError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case 401: - return loomapi.GetSnapshot401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil - case 403: - return loomapi.GetSnapshot403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil - case 404: - return loomapi.GetSnapshot404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil - case 500: - return loomapi.GetSnapshot500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil - case 503: - return loomapi.GetSnapshot503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("getSnapshot", status) - } -} - -func (r *HTTPRoutes) AbortSnapshot(ctx context.Context, _ loomapi.AbortSnapshotRequestObject) (loomapi.AbortSnapshotResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.load.HandleAbortSnapshot) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.AbortSnapshot200JSONResponse](body) - return response, decodeErr - } - value, decodeErr := serviceError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case 401: - return loomapi.AbortSnapshot401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil - case 403: - return loomapi.AbortSnapshot403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil - case 404: - return loomapi.AbortSnapshot404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil - case 409: - return loomapi.AbortSnapshot409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil - case 500: - return loomapi.AbortSnapshot500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil - case 503: - return loomapi.AbortSnapshot503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("abortSnapshot", status) - } -} - -func (r *HTTPRoutes) UploadSnapshotResource(ctx context.Context, _ loomapi.UploadSnapshotResourceRequestObject) (loomapi.UploadSnapshotResourceResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.load.HandleUploadSnapshotResource) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.UploadSnapshotResource200JSONResponse](body) - return response, decodeErr - } - value, decodeErr := serviceError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case 400: - return loomapi.UploadSnapshotResource400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil - case 401: - return loomapi.UploadSnapshotResource401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil - case 403: - return loomapi.UploadSnapshotResource403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil - case 404: - return loomapi.UploadSnapshotResource404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil - case 409: - return loomapi.UploadSnapshotResource409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil - case 422: - return loomapi.UploadSnapshotResource422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil - case 500: - return loomapi.UploadSnapshotResource500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil - case 503: - return loomapi.UploadSnapshotResource503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("uploadSnapshotResource", status) - } -} - -func (r *HTTPRoutes) FinalizeSnapshot(ctx context.Context, _ loomapi.FinalizeSnapshotRequestObject) (loomapi.FinalizeSnapshotResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.load.HandleFinalizeSnapshot) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.FinalizeSnapshot200JSONResponse](body) - return response, decodeErr - } - value, decodeErr := serviceError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case 400: - return loomapi.FinalizeSnapshot400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil - case 401: - return loomapi.FinalizeSnapshot401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil - case 403: - return loomapi.FinalizeSnapshot403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil - case 404: - return loomapi.FinalizeSnapshot404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil - case 409: - return loomapi.FinalizeSnapshot409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil - case 422: - return loomapi.FinalizeSnapshot422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil - case 500: - return loomapi.FinalizeSnapshot500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil - case 503: - return loomapi.FinalizeSnapshot503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("finalizeSnapshot", status) - } -} - -func (r *HTTPRoutes) CreateRelease(ctx context.Context, _ loomapi.CreateReleaseRequestObject) (loomapi.CreateReleaseResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.load.HandleCreateRelease) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.CreateRelease200JSONResponse](body) - return response, decodeErr - } - value, decodeErr := serviceError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case 400: - return loomapi.CreateRelease400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil - case 401: - return loomapi.CreateRelease401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil - case 403: - return loomapi.CreateRelease403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil - case 404: - return loomapi.CreateRelease404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil - case 409: - return loomapi.CreateRelease409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil - case 422: - return loomapi.CreateRelease422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil - case 500: - return loomapi.CreateRelease500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil - case 503: - return loomapi.CreateRelease503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("createRelease", status) - } -} - -func (r *HTTPRoutes) GetActiveRelease(ctx context.Context, _ loomapi.GetActiveReleaseRequestObject) (loomapi.GetActiveReleaseResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.load.HandleActiveRelease) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.GetActiveRelease200JSONResponse](body) - return response, decodeErr - } - value, decodeErr := serviceError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case 401: - return loomapi.GetActiveRelease401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil - case 403: - return loomapi.GetActiveRelease403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil - case 404: - return loomapi.GetActiveRelease404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil - case 500: - return loomapi.GetActiveRelease500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil - case 503: - return loomapi.GetActiveRelease503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("getActiveRelease", status) - } -} - -func (r *HTTPRoutes) GetRelease(ctx context.Context, _ loomapi.GetReleaseRequestObject) (loomapi.GetReleaseResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.load.HandleReleaseStatus) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.GetRelease200JSONResponse](body) - return response, decodeErr - } - value, decodeErr := serviceError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case 401: - return loomapi.GetRelease401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil - case 403: - return loomapi.GetRelease403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil - case 404: - return loomapi.GetRelease404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil - case 500: - return loomapi.GetRelease500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil - case 503: - return loomapi.GetRelease503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("getRelease", status) - } -} - -func (r *HTTPRoutes) ActivateRelease(ctx context.Context, _ loomapi.ActivateReleaseRequestObject) (loomapi.ActivateReleaseResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.load.HandleActivateRelease) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.ActivateRelease200JSONResponse](body) - return response, decodeErr - } - value, decodeErr := serviceError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case 400: - return loomapi.ActivateRelease400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil - case 401: - return loomapi.ActivateRelease401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil - case 403: - return loomapi.ActivateRelease403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil - case 404: - return loomapi.ActivateRelease404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil - case 409: - return loomapi.ActivateRelease409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil - case 422: - return loomapi.ActivateRelease422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil - case 500: - return loomapi.ActivateRelease500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil - case 503: - return loomapi.ActivateRelease503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("activateRelease", status) - } -} - -func (r *HTTPRoutes) ActivateReleaseCompatibility(ctx context.Context, _ loomapi.ActivateReleaseCompatibilityRequestObject) (loomapi.ActivateReleaseCompatibilityResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.load.HandleActivateReleaseCompatibility) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.ActivateReleaseCompatibility200JSONResponse](body) - return response, decodeErr - } - value, decodeErr := serviceError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case 400: - return loomapi.ActivateReleaseCompatibility400JSONResponse{ServiceBadRequestJSONResponse: loomapi.ServiceBadRequestJSONResponse(value)}, nil - case 401: - return loomapi.ActivateReleaseCompatibility401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, nil - case 403: - return loomapi.ActivateReleaseCompatibility403JSONResponse{ServiceForbiddenJSONResponse: loomapi.ServiceForbiddenJSONResponse(value)}, nil - case 404: - return loomapi.ActivateReleaseCompatibility404JSONResponse{ServiceNotFoundJSONResponse: loomapi.ServiceNotFoundJSONResponse(value)}, nil - case 409: - return loomapi.ActivateReleaseCompatibility409JSONResponse{ServiceConflictJSONResponse: loomapi.ServiceConflictJSONResponse(value)}, nil - case 422: - return loomapi.ActivateReleaseCompatibility422JSONResponse{ServiceUnprocessableJSONResponse: loomapi.ServiceUnprocessableJSONResponse(value)}, nil - case 500: - return loomapi.ActivateReleaseCompatibility500JSONResponse{ServiceInternalErrorJSONResponse: loomapi.ServiceInternalErrorJSONResponse(value)}, nil - case 503: - return loomapi.ActivateReleaseCompatibility503JSONResponse{ServiceUnavailableJSONResponse: loomapi.ServiceUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("activateReleaseCompatibility", status) - } -} - -func (r *HTTPRoutes) GetRecipeExecution(ctx context.Context, _ loomapi.GetRecipeExecutionRequestObject) (loomapi.GetRecipeExecutionResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.recipe.Handle) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.GetRecipeExecution200JSONResponse](body) - return response, decodeErr - } - if status == http.StatusUnauthorized { - response, decodeErr := decodeResponse[loomapi.GetRecipeExecution401JSONResponse](body) - return response, decodeErr - } - value, decodeErr := legacyError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case 403: - return loomapi.GetRecipeExecution403JSONResponse{LegacyForbiddenJSONResponse: loomapi.LegacyForbiddenJSONResponse(value)}, nil - case 404: - return loomapi.GetRecipeExecution404JSONResponse{LegacyNotFoundJSONResponse: loomapi.LegacyNotFoundJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("getRecipeExecution", status) - } -} - -func (r *HTTPRoutes) runGraphQL(ctx context.Context, handler http.Handler) (int, []byte, error) { - if handler == nil { - return http.StatusNotFound, []byte(`{"error":"not found"}`), nil - } - return runFiberHandler(ctx, fiberadaptor.HTTPHandlerWithContext(handler)) -} - -func (r *HTTPRoutes) ExecuteGraphQL(ctx context.Context, _ loomapi.ExecuteGraphQLRequestObject) (loomapi.ExecuteGraphQLResponseObject, error) { - status, body, err := r.runGraphQL(ctx, r.graphql.Handler) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.ExecuteGraphQL200JSONResponse](body) - return response, decodeErr - } - if status == http.StatusUnauthorized { - value, decodeErr := serviceError(body) - return loomapi.ExecuteGraphQL401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, decodeErr - } - value, decodeErr := decodeResponse[loomapi.RawJSON](body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case 400: - return loomapi.ExecuteGraphQL400JSONResponse{GraphQLBadRequestJSONResponse: loomapi.GraphQLBadRequestJSONResponse(value)}, nil - case 422: - return loomapi.ExecuteGraphQL422JSONResponse{GraphQLUnprocessableJSONResponse: loomapi.GraphQLUnprocessableJSONResponse(value)}, nil - case 500: - return loomapi.ExecuteGraphQL500JSONResponse{GraphQLInternalErrorJSONResponse: loomapi.GraphQLInternalErrorJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("executeGraphQL", status) - } -} - -func (r *HTTPRoutes) ExecuteDataframeGraphQL(ctx context.Context, _ loomapi.ExecuteDataframeGraphQLRequestObject) (loomapi.ExecuteDataframeGraphQLResponseObject, error) { - status, body, err := r.runGraphQL(ctx, r.graphql.Handler) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.ExecuteDataframeGraphQL200JSONResponse](body) - return response, decodeErr - } - if status == http.StatusUnauthorized { - value, decodeErr := serviceError(body) - return loomapi.ExecuteDataframeGraphQL401JSONResponse{ServiceUnauthorizedJSONResponse: loomapi.ServiceUnauthorizedJSONResponse(value)}, decodeErr - } - value, decodeErr := decodeResponse[loomapi.RawJSON](body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case 400: - return loomapi.ExecuteDataframeGraphQL400JSONResponse{GraphQLBadRequestJSONResponse: loomapi.GraphQLBadRequestJSONResponse(value)}, nil - case 422: - return loomapi.ExecuteDataframeGraphQL422JSONResponse{GraphQLUnprocessableJSONResponse: loomapi.GraphQLUnprocessableJSONResponse(value)}, nil - case 500: - return loomapi.ExecuteDataframeGraphQL500JSONResponse{GraphQLInternalErrorJSONResponse: loomapi.GraphQLInternalErrorJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("executeDataframeGraphQL", status) - } -} - -func (r *HTTPRoutes) GetGraphQLPlayground(ctx context.Context, _ loomapi.GetGraphQLPlaygroundRequestObject) (loomapi.GetGraphQLPlaygroundResponseObject, error) { - status, body, err := r.runGraphQL(ctx, r.graphql.Playground) - if err != nil { - return nil, err - } - if status != http.StatusOK { - return nil, fiber.ErrNotFound - } - return loomapi.GetGraphQLPlayground200TexthtmlResponse{HTMLTexthtmlResponse: loomapi.HTMLTexthtmlResponse{Body: bytes.NewReader(body), ContentLength: int64(len(body))}}, nil -} - -func (r *HTTPRoutes) GetApolloSandbox(ctx context.Context, _ loomapi.GetApolloSandboxRequestObject) (loomapi.GetApolloSandboxResponseObject, error) { - status, body, err := r.runGraphQL(ctx, r.graphql.Sandbox) - if err != nil { - return nil, err - } - if status != http.StatusOK { - return nil, fiber.ErrNotFound - } - return loomapi.GetApolloSandbox200TexthtmlResponse{HTMLTexthtmlResponse: loomapi.HTMLTexthtmlResponse{Body: bytes.NewReader(body), ContentLength: int64(len(body))}}, nil -} - -func (r *HTTPRoutes) ListExplorers(ctx context.Context, _ loomapi.ListExplorersRequestObject) (loomapi.ListExplorersResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.explorer.lifecycle.list) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.ListExplorers200JSONResponse](body) - return response, decodeErr - } - value, decodeErr := legacyError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case 403: - return loomapi.ListExplorers403JSONResponse{LegacyForbiddenJSONResponse: loomapi.LegacyForbiddenJSONResponse(value)}, nil - case 500: - return loomapi.ListExplorers500JSONResponse{LegacyInternalErrorJSONResponse: loomapi.LegacyInternalErrorJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("listExplorers", status) - } -} - -func (r *HTTPRoutes) CreateExplorer(ctx context.Context, _ loomapi.CreateExplorerRequestObject) (loomapi.CreateExplorerResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.explorer.lifecycle.create) - if err != nil { - return nil, err - } - if status == http.StatusCreated { - response, decodeErr := decodeResponse[loomapi.CreateExplorer201JSONResponse](body) - return response, decodeErr - } - value, decodeErr := legacyError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case 400: - return loomapi.CreateExplorer400JSONResponse{LegacyBadRequestJSONResponse: loomapi.LegacyBadRequestJSONResponse(value)}, nil - case 403: - return loomapi.CreateExplorer403JSONResponse{LegacyForbiddenJSONResponse: loomapi.LegacyForbiddenJSONResponse(value)}, nil - case 409: - return loomapi.CreateExplorer409JSONResponse{LegacyConflictJSONResponse: loomapi.LegacyConflictJSONResponse(value)}, nil - case 422: - return loomapi.CreateExplorer422JSONResponse{LegacyUnprocessableJSONResponse: loomapi.LegacyUnprocessableJSONResponse(value)}, nil - case 500: - return loomapi.CreateExplorer500JSONResponse{LegacyInternalErrorJSONResponse: loomapi.LegacyInternalErrorJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("createExplorer", status) - } -} - -func (r *HTTPRoutes) GetExplorer(ctx context.Context, _ loomapi.GetExplorerRequestObject) (loomapi.GetExplorerResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.explorer.lifecycle.get) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.GetExplorer200JSONResponse](body) - return response, decodeErr - } - value, decodeErr := legacyError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case 403: - return loomapi.GetExplorer403JSONResponse{LegacyForbiddenJSONResponse: loomapi.LegacyForbiddenJSONResponse(value)}, nil - case 404: - return loomapi.GetExplorer404JSONResponse{LegacyNotFoundJSONResponse: loomapi.LegacyNotFoundJSONResponse(value)}, nil - case 500: - return loomapi.GetExplorer500JSONResponse{LegacyInternalErrorJSONResponse: loomapi.LegacyInternalErrorJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("getExplorer", status) - } -} - -func (r *HTTPRoutes) PublishRepositoryExplorerConfig(ctx context.Context, _ loomapi.PublishRepositoryExplorerConfigRequestObject) (loomapi.PublishRepositoryExplorerConfigResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.explorer.publishRepositoryConfig) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.PublishRepositoryExplorerConfig200JSONResponse](body) - return response, decodeErr - } - value, decodeErr := legacyError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case 400: - return loomapi.PublishRepositoryExplorerConfig400JSONResponse{LegacyBadRequestJSONResponse: loomapi.LegacyBadRequestJSONResponse(value)}, nil - case 403: - return loomapi.PublishRepositoryExplorerConfig403JSONResponse{LegacyForbiddenJSONResponse: loomapi.LegacyForbiddenJSONResponse(value)}, nil - case 409: - return loomapi.PublishRepositoryExplorerConfig409JSONResponse{LegacyConflictJSONResponse: loomapi.LegacyConflictJSONResponse(value)}, nil - case 422: - return loomapi.PublishRepositoryExplorerConfig422JSONResponse{LegacyUnprocessableJSONResponse: loomapi.LegacyUnprocessableJSONResponse(value)}, nil - case 500: - return loomapi.PublishRepositoryExplorerConfig500JSONResponse{LegacyInternalErrorJSONResponse: loomapi.LegacyInternalErrorJSONResponse(value)}, nil - case 503: - return loomapi.PublishRepositoryExplorerConfig503JSONResponse{LegacyUnavailableJSONResponse: loomapi.LegacyUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("publishRepositoryExplorerConfig", status) - } -} - -func (r *HTTPRoutes) GetRepositoryExplorerConfig(ctx context.Context, _ loomapi.GetRepositoryExplorerConfigRequestObject) (loomapi.GetRepositoryExplorerConfigResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.explorer.getRepositoryConfig) - if err != nil { - return nil, err - } - if status == http.StatusOK { - response, decodeErr := decodeResponse[loomapi.GetRepositoryExplorerConfig200JSONResponse](body) - return response, decodeErr - } - value, decodeErr := legacyError(body) - if decodeErr != nil { - return nil, decodeErr - } - switch status { - case 403: - return loomapi.GetRepositoryExplorerConfig403JSONResponse{LegacyForbiddenJSONResponse: loomapi.LegacyForbiddenJSONResponse(value)}, nil - case 404: - return loomapi.GetRepositoryExplorerConfig404JSONResponse{LegacyNotFoundJSONResponse: loomapi.LegacyNotFoundJSONResponse(value)}, nil - case 500: - return loomapi.GetRepositoryExplorerConfig500JSONResponse{LegacyInternalErrorJSONResponse: loomapi.LegacyInternalErrorJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("getRepositoryExplorerConfig", status) - } -} - -func (r *HTTPRoutes) GetExplorerAuthoringCapability(ctx context.Context, _ loomapi.GetExplorerAuthoringCapabilityRequestObject) (loomapi.GetExplorerAuthoringCapabilityResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.explorer.authoring.getCapability) - if err != nil { - return nil, err - } - if status == http.StatusOK { - value, e := decodeResponse[loomapi.AuthoringCapability](body) - return loomapi.GetExplorerAuthoringCapability200JSONResponse(value), e - } - value, _, e := authoringError(body, status) - if e != nil { - return nil, e - } - switch status { - case 403: - return loomapi.GetExplorerAuthoringCapability403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil - case 500: - return loomapi.GetExplorerAuthoringCapability500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("getExplorerAuthoringCapability", status) - } -} - -func (r *HTTPRoutes) SearchExplorerCandidates(ctx context.Context, _ loomapi.SearchExplorerCandidatesRequestObject) (loomapi.SearchExplorerCandidatesResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.explorer.authoring.searchSuggestions) - if err != nil { - return nil, err - } - if status == http.StatusOK { - value, e := decodeResponse[loomapi.CandidateSearchResponse](body) - return loomapi.SearchExplorerCandidates200JSONResponse(value), e - } - value, _, e := authoringError(body, status) - if e != nil { - return nil, e - } - switch status { - case 400: - return loomapi.SearchExplorerCandidates400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(value)}, nil - case 403: - return loomapi.SearchExplorerCandidates403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil - case 409: - return loomapi.SearchExplorerCandidates409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil - case 500: - return loomapi.SearchExplorerCandidates500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil - case 503: - return loomapi.SearchExplorerCandidates503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("searchExplorerCandidates", status) - } -} - -func (r *HTTPRoutes) GetExplorerCandidateSuggestions(ctx context.Context, _ loomapi.GetExplorerCandidateSuggestionsRequestObject) (loomapi.GetExplorerCandidateSuggestionsResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.explorer.authoring.getCandidateSuggestions) - if err != nil { - return nil, err - } - if status == http.StatusOK { - value, e := decodeResponse[loomapi.CandidateSuggestions](body) - return loomapi.GetExplorerCandidateSuggestions200JSONResponse(value), e - } - value, _, e := authoringError(body, status) - if e != nil { - return nil, e - } - switch status { - case 400: - return loomapi.GetExplorerCandidateSuggestions400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(value)}, nil - case 403: - return loomapi.GetExplorerCandidateSuggestions403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil - case 404: - return loomapi.GetExplorerCandidateSuggestions404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(value)}, nil - case 409: - return loomapi.GetExplorerCandidateSuggestions409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil - case 500: - return loomapi.GetExplorerCandidateSuggestions500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil - case 503: - return loomapi.GetExplorerCandidateSuggestions503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("getExplorerCandidateSuggestions", status) - } -} - -func (r *HTTPRoutes) GetExplorerBuilder(ctx context.Context, _ loomapi.GetExplorerBuilderRequestObject) (loomapi.GetExplorerBuilderResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.explorer.authoring.getBuilder) - if err != nil { - return nil, err - } - if status == http.StatusOK { - value, e := decodeResponse[loomapi.BuilderState](body) - return loomapi.GetExplorerBuilder200JSONResponse(value), e - } - value, _, e := authoringError(body, status) - if e != nil { - return nil, e - } - switch status { - case 403: - return loomapi.GetExplorerBuilder403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil - case 404: - return loomapi.GetExplorerBuilder404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(value)}, nil - case 409: - return loomapi.GetExplorerBuilder409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil - case 500: - return loomapi.GetExplorerBuilder500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil - case 503: - return loomapi.GetExplorerBuilder503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("getExplorerBuilder", status) - } -} - -func (r *HTTPRoutes) SaveExplorerDraft(ctx context.Context, _ loomapi.SaveExplorerDraftRequestObject) (loomapi.SaveExplorerDraftResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.explorer.authoring.saveDraft) - if err != nil { - return nil, err - } - if status == http.StatusOK { - value, e := decodeResponse[loomapi.SaveDraftResponse](body) - return loomapi.SaveExplorerDraft200JSONResponse(value), e - } - value, _, e := authoringError(body, status) - if e != nil { - return nil, e - } - switch status { - case 400: - return loomapi.SaveExplorerDraft400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(value)}, nil - case 403: - return loomapi.SaveExplorerDraft403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil - case 404: - return loomapi.SaveExplorerDraft404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(value)}, nil - case 409: - return loomapi.SaveExplorerDraft409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil - case 422: - return loomapi.SaveExplorerDraft422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(value)}, nil - case 500: - return loomapi.SaveExplorerDraft500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil - case 503: - return loomapi.SaveExplorerDraft503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("saveExplorerDraft", status) - } -} - -func (r *HTTPRoutes) ExportExplorerWorkspace(ctx context.Context, _ loomapi.ExportExplorerWorkspaceRequestObject) (loomapi.ExportExplorerWorkspaceResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.explorer.authoring.exportWorkspace) - if err != nil { - return nil, err - } - if status == http.StatusOK { - value, e := decodeResponse[loomapi.Workspace](body) - return loomapi.ExportExplorerWorkspace200JSONResponse(value), e - } - value, _, e := authoringError(body, status) - if e != nil { - return nil, e - } - switch status { - case 403: - return loomapi.ExportExplorerWorkspace403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil - case 404: - return loomapi.ExportExplorerWorkspace404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(value)}, nil - case 409: - return loomapi.ExportExplorerWorkspace409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil - case 500: - return loomapi.ExportExplorerWorkspace500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("exportExplorerWorkspace", status) - } -} - -func (r *HTTPRoutes) ApplyExplorerBuilderCommands(ctx context.Context, _ loomapi.ApplyExplorerBuilderCommandsRequestObject) (loomapi.ApplyExplorerBuilderCommandsResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.explorer.authoring.applyCommands) - if err != nil { - return nil, err - } - if status == http.StatusOK { - value, e := decodeResponse[loomapi.ApplyCommandsResponse](body) - return loomapi.ApplyExplorerBuilderCommands200JSONResponse(value), e - } - value, _, e := authoringError(body, status) - if e != nil { - return nil, e - } - switch status { - case 400: - return loomapi.ApplyExplorerBuilderCommands400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(value)}, nil - case 403: - return loomapi.ApplyExplorerBuilderCommands403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil - case 409: - return loomapi.ApplyExplorerBuilderCommands409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil - case 422: - return loomapi.ApplyExplorerBuilderCommands422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(value)}, nil - case 500: - return loomapi.ApplyExplorerBuilderCommands500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil - case 503: - return loomapi.ApplyExplorerBuilderCommands503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("applyExplorerBuilderCommands", status) - } -} - -func (r *HTTPRoutes) compileExplorer(ctx context.Context, handler fiber.Handler) (loomapi.CompileResponse, loomapi.ErrorResponse, int, error) { - status, body, err := runFiberHandler(ctx, handler) - if err != nil { - return loomapi.CompileResponse{}, loomapi.ErrorResponse{}, 0, err - } - if status == http.StatusOK { - value, e := decodeResponse[loomapi.CompileResponse](body) - return value, loomapi.ErrorResponse{}, status, e - } - value, _, e := authoringError(body, status) - return loomapi.CompileResponse{}, value, status, e -} - -func (r *HTTPRoutes) CompileExplorerBuilder(ctx context.Context, _ loomapi.CompileExplorerBuilderRequestObject) (loomapi.CompileExplorerBuilderResponseObject, error) { - value, failure, status, err := r.compileExplorer(ctx, r.explorer.authoring.compileBuilder) - if err != nil { - return nil, err - } - if status == http.StatusOK { - return loomapi.CompileExplorerBuilder200JSONResponse(value), nil - } - switch status { - case 400: - return loomapi.CompileExplorerBuilder400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(failure)}, nil - case 403: - return loomapi.CompileExplorerBuilder403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(failure)}, nil - case 409: - return loomapi.CompileExplorerBuilder409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(failure)}, nil - case 422: - return loomapi.CompileExplorerBuilder422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(failure)}, nil - case 500: - return loomapi.CompileExplorerBuilder500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(failure)}, nil - case 503: - return loomapi.CompileExplorerBuilder503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(failure)}, nil - default: - return nil, unexpectedResponseStatus("compileExplorerBuilder", status) - } -} - -func (r *HTTPRoutes) CompileExplorer(ctx context.Context, _ loomapi.CompileExplorerRequestObject) (loomapi.CompileExplorerResponseObject, error) { - value, failure, status, err := r.compileExplorer(ctx, r.explorer.authoring.compile) - if err != nil { - return nil, err - } - if status == http.StatusOK { - return loomapi.CompileExplorer200JSONResponse(value), nil - } - switch status { - case 400: - return loomapi.CompileExplorer400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(failure)}, nil - case 403: - return loomapi.CompileExplorer403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(failure)}, nil - case 409: - return loomapi.CompileExplorer409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(failure)}, nil - case 422: - return loomapi.CompileExplorer422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(failure)}, nil - case 500: - return loomapi.CompileExplorer500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(failure)}, nil - case 503: - return loomapi.CompileExplorer503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(failure)}, nil - default: - return nil, unexpectedResponseStatus("compileExplorer", status) - } -} - -func (r *HTTPRoutes) ReconcileExplorerBuilder(ctx context.Context, _ loomapi.ReconcileExplorerBuilderRequestObject) (loomapi.ReconcileExplorerBuilderResponseObject, error) { - value, failure, status, err := r.compileExplorer(ctx, r.explorer.authoring.reconcile) - if err != nil { - return nil, err - } - if status == http.StatusOK { - return loomapi.ReconcileExplorerBuilder200JSONResponse(value), nil - } - switch status { - case 400: - return loomapi.ReconcileExplorerBuilder400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(failure)}, nil - case 403: - return loomapi.ReconcileExplorerBuilder403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(failure)}, nil - case 404: - return loomapi.ReconcileExplorerBuilder404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(failure)}, nil - case 409: - return loomapi.ReconcileExplorerBuilder409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(failure)}, nil - case 422: - return loomapi.ReconcileExplorerBuilder422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(failure)}, nil - case 500: - return loomapi.ReconcileExplorerBuilder500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(failure)}, nil - case 503: - return loomapi.ReconcileExplorerBuilder503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(failure)}, nil - default: - return nil, unexpectedResponseStatus("reconcileExplorerBuilder", status) - } -} - -func (r *HTTPRoutes) PreviewExplorer(ctx context.Context, _ loomapi.PreviewExplorerRequestObject) (loomapi.PreviewExplorerResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.explorer.authoring.preview) - if err != nil { - return nil, err - } - if status == http.StatusOK { - value, e := decodeResponse[loomapi.PreviewResponse](body) - return loomapi.PreviewExplorer200JSONResponse(value), e - } - value, _, e := authoringError(body, status) - if e != nil { - return nil, e - } - switch status { - case 400: - return loomapi.PreviewExplorer400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(value)}, nil - case 403: - return loomapi.PreviewExplorer403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil - case 404: - return loomapi.PreviewExplorer404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(value)}, nil - case 409: - return loomapi.PreviewExplorer409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil - case 413: - return loomapi.PreviewExplorer413JSONResponse{AuthoringPayloadTooLargeJSONResponse: loomapi.AuthoringPayloadTooLargeJSONResponse(value)}, nil - case 422: - return loomapi.PreviewExplorer422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(value)}, nil - case 429: - return loomapi.PreviewExplorer429JSONResponse{AuthoringTooManyRequestsJSONResponse: loomapi.AuthoringTooManyRequestsJSONResponse(value)}, nil - case 499: - return loomapi.PreviewExplorer499JSONResponse{AuthoringClientClosedRequestJSONResponse: loomapi.AuthoringClientClosedRequestJSONResponse(value)}, nil - case 500: - return loomapi.PreviewExplorer500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil - case 503: - return loomapi.PreviewExplorer503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil - case 504: - return loomapi.PreviewExplorer504JSONResponse{AuthoringGatewayTimeoutJSONResponse: loomapi.AuthoringGatewayTimeoutJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("previewExplorer", status) - } -} - -func (r *HTTPRoutes) PublishExplorer(ctx context.Context, _ loomapi.PublishExplorerRequestObject) (loomapi.PublishExplorerResponseObject, error) { - status, body, err := runFiberHandler(ctx, r.explorer.authoring.publish) - if err != nil { - return nil, err - } - if status == http.StatusOK { - value, e := decodeResponse[loomapi.PublishResponse](body) - return loomapi.PublishExplorer200JSONResponse(value), e - } - value, _, e := authoringError(body, status) - if e != nil { - return nil, e - } - switch status { - case 400: - return loomapi.PublishExplorer400JSONResponse{AuthoringBadRequestJSONResponse: loomapi.AuthoringBadRequestJSONResponse(value)}, nil - case 403: - return loomapi.PublishExplorer403JSONResponse{AuthoringForbiddenJSONResponse: loomapi.AuthoringForbiddenJSONResponse(value)}, nil - case 404: - return loomapi.PublishExplorer404JSONResponse{AuthoringNotFoundJSONResponse: loomapi.AuthoringNotFoundJSONResponse(value)}, nil - case 409: - return loomapi.PublishExplorer409JSONResponse{AuthoringConflictJSONResponse: loomapi.AuthoringConflictJSONResponse(value)}, nil - case 422: - return loomapi.PublishExplorer422JSONResponse{AuthoringUnprocessableJSONResponse: loomapi.AuthoringUnprocessableJSONResponse(value)}, nil - case 500: - return loomapi.PublishExplorer500JSONResponse{AuthoringInternalErrorJSONResponse: loomapi.AuthoringInternalErrorJSONResponse(value)}, nil - case 503: - return loomapi.PublishExplorer503JSONResponse{AuthoringUnavailableJSONResponse: loomapi.AuthoringUnavailableJSONResponse(value)}, nil - default: - return nil, unexpectedResponseStatus("publishExplorer", status) - } -} From b42a8dc27217a4677ac273ba82c5f8b006b9cf9c Mon Sep 17 00:00:00 2001 From: matthewpeterkort Date: Fri, 28 Aug 2026 17:00:30 -0700 Subject: [PATCH 14/15] dd scripts --- scripts/check_dataframe_package_boundaries.sh | 46 +++++++++++++++++++ scripts/check_openapi_route_ownership.sh | 19 ++++++++ 2 files changed, 65 insertions(+) create mode 100755 scripts/check_dataframe_package_boundaries.sh create mode 100644 scripts/check_openapi_route_ownership.sh diff --git a/scripts/check_dataframe_package_boundaries.sh b/scripts/check_dataframe_package_boundaries.sh new file mode 100755 index 00000000..f319143b --- /dev/null +++ b/scripts/check_dataframe_package_boundaries.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Keep the dataframe pipeline directional. This is intentionally a small +# source check rather than a Go test so it can run before compilation in CI. +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +fail_if_matches() { + local label="$1" + local pattern="$2" + shift 2 + if rg -n --glob '*.go' --glob '!**/*_test.go' "$pattern" "$@"; then + echo "dataframe package boundary violation: $label" >&2 + exit 1 + fi +} + +fail_if_matches "spec imports runtime/compiler implementation" \ + 'internal/dataframe/(runtime|compiler|semantic|materialization|template|errors)' \ + "$root/internal/dataframe/spec" + +fail_if_matches "semantic imports physical compiler implementation" \ + 'internal/dataframe/compiler/(ir|lower|optimize|render)' \ + "$root/internal/dataframe/semantic" + +fail_if_matches "ir imports lowering, optimization, rendering, or runtime" \ + 'internal/dataframe/compiler/(lower|optimize|render)|internal/dataframe/runtime|internal/store/arango' \ + "$root/internal/dataframe/compiler/ir" + +fail_if_matches "optimizer imports renderer, lowerer, runtime, or schema routes" \ + 'internal/dataframe/compiler/(lower|render)|internal/dataframe/runtime|ResolveStorageRoute|fhirschema' \ + "$root/internal/dataframe/compiler/optimize" + +fail_if_matches "renderer imports lowerer, optimizer, runtime, or Arango" \ + 'internal/dataframe/compiler/(lower|optimize)|internal/dataframe/runtime|internal/store/arango|ResolveStorageRoute' \ + "$root/internal/dataframe/compiler/render/aql" + +fail_if_matches "stored recipe domain imports execution or storage layers" \ + 'internal/dataframe/(compiler|runtime|materialization|publication|store)' \ + "$root"/internal/dataframe/recipe/*.go + +fail_if_matches "publication targets import dataframe runtime orchestration" \ + 'internal/dataframe/runtime|internal/dataframe/published|internal/dataframe/materialization' \ + "$root"/internal/dataframe/publication + +echo "dataframe package boundaries: ok" diff --git a/scripts/check_openapi_route_ownership.sh b/scripts/check_openapi_route_ownership.sh new file mode 100644 index 00000000..b40e6582 --- /dev/null +++ b/scripts/check_openapi_route_ownership.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail + +if matches="$(rg -n '(^|[^[:alnum:]_])(app|router|[[:alnum:]_]+\.app|server\.App\(\))\.(Get|Post|Put|Delete|Patch|Head|Options|All)\(' internal \ + --glob '*.go' \ + --glob '!**/*_test.go' \ + --glob '!**/generated/**' || true)" && [[ -n "${matches}" ]]; then + printf '%s\n' 'production HTTP routes must be registered through generated/loomapi:' + printf '%s\n' "${matches}" + exit 1 +fi + +registrars="$(rg -n 'RegisterHandlers(WithOptions)?\(' internal --glob '*.go' --glob '!**/*_test.go' || true)" +expected='internal/server/routes.go:' +if [[ "${registrars}" != "${expected}"* ]] || [[ "$(printf '%s\n' "${registrars}" | wc -l | tr -d ' ')" != '1' ]]; then + printf '%s\n' 'expected exactly one production generated route registrar in internal/server/routes.go:' + printf '%s\n' "${registrars}" + exit 1 +fi From b15830ca7af9b518de3833be25fb7a8bc7ad97bb Mon Sep 17 00:00:00 2001 From: matthewpeterkort Date: Fri, 28 Aug 2026 17:05:25 -0700 Subject: [PATCH 15/15] fix OpenAPI ownership check without ripgrep --- scripts/check_openapi_route_ownership.sh | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/scripts/check_openapi_route_ownership.sh b/scripts/check_openapi_route_ownership.sh index b40e6582..3577e43a 100644 --- a/scripts/check_openapi_route_ownership.sh +++ b/scripts/check_openapi_route_ownership.sh @@ -1,16 +1,22 @@ #!/usr/bin/env bash set -euo pipefail -if matches="$(rg -n '(^|[^[:alnum:]_])(app|router|[[:alnum:]_]+\.app|server\.App\(\))\.(Get|Post|Put|Delete|Patch|Head|Options|All)\(' internal \ - --glob '*.go' \ - --glob '!**/*_test.go' \ - --glob '!**/generated/**' || true)" && [[ -n "${matches}" ]]; then +search_production_go() { + local pattern="$1" + if command -v rg >/dev/null 2>&1; then + rg -n "${pattern}" internal --glob '*.go' --glob '!**/*_test.go' + else + grep -R -nE --include='*.go' --exclude='*_test.go' "${pattern}" internal + fi +} + +if matches="$(search_production_go '(^|[^[:alnum:]_])(app|router|[[:alnum:]_]+\.app|server\.App\(\))\.(Get|Post|Put|Delete|Patch|Head|Options|All)\(' | grep -v '/generated/' || true)" && [[ -n "${matches}" ]]; then printf '%s\n' 'production HTTP routes must be registered through generated/loomapi:' printf '%s\n' "${matches}" exit 1 fi -registrars="$(rg -n 'RegisterHandlers(WithOptions)?\(' internal --glob '*.go' --glob '!**/*_test.go' || true)" +registrars="$(search_production_go 'RegisterHandlers(WithOptions)?\(' || true)" expected='internal/server/routes.go:' if [[ "${registrars}" != "${expected}"* ]] || [[ "$(printf '%s\n' "${registrars}" | wc -l | tr -d ' ')" != '1' ]]; then printf '%s\n' 'expected exactly one production generated route registrar in internal/server/routes.go:'